File indexing completed on 2026-08-08 09:23:35
0001
0002
0003
0004
0005
0006 #ifndef QHASH_H
0007 #define QHASH_H
0008
0009 #include <QtCore/qalgorithms.h>
0010 #include <QtCore/qcontainertools_impl.h>
0011 #include <QtCore/qhashfunctions.h>
0012 #include <QtCore/qiterator.h>
0013 #include <QtCore/qlist.h>
0014 #include <QtCore/qrefcount.h>
0015 #include <QtCore/qttypetraits.h>
0016
0017 #include <initializer_list>
0018 #include <functional> // for std::hash
0019 #include <QtCore/q20type_traits.h>
0020
0021 class tst_QHash;
0022
0023 QT_BEGIN_NAMESPACE
0024
0025 struct QHashDummyValue
0026 {
0027 explicit QHashDummyValue() = default;
0028 friend constexpr bool operator==(QHashDummyValue, QHashDummyValue) noexcept { return true; }
0029 #ifndef __cpp_impl_three_way_comparison
0030 friend constexpr bool operator!=(QHashDummyValue, QHashDummyValue) noexcept { return false; }
0031 #endif
0032 friend constexpr size_t qHash(QHashDummyValue) noexcept = delete;
0033 friend constexpr size_t qHash(QHashDummyValue, size_t) noexcept = delete;
0034 };
0035
0036 namespace QHashPrivate {
0037
0038 template <typename T, typename = void>
0039 constexpr inline bool HasQHashOverload = false;
0040
0041 template <typename T>
0042 constexpr inline bool HasQHashOverload<T, std::enable_if_t<
0043 std::is_convertible_v<decltype(qHash(std::declval<const T &>(), std::declval<size_t>())), size_t>
0044 >> = true;
0045
0046 template <typename T, typename = void>
0047 constexpr inline bool HasStdHashSpecializationWithSeed = false;
0048
0049 template <typename T>
0050 constexpr inline bool HasStdHashSpecializationWithSeed<T, std::enable_if_t<
0051 std::is_convertible_v<decltype(std::hash<T>()(std::declval<const T &>(), std::declval<size_t>())), size_t>
0052 >> = true;
0053
0054 template <typename T, typename = void>
0055 constexpr inline bool HasStdHashSpecializationWithoutSeed = false;
0056
0057 template <typename T>
0058 constexpr inline bool HasStdHashSpecializationWithoutSeed<T, std::enable_if_t<
0059 std::is_convertible_v<decltype(std::hash<T>()(std::declval<const T &>())), size_t>
0060 >> = true;
0061
0062 template <typename T>
0063 size_t calculateHash(const T &t, size_t seed = 0)
0064 {
0065 if constexpr (HasQHashOverload<T>) {
0066 return qHash(t, seed);
0067 } else if constexpr (HasStdHashSpecializationWithSeed<T>) {
0068 return std::hash<T>()(t, seed);
0069 } else if constexpr (HasStdHashSpecializationWithoutSeed<T>) {
0070 Q_UNUSED(seed);
0071 return std::hash<T>()(t);
0072 } else {
0073 static_assert(QtPrivate::type_dependent_false<T>(), "The key type must have a qHash overload or a std::hash specialization");
0074 return 0;
0075 }
0076 }
0077
0078 template <typename Key, typename T>
0079 struct Node
0080 {
0081 using KeyType = Key;
0082 using ValueType = T;
0083
0084 Key key;
0085 T value;
0086 template<typename ...Args>
0087 static void createInPlace(Node *n, Key &&k, Args &&... args)
0088 { new (n) Node{ std::move(k), T(std::forward<Args>(args)...) }; }
0089 template<typename ...Args>
0090 static void createInPlace(Node *n, const Key &k, Args &&... args)
0091 { new (n) Node{ Key(k), T(std::forward<Args>(args)...) }; }
0092 template<typename ...Args>
0093 void emplaceValue(Args &&... args)
0094 {
0095 value = T(std::forward<Args>(args)...);
0096 }
0097 T &&takeValue() noexcept
0098 {
0099 return std::move(value);
0100 }
0101 bool valuesEqual(const Node *other) const { return value == other->value; }
0102 };
0103
0104 template <typename Key>
0105 struct Node<Key, QHashDummyValue> {
0106 using KeyType = Key;
0107 using ValueType = QHashDummyValue;
0108
0109 Key key;
0110 template<typename ...Args>
0111 static void createInPlace(Node *n, Key &&k, Args &&...)
0112 { new (n) Node{ std::move(k) }; }
0113 template<typename ...Args>
0114 static void createInPlace(Node *n, const Key &k, Args &&...)
0115 { new (n) Node{ k }; }
0116 template<typename ...Args>
0117 void emplaceValue(Args &&...)
0118 {
0119 }
0120 ValueType takeValue() noexcept { return QHashDummyValue(); }
0121 bool valuesEqual(const Node *) const { return true; }
0122 };
0123
0124 template <typename T>
0125 struct MultiNodeChain
0126 {
0127 T value;
0128 MultiNodeChain *next = nullptr;
0129 ~MultiNodeChain()
0130 {
0131 }
0132 qsizetype free() noexcept(std::is_nothrow_destructible_v<T>)
0133 {
0134 qsizetype nEntries = 0;
0135 MultiNodeChain *e = this;
0136 while (e) {
0137 MultiNodeChain *n = e->next;
0138 ++nEntries;
0139 delete e;
0140 e = n;
0141 }
0142 return nEntries;
0143 }
0144 bool contains(const T &val) const noexcept
0145 {
0146 const MultiNodeChain *e = this;
0147 while (e) {
0148 if (e->value == val)
0149 return true;
0150 e = e->next;
0151 }
0152 return false;
0153 }
0154 };
0155
0156 template <typename Key, typename T>
0157 struct MultiNode
0158 {
0159 using KeyType = Key;
0160 using ValueType = T;
0161 using Chain = MultiNodeChain<T>;
0162
0163 Key key;
0164 Chain *value;
0165
0166 template<typename ...Args>
0167 static void createInPlace(MultiNode *n, Key &&k, Args &&... args)
0168 { new (n) MultiNode(std::move(k), new Chain{ T(std::forward<Args>(args)...), nullptr }); }
0169 template<typename ...Args>
0170 static void createInPlace(MultiNode *n, const Key &k, Args &&... args)
0171 { new (n) MultiNode(k, new Chain{ T(std::forward<Args>(args)...), nullptr }); }
0172
0173 MultiNode(const Key &k, Chain *c)
0174 : key(k),
0175 value(c)
0176 {}
0177 MultiNode(Key &&k, Chain *c) noexcept(std::is_nothrow_move_assignable_v<Key>)
0178 : key(std::move(k)),
0179 value(c)
0180 {}
0181
0182 MultiNode(MultiNode &&other)
0183 : key(std::move(other.key)),
0184 value(std::exchange(other.value, nullptr))
0185 {
0186 }
0187
0188 MultiNode(const MultiNode &other)
0189 : key(other.key)
0190 {
0191 Chain *c = other.value;
0192 Chain **e = &value;
0193 while (c) {
0194 Chain *chain = new Chain{ c->value, nullptr };
0195 *e = chain;
0196 e = &chain->next;
0197 c = c->next;
0198 }
0199 }
0200 ~MultiNode()
0201 {
0202 if (value)
0203 value->free();
0204 }
0205 static qsizetype freeChain(MultiNode *n) noexcept(std::is_nothrow_destructible_v<T>)
0206 {
0207 qsizetype size = n->value->free();
0208 n->value = nullptr;
0209 return size;
0210 }
0211 template<typename ...Args>
0212 void insertMulti(Args &&... args)
0213 {
0214 Chain *e = new Chain{ T(std::forward<Args>(args)...), nullptr };
0215 e->next = std::exchange(value, e);
0216 }
0217 template<typename ...Args>
0218 void emplaceValue(Args &&... args)
0219 {
0220 value->value = T(std::forward<Args>(args)...);
0221 }
0222 };
0223
0224 template<typename Node>
0225 inline constexpr bool isRelocatable_v =
0226 QTypeInfo<typename Node::KeyType>::isRelocatable &&
0227 QTypeInfo<typename Node::ValueType>::isRelocatable;
0228
0229 struct SpanConstants {
0230 static constexpr size_t SpanShift = 7;
0231 static constexpr size_t NEntries = (1 << SpanShift);
0232 static constexpr size_t LocalBucketMask = (NEntries - 1);
0233 static constexpr size_t UnusedEntry = 0xff;
0234
0235 static_assert ((NEntries & LocalBucketMask) == 0, "NEntries must be a power of two.");
0236 };
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 template<typename Node>
0247 struct Span {
0248
0249
0250
0251
0252
0253
0254 struct Entry {
0255 struct { alignas(Node) unsigned char data[sizeof(Node)]; } storage;
0256
0257 unsigned char &nextFree() { return *reinterpret_cast<unsigned char *>(&storage); }
0258 Node &node() { return *reinterpret_cast<Node *>(&storage); }
0259 };
0260
0261 unsigned char offsets[SpanConstants::NEntries];
0262 Entry *entries = nullptr;
0263 unsigned char allocated = 0;
0264 unsigned char nextFree = 0;
0265 Span() noexcept
0266 {
0267 memset(offsets, SpanConstants::UnusedEntry, sizeof(offsets));
0268 }
0269 ~Span()
0270 {
0271 freeData();
0272 }
0273 void freeData() noexcept(std::is_nothrow_destructible<Node>::value)
0274 {
0275 if (entries) {
0276 if constexpr (!std::is_trivially_destructible<Node>::value) {
0277 for (auto o : offsets) {
0278 if (o != SpanConstants::UnusedEntry)
0279 entries[o].node().~Node();
0280 }
0281 }
0282 delete[] entries;
0283 entries = nullptr;
0284 }
0285 }
0286 Node *insert(size_t i)
0287 {
0288 Q_ASSERT(i < SpanConstants::NEntries);
0289 Q_ASSERT(offsets[i] == SpanConstants::UnusedEntry);
0290 if (nextFree == allocated)
0291 addStorage();
0292 unsigned char entry = nextFree;
0293 Q_ASSERT(entry < allocated);
0294 nextFree = entries[entry].nextFree();
0295 offsets[i] = entry;
0296 return &entries[entry].node();
0297 }
0298 void erase(size_t bucket) noexcept(std::is_nothrow_destructible<Node>::value)
0299 {
0300 Q_ASSERT(bucket < SpanConstants::NEntries);
0301 Q_ASSERT(offsets[bucket] != SpanConstants::UnusedEntry);
0302
0303 unsigned char entry = offsets[bucket];
0304 offsets[bucket] = SpanConstants::UnusedEntry;
0305
0306 entries[entry].node().~Node();
0307 entries[entry].nextFree() = nextFree;
0308 nextFree = entry;
0309 }
0310 size_t offset(size_t i) const noexcept
0311 {
0312 return offsets[i];
0313 }
0314 bool hasNode(size_t i) const noexcept
0315 {
0316 return (offsets[i] != SpanConstants::UnusedEntry);
0317 }
0318 Node &at(size_t i) noexcept
0319 {
0320 Q_ASSERT(i < SpanConstants::NEntries);
0321 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
0322
0323 return entries[offsets[i]].node();
0324 }
0325 const Node &at(size_t i) const noexcept
0326 {
0327 Q_ASSERT(i < SpanConstants::NEntries);
0328 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
0329
0330 return entries[offsets[i]].node();
0331 }
0332 Node &atOffset(size_t o) noexcept
0333 {
0334 Q_ASSERT(o < allocated);
0335
0336 return entries[o].node();
0337 }
0338 const Node &atOffset(size_t o) const noexcept
0339 {
0340 Q_ASSERT(o < allocated);
0341
0342 return entries[o].node();
0343 }
0344 void moveLocal(size_t from, size_t to) noexcept
0345 {
0346 Q_ASSERT(offsets[from] != SpanConstants::UnusedEntry);
0347 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
0348 offsets[to] = offsets[from];
0349 offsets[from] = SpanConstants::UnusedEntry;
0350 }
0351 void moveFromSpan(Span &fromSpan, size_t fromIndex, size_t to) noexcept(std::is_nothrow_move_constructible_v<Node>)
0352 {
0353 Q_ASSERT(to < SpanConstants::NEntries);
0354 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
0355 Q_ASSERT(fromIndex < SpanConstants::NEntries);
0356 Q_ASSERT(fromSpan.offsets[fromIndex] != SpanConstants::UnusedEntry);
0357 if (nextFree == allocated)
0358 addStorage();
0359 Q_ASSERT(nextFree < allocated);
0360 offsets[to] = nextFree;
0361 Entry &toEntry = entries[nextFree];
0362 nextFree = toEntry.nextFree();
0363
0364 size_t fromOffset = fromSpan.offsets[fromIndex];
0365 fromSpan.offsets[fromIndex] = SpanConstants::UnusedEntry;
0366 Entry &fromEntry = fromSpan.entries[fromOffset];
0367
0368 if constexpr (isRelocatable_v<Node>) {
0369 memcpy(&toEntry, &fromEntry, sizeof(Entry));
0370 } else {
0371 new (&toEntry.node()) Node(std::move(fromEntry.node()));
0372 fromEntry.node().~Node();
0373 }
0374 fromEntry.nextFree() = fromSpan.nextFree;
0375 fromSpan.nextFree = static_cast<unsigned char>(fromOffset);
0376 }
0377
0378 void addStorage()
0379 {
0380 Q_ASSERT(allocated < SpanConstants::NEntries);
0381 Q_ASSERT(nextFree == allocated);
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394 size_t alloc;
0395 static_assert(SpanConstants::NEntries % 8 == 0);
0396 if (!allocated)
0397 alloc = SpanConstants::NEntries / 8 * 3;
0398 else if (allocated == SpanConstants::NEntries / 8 * 3)
0399 alloc = SpanConstants::NEntries / 8 * 5;
0400 else
0401 alloc = allocated + SpanConstants::NEntries/8;
0402 Entry *newEntries = new Entry[alloc];
0403
0404
0405 if constexpr (isRelocatable_v<Node>) {
0406 if (allocated)
0407 memcpy(newEntries, entries, allocated * sizeof(Entry));
0408 } else {
0409 for (size_t i = 0; i < allocated; ++i) {
0410 new (&newEntries[i].node()) Node(std::move(entries[i].node()));
0411 entries[i].node().~Node();
0412 }
0413 }
0414 for (size_t i = allocated; i < alloc; ++i) {
0415 newEntries[i].nextFree() = uchar(i + 1);
0416 }
0417 delete[] entries;
0418 entries = newEntries;
0419 allocated = uchar(alloc);
0420 }
0421 };
0422
0423
0424 namespace GrowthPolicy {
0425 inline constexpr size_t bucketsForCapacity(size_t requestedCapacity) noexcept
0426 {
0427 constexpr int SizeDigits = std::numeric_limits<size_t>::digits;
0428
0429
0430
0431 if (requestedCapacity <= 64)
0432 return SpanConstants::NEntries;
0433
0434
0435
0436
0437
0438
0439
0440 int count = qCountLeadingZeroBits(requestedCapacity);
0441 if (count < 2)
0442 return (std::numeric_limits<size_t>::max)();
0443 return size_t(1) << (SizeDigits - count + 1);
0444 }
0445 inline constexpr size_t bucketForHash(size_t nBuckets, size_t hash) noexcept
0446 {
0447 return hash & (nBuckets - 1);
0448 }
0449 }
0450
0451 template <typename Node>
0452 struct iterator;
0453
0454 template <typename Node>
0455 struct Data
0456 {
0457 using Key = typename Node::KeyType;
0458 using T = typename Node::ValueType;
0459 using Span = QHashPrivate::Span<Node>;
0460 using iterator = QHashPrivate::iterator<Node>;
0461
0462 QtPrivate::RefCount ref = {{1}};
0463 size_t size = 0;
0464 size_t numBuckets = 0;
0465 size_t seed = 0;
0466 Span *spans = nullptr;
0467
0468 static constexpr size_t maxNumBuckets() noexcept
0469 {
0470 return (std::numeric_limits<ptrdiff_t>::max)() / sizeof(Span);
0471 }
0472
0473 struct Bucket {
0474 Span *span;
0475 size_t index;
0476
0477 Bucket(Span *s, size_t i) noexcept
0478 : span(s), index(i)
0479 {}
0480 Bucket(const Data *d, size_t bucket) noexcept
0481 : span(d->spans + (bucket >> SpanConstants::SpanShift)),
0482 index(bucket & SpanConstants::LocalBucketMask)
0483 {}
0484 Bucket(iterator it) noexcept
0485 : Bucket(it.d, it.bucket)
0486 {}
0487
0488 size_t toBucketIndex(const Data *d) const noexcept
0489 {
0490 return ((span - d->spans) << SpanConstants::SpanShift) | index;
0491 }
0492 iterator toIterator(const Data *d) const noexcept { return iterator{d, toBucketIndex(d)}; }
0493 void advanceWrapped(const Data *d) noexcept
0494 {
0495 advance_impl(d, d->spans);
0496 }
0497 void advance(const Data *d) noexcept
0498 {
0499 advance_impl(d, nullptr);
0500 }
0501 bool isUnused() const noexcept
0502 {
0503 return !span->hasNode(index);
0504 }
0505 size_t offset() const noexcept
0506 {
0507 return span->offset(index);
0508 }
0509 Node &nodeAtOffset(size_t offset)
0510 {
0511 return span->atOffset(offset);
0512 }
0513 Node *node()
0514 {
0515 return &span->at(index);
0516 }
0517 Node *insert() const
0518 {
0519 return span->insert(index);
0520 }
0521
0522 private:
0523 friend bool operator==(Bucket lhs, Bucket rhs) noexcept
0524 {
0525 return lhs.span == rhs.span && lhs.index == rhs.index;
0526 }
0527 friend bool operator!=(Bucket lhs, Bucket rhs) noexcept { return !(lhs == rhs); }
0528
0529 void advance_impl(const Data *d, Span *whenAtEnd) noexcept
0530 {
0531 Q_ASSERT(span);
0532 ++index;
0533 if (Q_UNLIKELY(index == SpanConstants::NEntries)) {
0534 index = 0;
0535 ++span;
0536 if (span - d->spans == ptrdiff_t(d->numBuckets >> SpanConstants::SpanShift))
0537 span = whenAtEnd;
0538 }
0539 }
0540 };
0541
0542 static auto allocateSpans(size_t numBuckets)
0543 {
0544 struct R {
0545 Span *spans;
0546 size_t nSpans;
0547 };
0548
0549 constexpr qptrdiff MaxSpanCount = (std::numeric_limits<qptrdiff>::max)() / sizeof(Span);
0550 constexpr size_t MaxBucketCount = MaxSpanCount << SpanConstants::SpanShift;
0551
0552 if (numBuckets > MaxBucketCount) {
0553 Q_CHECK_PTR(false);
0554 Q_UNREACHABLE();
0555 }
0556
0557 size_t nSpans = numBuckets >> SpanConstants::SpanShift;
0558 return R{ new Span[nSpans], nSpans };
0559 }
0560
0561 Data(size_t reserve = 0)
0562 {
0563 numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
0564 spans = allocateSpans(numBuckets).spans;
0565 seed = QHashSeed::globalSeed();
0566 }
0567
0568
0569
0570 template <bool Resized>
0571 Q_ALWAYS_INLINE
0572 void reallocationHelper(const Data &other, size_t nSpans)
0573 {
0574 for (size_t s = 0; s < nSpans; ++s) {
0575 const Span &span = other.spans[s];
0576 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
0577 if (!span.hasNode(index))
0578 continue;
0579 const Node &n = span.at(index);
0580 auto it = Resized ? findBucket(n.key) : Bucket { spans + s, index };
0581 Q_ASSERT(it.isUnused());
0582 Node *newNode = it.insert();
0583 new (newNode) Node(n);
0584 }
0585 }
0586 }
0587
0588 Data(const Data &other) : size(other.size), numBuckets(other.numBuckets), seed(other.seed)
0589 {
0590 auto r = allocateSpans(numBuckets);
0591 spans = r.spans;
0592 reallocationHelper<false>(other, r.nSpans);
0593 }
0594 Data(const Data &other, size_t reserved) : size(other.size), seed(other.seed)
0595 {
0596 numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
0597 spans = allocateSpans(numBuckets).spans;
0598 size_t otherNSpans = other.numBuckets >> SpanConstants::SpanShift;
0599 reallocationHelper<true>(other, otherNSpans);
0600 }
0601
0602 static Data *detached(Data *d)
0603 {
0604 if (!d)
0605 return new Data;
0606 Data *dd = new Data(*d);
0607 if (!d->ref.deref())
0608 delete d;
0609 return dd;
0610 }
0611 static Data *detached(Data *d, size_t size)
0612 {
0613 if (!d)
0614 return new Data(size);
0615 Data *dd = new Data(*d, size);
0616 if (!d->ref.deref())
0617 delete d;
0618 return dd;
0619 }
0620
0621 void clear()
0622 {
0623 delete[] spans;
0624 spans = nullptr;
0625 size = 0;
0626 numBuckets = 0;
0627 }
0628
0629 iterator detachedIterator(iterator other) const noexcept
0630 {
0631 return iterator{this, other.bucket};
0632 }
0633
0634 iterator begin() const noexcept
0635 {
0636 iterator it{ this, 0 };
0637 if (it.isUnused())
0638 ++it;
0639 return it;
0640 }
0641
0642 constexpr iterator end() const noexcept
0643 {
0644 return iterator();
0645 }
0646
0647 void rehash(size_t sizeHint = 0)
0648 {
0649 if (sizeHint == 0)
0650 sizeHint = size;
0651 size_t newBucketCount = GrowthPolicy::bucketsForCapacity(sizeHint);
0652
0653 Span *oldSpans = spans;
0654 size_t oldBucketCount = numBuckets;
0655 spans = allocateSpans(newBucketCount).spans;
0656 numBuckets = newBucketCount;
0657 size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
0658
0659 for (size_t s = 0; s < oldNSpans; ++s) {
0660 Span &span = oldSpans[s];
0661 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
0662 if (!span.hasNode(index))
0663 continue;
0664 Node &n = span.at(index);
0665 auto it = findBucket(n.key);
0666 Q_ASSERT(it.isUnused());
0667 Node *newNode = it.insert();
0668 new (newNode) Node(std::move(n));
0669 }
0670 span.freeData();
0671 }
0672 delete[] oldSpans;
0673 }
0674
0675 size_t nextBucket(size_t bucket) const noexcept
0676 {
0677 ++bucket;
0678 if (bucket == numBuckets)
0679 bucket = 0;
0680 return bucket;
0681 }
0682
0683 float loadFactor() const noexcept
0684 {
0685 return float(size)/numBuckets;
0686 }
0687 bool shouldGrow() const noexcept
0688 {
0689 return size >= (numBuckets >> 1);
0690 }
0691
0692 template <typename K> Bucket findBucket(const K &key) const noexcept
0693 {
0694 size_t hash = QHashPrivate::calculateHash(key, seed);
0695 return findBucketWithHash(key, hash);
0696 }
0697
0698 template <typename K> Bucket findBucketWithHash(const K &key, size_t hash) const noexcept
0699 {
0700 static_assert(std::is_same_v<std::remove_cv_t<Key>, K> ||
0701 QHashHeterogeneousSearch<std::remove_cv_t<Key>, K>::value);
0702 Q_ASSERT(numBuckets > 0);
0703 Bucket bucket(this, GrowthPolicy::bucketForHash(numBuckets, hash));
0704
0705
0706 while (true) {
0707 size_t offset = bucket.offset();
0708 if (offset == SpanConstants::UnusedEntry) {
0709 return bucket;
0710 } else {
0711 Node &n = bucket.nodeAtOffset(offset);
0712 if (qHashEquals(n.key, key))
0713 return bucket;
0714 }
0715 bucket.advanceWrapped(this);
0716 }
0717 }
0718
0719 template <typename K> Node *findNode(const K &key) const noexcept
0720 {
0721 auto bucket = findBucket(key);
0722 if (bucket.isUnused())
0723 return nullptr;
0724 return bucket.node();
0725 }
0726
0727 struct InsertionResult
0728 {
0729 iterator it;
0730 bool initialized;
0731 };
0732
0733 template <typename K> InsertionResult findOrInsert(const K &key) noexcept
0734 {
0735 Bucket it(static_cast<Span *>(nullptr), 0);
0736 size_t hash = QHashPrivate::calculateHash(key, seed);
0737 if (numBuckets > 0) {
0738 it = findBucketWithHash(key, hash);
0739 if (!it.isUnused())
0740 return { it.toIterator(this), true };
0741 }
0742 if (shouldGrow()) {
0743 rehash(size + 1);
0744 it = findBucketWithHash(key, hash);
0745 }
0746 Q_ASSERT(it.span != nullptr);
0747 Q_ASSERT(it.isUnused());
0748 it.insert();
0749 ++size;
0750 return { it.toIterator(this), false };
0751 }
0752
0753 void erase(Bucket bucket) noexcept(std::is_nothrow_destructible<Node>::value)
0754 {
0755 Q_ASSERT(bucket.span->hasNode(bucket.index));
0756 bucket.span->erase(bucket.index);
0757 --size;
0758
0759
0760 Bucket next = bucket;
0761 while (true) {
0762 next.advanceWrapped(this);
0763 size_t offset = next.offset();
0764 if (offset == SpanConstants::UnusedEntry)
0765 return;
0766 size_t hash = QHashPrivate::calculateHash(next.nodeAtOffset(offset).key, seed);
0767 Bucket newBucket(this, GrowthPolicy::bucketForHash(numBuckets, hash));
0768 while (true) {
0769 if (newBucket == next) {
0770
0771 break;
0772 } else if (newBucket == bucket) {
0773
0774 if (next.span == bucket.span) {
0775 bucket.span->moveLocal(next.index, bucket.index);
0776 } else {
0777
0778 bucket.span->moveFromSpan(*next.span, next.index, bucket.index);
0779 }
0780 bucket = next;
0781 break;
0782 }
0783 newBucket.advanceWrapped(this);
0784 }
0785 }
0786 }
0787
0788 ~Data()
0789 {
0790 delete [] spans;
0791 }
0792 };
0793
0794 template <typename Node>
0795 struct iterator {
0796 using Span = QHashPrivate::Span<Node>;
0797
0798 const Data<Node> *d = nullptr;
0799 size_t bucket = 0;
0800
0801 size_t span() const noexcept { return bucket >> SpanConstants::SpanShift; }
0802 size_t index() const noexcept { return bucket & SpanConstants::LocalBucketMask; }
0803 inline bool isUnused() const noexcept { return !d->spans[span()].hasNode(index()); }
0804
0805 inline Node *node() const noexcept
0806 {
0807 Q_ASSERT(!isUnused());
0808 return &d->spans[span()].at(index());
0809 }
0810 bool atEnd() const noexcept { return !d; }
0811
0812 iterator operator++() noexcept
0813 {
0814 while (true) {
0815 ++bucket;
0816 if (bucket == d->numBuckets) {
0817 d = nullptr;
0818 bucket = 0;
0819 break;
0820 }
0821 if (!isUnused())
0822 break;
0823 }
0824 return *this;
0825 }
0826 bool operator==(iterator other) const noexcept
0827 { return d == other.d && bucket == other.bucket; }
0828 bool operator!=(iterator other) const noexcept
0829 { return !(*this == other); }
0830 };
0831
0832 template <typename HashKey, typename KeyArgument>
0833 using HeterogenousConstructProxy = std::conditional_t<
0834 std::is_same_v<HashKey, q20::remove_cvref_t<KeyArgument>>,
0835 KeyArgument,
0836 HashKey
0837 >;
0838
0839 }
0840
0841 template <typename Key, typename T>
0842 class QHash
0843 {
0844 using Node = QHashPrivate::Node<Key, T>;
0845 using Data = QHashPrivate::Data<Node>;
0846 friend class QSet<Key>;
0847 friend class QMultiHash<Key, T>;
0848 friend tst_QHash;
0849
0850 Data *d = nullptr;
0851
0852 public:
0853 using key_type = Key;
0854 using mapped_type = T;
0855 using value_type = T;
0856 using size_type = qsizetype;
0857 using difference_type = qsizetype;
0858 using reference = T &;
0859 using const_reference = const T &;
0860
0861 inline QHash() noexcept = default;
0862 inline QHash(std::initializer_list<std::pair<Key,T> > list)
0863 : d(new Data(list.size()))
0864 {
0865 for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
0866 insert(it->first, it->second);
0867 }
0868 QHash(const QHash &other) noexcept
0869 : d(other.d)
0870 {
0871 if (d)
0872 d->ref.ref();
0873 }
0874 ~QHash()
0875 {
0876 static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
0877 static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0878
0879 if (d && !d->ref.deref())
0880 delete d;
0881 }
0882
0883 QHash &operator=(const QHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
0884 {
0885 if (d != other.d) {
0886 Data *o = other.d;
0887 if (o)
0888 o->ref.ref();
0889 if (d && !d->ref.deref())
0890 delete d;
0891 d = o;
0892 }
0893 return *this;
0894 }
0895
0896 QHash(QHash &&other) noexcept
0897 : d(std::exchange(other.d, nullptr))
0898 {
0899 }
0900 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHash)
0901 #ifdef Q_QDOC
0902 template <typename InputIterator>
0903 QHash(InputIterator f, InputIterator l);
0904 #else
0905 template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
0906 QHash(InputIterator f, InputIterator l)
0907 : QHash()
0908 {
0909 QtPrivate::reserveIfForwardIterator(this, f, l);
0910 for (; f != l; ++f)
0911 insert(f.key(), f.value());
0912 }
0913
0914 template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
0915 QHash(InputIterator f, InputIterator l)
0916 : QHash()
0917 {
0918 QtPrivate::reserveIfForwardIterator(this, f, l);
0919 for (; f != l; ++f) {
0920 auto &&e = *f;
0921 using V = decltype(e);
0922 insert(std::forward<V>(e).first, std::forward<V>(e).second);
0923 }
0924 }
0925 #endif
0926 void swap(QHash &other) noexcept { qt_ptr_swap(d, other.d); }
0927
0928 class const_iterator;
0929
0930 #ifndef Q_QDOC
0931 private:
0932 static bool compareIterators(const const_iterator &lhs, const const_iterator &rhs)
0933 {
0934 return lhs.i.node()->valuesEqual(rhs.i.node());
0935 }
0936
0937 template <typename AKey = Key, typename AT = T,
0938 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> = true>
0939 friend bool comparesEqual(const QHash &lhs, const QHash &rhs) noexcept
0940 {
0941 if (lhs.d == rhs.d)
0942 return true;
0943 if (lhs.size() != rhs.size())
0944 return false;
0945
0946 for (const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
0947 const_iterator i = lhs.find(it.key());
0948 if (i == lhs.end() || !compareIterators(i, it))
0949 return false;
0950 }
0951
0952 return true;
0953 }
0954 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QHash, QHash, , noexcept,
0955 template <typename AKey = Key, typename AT = T,
0956 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> = true>)
0957 public:
0958 #else
0959 friend bool operator==(const QHash &lhs, const QHash &rhs) noexcept;
0960 friend bool operator!=(const QHash &lhs, const QHash &rhs) noexcept;
0961 #endif
0962
0963 inline qsizetype size() const noexcept { return d ? qsizetype(d->size) : 0; }
0964
0965 [[nodiscard]]
0966 inline bool isEmpty() const noexcept { return !d || d->size == 0; }
0967
0968 inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
0969 void reserve(qsizetype size)
0970 {
0971
0972 if (size && (this->capacity() >= size))
0973 return;
0974 if (isDetached())
0975 d->rehash(size);
0976 else
0977 d = Data::detached(d, size_t(size));
0978 }
0979 inline void squeeze()
0980 {
0981 if (capacity())
0982 reserve(0);
0983 }
0984
0985 inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
0986 inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
0987 bool isSharedWith(const QHash &other) const noexcept { return d == other.d; }
0988
0989 void clear() noexcept(std::is_nothrow_destructible<Node>::value)
0990 {
0991 if (d && !d->ref.deref())
0992 delete d;
0993 d = nullptr;
0994 }
0995
0996 bool remove(const Key &key)
0997 {
0998 return removeImpl(key);
0999 }
1000 private:
1001 template <typename K> bool removeImpl(const K &key)
1002 {
1003 if (isEmpty())
1004 return false;
1005 auto it = d->findBucket(key);
1006 if (it.isUnused())
1007 return false;
1008
1009 size_t bucket = it.toBucketIndex(d);
1010 detach();
1011 it = typename Data::Bucket(d, bucket);
1012
1013 d->erase(it);
1014 return true;
1015 }
1016
1017 public:
1018 template <typename Predicate>
1019 qsizetype removeIf(Predicate pred)
1020 {
1021 return QtPrivate::associative_erase_if(*this, pred);
1022 }
1023
1024 T take(const Key &key)
1025 {
1026 return takeImpl(key);
1027 }
1028 private:
1029 template <typename K> T takeImpl(const K &key)
1030 {
1031 if (isEmpty())
1032 return T();
1033 auto it = d->findBucket(key);
1034 size_t bucket = it.toBucketIndex(d);
1035 detach();
1036 it = typename Data::Bucket(d, bucket);
1037
1038 if (it.isUnused())
1039 return T();
1040 return [&] {
1041 T value = it.node()->takeValue();
1042 d->erase(it);
1043 return value;
1044 }();
1045 }
1046
1047 public:
1048 bool contains(const Key &key) const noexcept
1049 {
1050 if (!d)
1051 return false;
1052 return d->findNode(key) != nullptr;
1053 }
1054 qsizetype count(const Key &key) const noexcept
1055 {
1056 return contains(key) ? 1 : 0;
1057 }
1058
1059 private:
1060 const Key *keyImpl(const T &value) const noexcept
1061 {
1062 if (d) {
1063 const_iterator i = begin();
1064 while (i != end()) {
1065 if (i.value() == value)
1066 return &i.key();
1067 ++i;
1068 }
1069 }
1070
1071 return nullptr;
1072 }
1073
1074 public:
1075 Key key(const T &value) const noexcept
1076 {
1077 if (auto *k = keyImpl(value))
1078 return *k;
1079 else
1080 return Key();
1081 }
1082 Key key(const T &value, const Key &defaultKey) const noexcept
1083 {
1084 if (auto *k = keyImpl(value))
1085 return *k;
1086 else
1087 return defaultKey;
1088 }
1089
1090 private:
1091 template <typename K>
1092 T *valueImpl(const K &key) const noexcept
1093 {
1094 if (d) {
1095 Node *n = d->findNode(key);
1096 if (n)
1097 return &n->value;
1098 }
1099 return nullptr;
1100 }
1101 public:
1102 T value(const Key &key) const noexcept
1103 {
1104 if (T *v = valueImpl(key))
1105 return *v;
1106 else
1107 return T();
1108 }
1109
1110 T value(const Key &key, const T &defaultValue) const noexcept
1111 {
1112 if (T *v = valueImpl(key))
1113 return *v;
1114 else
1115 return defaultValue;
1116 }
1117
1118 T &operator[](const Key &key)
1119 {
1120 return *tryEmplace(key).iterator;
1121 }
1122
1123 const T operator[](const Key &key) const noexcept
1124 {
1125 return value(key);
1126 }
1127
1128 QList<Key> keys() const { return QList<Key>(keyBegin(), keyEnd()); }
1129 QList<Key> keys(const T &value) const
1130 {
1131 QList<Key> res;
1132 const_iterator i = begin();
1133 while (i != end()) {
1134 if (i.value() == value)
1135 res.append(i.key());
1136 ++i;
1137 }
1138 return res;
1139 }
1140 QList<T> values() const { return QList<T>(begin(), end()); }
1141
1142 class iterator
1143 {
1144 using piter = typename QHashPrivate::iterator<Node>;
1145 friend class const_iterator;
1146 friend class QHash<Key, T>;
1147 friend class QSet<Key>;
1148 piter i;
1149 explicit inline iterator(piter it) noexcept : i(it) { }
1150
1151 public:
1152 typedef std::forward_iterator_tag iterator_category;
1153 typedef qptrdiff difference_type;
1154 typedef T value_type;
1155 typedef T *pointer;
1156 typedef T &reference;
1157
1158 constexpr iterator() noexcept = default;
1159
1160 inline const Key &key() const noexcept { return i.node()->key; }
1161 inline T &value() const noexcept { return i.node()->value; }
1162 inline T &operator*() const noexcept { return i.node()->value; }
1163 inline T *operator->() const noexcept { return &i.node()->value; }
1164 inline bool operator==(const iterator &o) const noexcept { return i == o.i; }
1165 inline bool operator!=(const iterator &o) const noexcept { return i != o.i; }
1166
1167 inline iterator &operator++() noexcept
1168 {
1169 ++i;
1170 return *this;
1171 }
1172 inline iterator operator++(int) noexcept
1173 {
1174 iterator r = *this;
1175 ++i;
1176 return r;
1177 }
1178
1179 inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
1180 inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
1181 };
1182 friend class iterator;
1183
1184 class const_iterator
1185 {
1186 using piter = typename QHashPrivate::iterator<Node>;
1187 friend class iterator;
1188 friend class QHash<Key, T>;
1189 friend class QSet<Key>;
1190 piter i;
1191 explicit inline const_iterator(piter it) : i(it) { }
1192
1193 public:
1194 typedef std::forward_iterator_tag iterator_category;
1195 typedef qptrdiff difference_type;
1196 typedef T value_type;
1197 typedef const T *pointer;
1198 typedef const T &reference;
1199
1200 constexpr const_iterator() noexcept = default;
1201 inline const_iterator(const iterator &o) noexcept : i(o.i) { }
1202
1203 inline const Key &key() const noexcept { return i.node()->key; }
1204 inline const T &value() const noexcept { return i.node()->value; }
1205 inline const T &operator*() const noexcept { return i.node()->value; }
1206 inline const T *operator->() const noexcept { return &i.node()->value; }
1207 inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
1208 inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
1209
1210 inline const_iterator &operator++() noexcept
1211 {
1212 ++i;
1213 return *this;
1214 }
1215 inline const_iterator operator++(int) noexcept
1216 {
1217 const_iterator r = *this;
1218 ++i;
1219 return r;
1220 }
1221 };
1222 friend class const_iterator;
1223
1224 class key_iterator
1225 {
1226 const_iterator i;
1227
1228 public:
1229 typedef typename const_iterator::iterator_category iterator_category;
1230 typedef qptrdiff difference_type;
1231 typedef Key value_type;
1232 typedef const Key *pointer;
1233 typedef const Key &reference;
1234
1235 key_iterator() noexcept = default;
1236 explicit key_iterator(const_iterator o) noexcept : i(o) { }
1237
1238 const Key &operator*() const noexcept { return i.key(); }
1239 const Key *operator->() const noexcept { return &i.key(); }
1240 bool operator==(key_iterator o) const noexcept { return i == o.i; }
1241 bool operator!=(key_iterator o) const noexcept { return i != o.i; }
1242
1243 inline key_iterator &operator++() noexcept { ++i; return *this; }
1244 inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
1245 const_iterator base() const noexcept { return i; }
1246 };
1247
1248 typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1249 typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1250
1251
1252 inline iterator begin() { if (!d) return iterator(); detach(); return iterator(d->begin()); }
1253 inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1254 inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1255 inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1256 inline iterator end() noexcept { return iterator(); }
1257 inline const_iterator end() const noexcept { return const_iterator(); }
1258 inline const_iterator cend() const noexcept { return const_iterator(); }
1259 inline const_iterator constEnd() const noexcept { return const_iterator(); }
1260 inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
1261 inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
1262 inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
1263 inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
1264 inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
1265 inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
1266 inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
1267 inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
1268 auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QHash &>(*this); }
1269 auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QHash &>(*this); }
1270 auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QHash>(std::move(*this)); }
1271 auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QHash>(std::move(*this)); }
1272
1273 struct TryEmplaceResult
1274 {
1275 QHash::iterator iterator;
1276 bool inserted;
1277
1278 TryEmplaceResult() = default;
1279
1280 TryEmplaceResult(QHash::iterator it, bool b)
1281 : iterator(it), inserted(b)
1282 {
1283 }
1284
1285
1286 Q_IMPLICIT TryEmplaceResult(const std::pair<key_value_iterator, bool> &p)
1287 : iterator(p.first.base()), inserted(p.second)
1288 {
1289 }
1290
1291 Q_IMPLICIT operator std::pair<key_value_iterator, bool>()
1292 {
1293 return { key_value_iterator(iterator), inserted };
1294 }
1295 };
1296
1297 iterator erase(const_iterator it)
1298 {
1299 Q_ASSERT(it != constEnd());
1300 detach();
1301
1302 iterator i = iterator{d->detachedIterator(it.i)};
1303 typename Data::Bucket bucket(i.i);
1304
1305 d->erase(bucket);
1306 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
1307 ++i;
1308 return i;
1309 }
1310
1311 std::pair<iterator, iterator> equal_range(const Key &key)
1312 {
1313 return equal_range_impl(*this, key);
1314 }
1315 std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
1316 {
1317 return equal_range_impl(*this, key);
1318 }
1319 private:
1320 template <typename Hash, typename K> static auto equal_range_impl(Hash &self, const K &key)
1321 {
1322 auto first = self.find(key);
1323 auto second = first;
1324 if (second != decltype(first){})
1325 ++second;
1326 return std::make_pair(first, second);
1327 }
1328
1329 template <typename K> iterator findImpl(const K &key)
1330 {
1331 if (isEmpty())
1332 return end();
1333 auto it = d->findBucket(key);
1334 size_t bucket = it.toBucketIndex(d);
1335 detach();
1336 it = typename Data::Bucket(d, bucket);
1337 if (it.isUnused())
1338 return end();
1339 return iterator(it.toIterator(d));
1340 }
1341 template <typename K> const_iterator constFindImpl(const K &key) const noexcept
1342 {
1343 if (isEmpty())
1344 return end();
1345 auto it = d->findBucket(key);
1346 if (it.isUnused())
1347 return end();
1348 return const_iterator({d, it.toBucketIndex(d)});
1349 }
1350
1351 public:
1352 typedef iterator Iterator;
1353 typedef const_iterator ConstIterator;
1354 inline qsizetype count() const noexcept { return d ? qsizetype(d->size) : 0; }
1355 iterator find(const Key &key)
1356 {
1357 return findImpl(key);
1358 }
1359 const_iterator find(const Key &key) const noexcept
1360 {
1361 return constFindImpl(key);
1362 }
1363 const_iterator constFind(const Key &key) const noexcept
1364 {
1365 return find(key);
1366 }
1367
1368 iterator insert(const Key &key, const T &value)
1369 {
1370 return emplace(key, value);
1371 }
1372
1373 iterator insert(const Key &key, T &&value)
1374 {
1375 return emplace(key, std::move(value));
1376 }
1377
1378 iterator insert(Key &&key, const T &value)
1379 {
1380 return emplace(std::move(key), value);
1381 }
1382
1383 iterator insert(Key &&key, T &&value)
1384 {
1385 return emplace(std::move(key), std::move(value));
1386 }
1387
1388 void insert(const QHash &hash)
1389 {
1390 if (d == hash.d || !hash.d)
1391 return;
1392 if (!d) {
1393 *this = hash;
1394 return;
1395 }
1396
1397 detach();
1398
1399 for (auto it = hash.begin(); it != hash.end(); ++it)
1400 emplace(it.key(), it.value());
1401 }
1402
1403 template <typename ...Args>
1404 iterator emplace(const Key &key, Args &&... args)
1405 {
1406 Key copy = key;
1407 return emplace(std::move(copy), std::forward<Args>(args)...);
1408 }
1409
1410 template <typename ...Args>
1411 iterator emplace(Key &&key, Args &&... args)
1412 {
1413 if (isDetached()) {
1414 if (d->shouldGrow())
1415 return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
1416 return emplace_helper(std::move(key), std::forward<Args>(args)...);
1417 }
1418
1419 const auto copy = *this;
1420 detach();
1421 return emplace_helper(std::move(key), std::forward<Args>(args)...);
1422 }
1423
1424 template <typename... Args>
1425 TryEmplaceResult tryEmplace(const Key &key, Args &&...args)
1426 {
1427 return tryEmplace_impl(key, std::forward<Args>(args)...);
1428 }
1429 template <typename... Args>
1430 TryEmplaceResult tryEmplace(Key &&key, Args &&...args)
1431 {
1432 return tryEmplace_impl(std::move(key), std::forward<Args>(args)...);
1433 }
1434
1435 TryEmplaceResult tryInsert(const Key &key, const T &value)
1436 {
1437 return tryEmplace_impl(key, value);
1438 }
1439
1440 template <typename... Args>
1441 std::pair<key_value_iterator, bool> try_emplace(const Key &key, Args &&...args)
1442 {
1443 return tryEmplace_impl(key, std::forward<Args>(args)...);
1444 }
1445 template <typename... Args>
1446 std::pair<key_value_iterator, bool> try_emplace(Key &&key, Args &&...args)
1447 {
1448 return tryEmplace_impl(std::move(key), std::forward<Args>(args)...);
1449 }
1450 template <typename... Args>
1451 key_value_iterator try_emplace(const_iterator , const Key &key, Args &&...args)
1452 {
1453 return key_value_iterator(tryEmplace_impl(key, std::forward<Args>(args)...).iterator);
1454 }
1455 template <typename... Args>
1456 key_value_iterator try_emplace(const_iterator , Key &&key, Args &&...args)
1457 {
1458 return key_value_iterator(tryEmplace_impl(std::move(key), std::forward<Args>(args)...).iterator);
1459 }
1460
1461 private:
1462 template <typename K, typename... Args>
1463 TryEmplaceResult tryEmplace_impl(K &&key, Args &&...args)
1464 {
1465 if (!d)
1466 detach();
1467 QHash detachGuard;
1468
1469 size_t hash = QHashPrivate::calculateHash(key, d->seed);
1470 typename Data::Bucket bucket = d->findBucketWithHash(key, hash);
1471 const bool shouldInsert = bucket.isUnused();
1472
1473
1474
1475 if (!isDetached() || (shouldInsert && d->shouldGrow())) {
1476 detachGuard = *this;
1477 const bool resized = shouldInsert && d->shouldGrow();
1478 const size_t bucketIndex = bucket.toBucketIndex(d);
1479
1480
1481 d = resized ? Data::detached(d, d->size + 1) : Data::detached(d);
1482 bucket = resized ? d->findBucketWithHash(key, hash) : typename Data::Bucket(d, bucketIndex);
1483 }
1484 if (shouldInsert) {
1485 Node *n = bucket.insert();
1486 using ConstructProxy = typename QHashPrivate::HeterogenousConstructProxy<Key, K>;
1487 Node::createInPlace(n, ConstructProxy(std::forward<K>(key)),
1488 std::forward<Args>(args)...);
1489 ++d->size;
1490 }
1491 return {iterator(bucket.toIterator(d)), shouldInsert};
1492 }
1493 public:
1494 template <typename Value>
1495 TryEmplaceResult insertOrAssign(const Key &key, Value &&value)
1496 {
1497 return insertOrAssign_impl(key, std::forward<Value>(value));
1498 }
1499 template <typename Value>
1500 TryEmplaceResult insertOrAssign(Key &&key, Value &&value)
1501 {
1502 return insertOrAssign_impl(std::move(key), std::forward<Value>(value));
1503 }
1504 template <typename Value>
1505 std::pair<key_value_iterator, bool> insert_or_assign(const Key &key, Value &&value)
1506 {
1507 return insertOrAssign_impl(key, std::forward<Value>(value));
1508 }
1509 template <typename Value>
1510 std::pair<key_value_iterator, bool> insert_or_assign(Key &&key, Value &&value)
1511 {
1512 return insertOrAssign_impl(std::move(key), std::forward<Value>(value));
1513 }
1514 template <typename Value>
1515 key_value_iterator insert_or_assign(const_iterator , const Key &key, Value &&value)
1516 {
1517 return key_value_iterator(insertOrAssign_impl(key, std::forward<Value>(value)).iterator);
1518 }
1519 template <typename Value>
1520 key_value_iterator insert_or_assign(const_iterator , Key &&key, Value &&value)
1521 {
1522 return key_value_iterator(insertOrAssign_impl(std::move(key), std::forward<Value>(value)).iterator);
1523 }
1524
1525 private:
1526 template <typename K, typename Value>
1527 TryEmplaceResult insertOrAssign_impl(K &&key, Value &&value)
1528 {
1529 auto r = tryEmplace(std::forward<K>(key), std::forward<Value>(value));
1530 if (!r.inserted)
1531 *r.iterator = std::forward<Value>(value);
1532 return r;
1533 }
1534
1535 public:
1536
1537 float load_factor() const noexcept { return d ? d->loadFactor() : 0; }
1538 static float max_load_factor() noexcept { return 0.5; }
1539 size_t bucket_count() const noexcept { return d ? d->numBuckets : 0; }
1540 static size_t max_bucket_count() noexcept { return Data::maxNumBuckets(); }
1541
1542 [[nodiscard]]
1543 inline bool empty() const noexcept { return isEmpty(); }
1544
1545 private:
1546 template <typename ...Args>
1547 iterator emplace_helper(Key &&key, Args &&... args)
1548 {
1549 auto result = d->findOrInsert(key);
1550 if (!result.initialized)
1551 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
1552 else
1553 result.it.node()->emplaceValue(std::forward<Args>(args)...);
1554 return iterator(result.it);
1555 }
1556
1557 template <typename K>
1558 using if_heterogeneously_searchable = QHashPrivate::if_heterogeneously_searchable_with<Key, K>;
1559
1560 template <typename K>
1561 using if_key_constructible_from = std::enable_if_t<std::is_constructible_v<Key, K>, bool>;
1562
1563 public:
1564 template <typename K, if_heterogeneously_searchable<K> = true>
1565 bool remove(const K &key)
1566 {
1567 return removeImpl(key);
1568 }
1569 template <typename K, if_heterogeneously_searchable<K> = true>
1570 T take(const K &key)
1571 {
1572 return takeImpl(key);
1573 }
1574 template <typename K, if_heterogeneously_searchable<K> = true>
1575 bool contains(const K &key) const
1576 {
1577 return d ? d->findNode(key) != nullptr : false;
1578 }
1579 template <typename K, if_heterogeneously_searchable<K> = true>
1580 qsizetype count(const K &key) const
1581 {
1582 return contains(key) ? 1 : 0;
1583 }
1584 template <typename K, if_heterogeneously_searchable<K> = true>
1585 T value(const K &key) const noexcept
1586 {
1587 if (auto *v = valueImpl(key))
1588 return *v;
1589 else
1590 return T();
1591 }
1592 template <typename K, if_heterogeneously_searchable<K> = true>
1593 T value(const K &key, const T &defaultValue) const noexcept
1594 {
1595 if (auto *v = valueImpl(key))
1596 return *v;
1597 else
1598 return defaultValue;
1599 }
1600 template <typename K, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1601 T &operator[](const K &key)
1602 {
1603 return *tryEmplace(key).iterator;
1604 }
1605 template <typename K, if_heterogeneously_searchable<K> = true>
1606 const T operator[](const K &key) const noexcept
1607 {
1608 return value(key);
1609 }
1610 template <typename K, if_heterogeneously_searchable<K> = true>
1611 std::pair<iterator, iterator>
1612 equal_range(const K &key)
1613 {
1614 return equal_range_impl(*this, key);
1615 }
1616 template <typename K, if_heterogeneously_searchable<K> = true>
1617 std::pair<const_iterator, const_iterator>
1618 equal_range(const K &key) const noexcept
1619 {
1620 return equal_range_impl(*this, key);
1621 }
1622 template <typename K, if_heterogeneously_searchable<K> = true>
1623 iterator find(const K &key)
1624 {
1625 return findImpl(key);
1626 }
1627 template <typename K, if_heterogeneously_searchable<K> = true>
1628 const_iterator find(const K &key) const noexcept
1629 {
1630 return constFindImpl(key);
1631 }
1632 template <typename K, if_heterogeneously_searchable<K> = true>
1633 const_iterator constFind(const K &key) const noexcept
1634 {
1635 return find(key);
1636 }
1637 template <typename K, typename... Args, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1638 TryEmplaceResult tryEmplace(K &&key, Args &&...args)
1639 {
1640 return tryEmplace_impl(std::forward<K>(key), std::forward<Args>(args)...);
1641 }
1642 template <typename K, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1643 TryEmplaceResult tryInsert(K &&key, const T &value)
1644 {
1645 return tryEmplace_impl(std::forward<K>(key), value);
1646 }
1647 template <typename K, typename... Args, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1648 std::pair<key_value_iterator, bool> try_emplace(K &&key, Args &&...args)
1649 {
1650 return tryEmplace_impl(std::forward<K>(key), std::forward<Args>(args)...);
1651 }
1652 template <typename K, typename... Args, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1653 key_value_iterator try_emplace(const_iterator , K &&key, Args &&...args)
1654 {
1655 return key_value_iterator(tryEmplace_impl(std::forward<K>(key), std::forward<Args>(args)...).iterator);
1656 }
1657 template <typename K, typename Value, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1658 TryEmplaceResult insertOrAssign(K &&key, Value &&value)
1659 {
1660 return insertOrAssign_impl(std::forward<K>(key), std::forward<Value>(value));
1661 }
1662 template <typename K, typename Value, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1663 std::pair<key_value_iterator, bool> insert_or_assign(K &&key, Value &&value)
1664 {
1665 return insertOrAssign_impl(std::forward<K>(key), std::forward<Value>(value));
1666 }
1667 template <typename K, typename Value, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
1668 key_value_iterator insert_or_assign(const_iterator , K &&key, Value &&value)
1669 {
1670 return key_value_iterator(insertOrAssign_impl(std::forward<K>(key), std::forward<Value>(value)).iterator);
1671 }
1672 };
1673
1674
1675 template <typename Key, typename T>
1676 class QMultiHash
1677 {
1678 using Node = QHashPrivate::MultiNode<Key, T>;
1679 using Data = QHashPrivate::Data<Node>;
1680 using Chain = QHashPrivate::MultiNodeChain<T>;
1681
1682 Data *d = nullptr;
1683 qsizetype m_size = 0;
1684
1685 public:
1686 using key_type = Key;
1687 using mapped_type = T;
1688 using value_type = T;
1689 using size_type = qsizetype;
1690 using difference_type = qsizetype;
1691 using reference = T &;
1692 using const_reference = const T &;
1693
1694 QMultiHash() noexcept = default;
1695 inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
1696 : d(new Data(list.size()))
1697 {
1698 for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
1699 insert(it->first, it->second);
1700 }
1701 #ifdef Q_QDOC
1702 template <typename InputIterator>
1703 QMultiHash(InputIterator f, InputIterator l);
1704 #else
1705 template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
1706 QMultiHash(InputIterator f, InputIterator l)
1707 {
1708 QtPrivate::reserveIfForwardIterator(this, f, l);
1709 for (; f != l; ++f)
1710 insert(f.key(), f.value());
1711 }
1712
1713 template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
1714 QMultiHash(InputIterator f, InputIterator l)
1715 {
1716 QtPrivate::reserveIfForwardIterator(this, f, l);
1717 for (; f != l; ++f) {
1718 auto &&e = *f;
1719 using V = decltype(e);
1720 insert(std::forward<V>(e).first, std::forward<V>(e).second);
1721 }
1722 }
1723 #endif
1724 QMultiHash(const QMultiHash &other) noexcept
1725 : d(other.d), m_size(other.m_size)
1726 {
1727 if (d)
1728 d->ref.ref();
1729 }
1730 ~QMultiHash()
1731 {
1732 static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
1733 static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
1734
1735 if (d && !d->ref.deref())
1736 delete d;
1737 }
1738
1739 QMultiHash &operator=(const QMultiHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
1740 {
1741 if (d != other.d) {
1742 Data *o = other.d;
1743 if (o)
1744 o->ref.ref();
1745 if (d && !d->ref.deref())
1746 delete d;
1747 d = o;
1748 m_size = other.m_size;
1749 }
1750 return *this;
1751 }
1752 QMultiHash(QMultiHash &&other) noexcept
1753 : d(std::exchange(other.d, nullptr)),
1754 m_size(std::exchange(other.m_size, 0))
1755 {
1756 }
1757 QMultiHash &operator=(QMultiHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
1758 {
1759 QMultiHash moved(std::move(other));
1760 swap(moved);
1761 return *this;
1762 }
1763
1764 explicit QMultiHash(const QHash<Key, T> &other)
1765 : QMultiHash(other.begin(), other.end())
1766 {}
1767
1768 explicit QMultiHash(QHash<Key, T> &&other)
1769 {
1770 unite(std::move(other));
1771 }
1772
1773 void swap(QMultiHash &other) noexcept
1774 {
1775 qt_ptr_swap(d, other.d);
1776 std::swap(m_size, other.m_size);
1777 }
1778
1779 #ifndef Q_QDOC
1780 private:
1781 template <typename AKey = Key, typename AT = T,
1782 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> = true>
1783 friend bool comparesEqual(const QMultiHash &lhs, const QMultiHash &rhs) noexcept
1784 {
1785 if (lhs.d == rhs.d)
1786 return true;
1787 if (lhs.m_size != rhs.m_size)
1788 return false;
1789 if (lhs.m_size == 0)
1790 return true;
1791
1792 Q_ASSERT(lhs.d);
1793 Q_ASSERT(rhs.d);
1794 if (lhs.d->size != rhs.d->size)
1795 return false;
1796 for (auto it = rhs.d->begin(); it != rhs.d->end(); ++it) {
1797 auto *n = lhs.d->findNode(it.node()->key);
1798 if (!n)
1799 return false;
1800 Chain *e = it.node()->value;
1801 while (e) {
1802 Chain *oe = n->value;
1803 while (oe) {
1804 if (oe->value == e->value)
1805 break;
1806 oe = oe->next;
1807 }
1808 if (!oe)
1809 return false;
1810 e = e->next;
1811 }
1812 }
1813
1814 return true;
1815 }
1816 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiHash, QMultiHash, , noexcept,
1817 template <typename AKey = Key, typename AT = T,
1818 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> = true>)
1819 public:
1820 #else
1821 friend bool operator==(const QMultiHash &lhs, const QMultiHash &rhs) noexcept;
1822 friend bool operator!=(const QMultiHash &lhs, const QMultiHash &rhs) noexcept;
1823 #endif
1824
1825 inline qsizetype size() const noexcept { return m_size; }
1826
1827 [[nodiscard]]
1828 inline bool isEmpty() const noexcept { return !m_size; }
1829
1830 inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
1831 void reserve(qsizetype size)
1832 {
1833
1834 if (size && (this->capacity() >= size))
1835 return;
1836 if (isDetached())
1837 d->rehash(size);
1838 else
1839 d = Data::detached(d, size_t(size));
1840 }
1841 inline void squeeze() { reserve(0); }
1842
1843 inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
1844 inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
1845 bool isSharedWith(const QMultiHash &other) const noexcept { return d == other.d; }
1846
1847 void clear() noexcept(std::is_nothrow_destructible<Node>::value)
1848 {
1849 if (d && !d->ref.deref())
1850 delete d;
1851 d = nullptr;
1852 m_size = 0;
1853 }
1854
1855 qsizetype remove(const Key &key)
1856 {
1857 return removeImpl(key);
1858 }
1859 private:
1860 template <typename K> qsizetype removeImpl(const K &key)
1861 {
1862 if (isEmpty())
1863 return 0;
1864 auto it = d->findBucket(key);
1865 size_t bucket = it.toBucketIndex(d);
1866 detach();
1867 it = typename Data::Bucket(d, bucket);
1868
1869 if (it.isUnused())
1870 return 0;
1871 qsizetype n = Node::freeChain(it.node());
1872 m_size -= n;
1873 Q_ASSERT(m_size >= 0);
1874 d->erase(it);
1875 return n;
1876 }
1877
1878 public:
1879 template <typename Predicate>
1880 qsizetype removeIf(Predicate pred)
1881 {
1882 return QtPrivate::associative_erase_if(*this, pred);
1883 }
1884
1885 T take(const Key &key)
1886 {
1887 return takeImpl(key);
1888 }
1889 private:
1890 template <typename K> T takeImpl(const K &key)
1891 {
1892 if (isEmpty())
1893 return T();
1894 auto it = d->findBucket(key);
1895 size_t bucket = it.toBucketIndex(d);
1896 detach();
1897 it = typename Data::Bucket(d, bucket);
1898
1899 if (it.isUnused())
1900 return T();
1901 Chain *e = it.node()->value;
1902 Q_ASSERT(e);
1903 T t = std::move(e->value);
1904 if (e->next) {
1905 it.node()->value = e->next;
1906 delete e;
1907 } else {
1908
1909 d->erase(it);
1910 }
1911 --m_size;
1912 Q_ASSERT(m_size >= 0);
1913 return t;
1914 }
1915
1916 public:
1917 bool contains(const Key &key) const noexcept
1918 {
1919 if (!d)
1920 return false;
1921 return d->findNode(key) != nullptr;
1922 }
1923
1924 private:
1925 const Key *keyImpl(const T &value) const noexcept
1926 {
1927 if (d) {
1928 auto i = d->begin();
1929 while (i != d->end()) {
1930 Chain *e = i.node()->value;
1931 if (e->contains(value))
1932 return &i.node()->key;
1933 ++i;
1934 }
1935 }
1936
1937 return nullptr;
1938 }
1939 public:
1940 Key key(const T &value) const noexcept
1941 {
1942 if (auto *k = keyImpl(value))
1943 return *k;
1944 else
1945 return Key();
1946 }
1947 Key key(const T &value, const Key &defaultKey) const noexcept
1948 {
1949 if (auto *k = keyImpl(value))
1950 return *k;
1951 else
1952 return defaultKey;
1953 }
1954
1955 private:
1956 template <typename K>
1957 T *valueImpl(const K &key) const noexcept
1958 {
1959 if (d) {
1960 Node *n = d->findNode(key);
1961 if (n) {
1962 Q_ASSERT(n->value);
1963 return &n->value->value;
1964 }
1965 }
1966 return nullptr;
1967 }
1968 public:
1969 T value(const Key &key) const noexcept
1970 {
1971 if (auto *v = valueImpl(key))
1972 return *v;
1973 else
1974 return T();
1975 }
1976 T value(const Key &key, const T &defaultValue) const noexcept
1977 {
1978 if (auto *v = valueImpl(key))
1979 return *v;
1980 else
1981 return defaultValue;
1982 }
1983
1984 T &operator[](const Key &key)
1985 {
1986 return operatorIndexImpl(key);
1987 }
1988 private:
1989 template <typename K> T &operatorIndexImpl(const K &key)
1990 {
1991 const auto copy = isDetached() ? QMultiHash() : *this;
1992 detach();
1993 auto result = d->findOrInsert(key);
1994 Q_ASSERT(!result.it.atEnd());
1995 if (!result.initialized) {
1996 Node::createInPlace(result.it.node(), Key(key), T());
1997 ++m_size;
1998 }
1999 return result.it.node()->value->value;
2000 }
2001
2002 public:
2003 const T operator[](const Key &key) const noexcept
2004 {
2005 return value(key);
2006 }
2007
2008 QList<Key> uniqueKeys() const
2009 {
2010 QList<Key> res;
2011 if (d) {
2012 auto i = d->begin();
2013 while (i != d->end()) {
2014 res.append(i.node()->key);
2015 ++i;
2016 }
2017 }
2018 return res;
2019 }
2020
2021 QList<Key> keys() const { return QList<Key>(keyBegin(), keyEnd()); }
2022 QList<Key> keys(const T &value) const
2023 {
2024 QList<Key> res;
2025 const_iterator i = begin();
2026 while (i != end()) {
2027 if (i.value() == value)
2028 res.append(i.key());
2029 ++i;
2030 }
2031 return res;
2032 }
2033
2034 QList<T> values() const { return QList<T>(begin(), end()); }
2035 QList<T> values(const Key &key) const
2036 {
2037 return valuesImpl(key);
2038 }
2039 private:
2040 template <typename K> QList<T> valuesImpl(const K &key) const
2041 {
2042 QList<T> values;
2043 if (d) {
2044 Node *n = d->findNode(key);
2045 if (n) {
2046 Chain *e = n->value;
2047 while (e) {
2048 values.append(e->value);
2049 e = e->next;
2050 }
2051 }
2052 }
2053 return values;
2054 }
2055
2056 public:
2057 class const_iterator;
2058
2059 class iterator
2060 {
2061 using piter = typename QHashPrivate::iterator<Node>;
2062 friend class const_iterator;
2063 friend class QMultiHash<Key, T>;
2064 piter i;
2065 Chain **e = nullptr;
2066 explicit inline iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
2067 {
2068 if (!it.atEnd() && !e) {
2069 e = &it.node()->value;
2070 Q_ASSERT(e && *e);
2071 }
2072 }
2073
2074 public:
2075 typedef std::forward_iterator_tag iterator_category;
2076 typedef qptrdiff difference_type;
2077 typedef T value_type;
2078 typedef T *pointer;
2079 typedef T &reference;
2080
2081 constexpr iterator() noexcept = default;
2082
2083 inline const Key &key() const noexcept { return i.node()->key; }
2084 inline T &value() const noexcept { return (*e)->value; }
2085 inline T &operator*() const noexcept { return (*e)->value; }
2086 inline T *operator->() const noexcept { return &(*e)->value; }
2087 inline bool operator==(const iterator &o) const noexcept { return e == o.e; }
2088 inline bool operator!=(const iterator &o) const noexcept { return e != o.e; }
2089
2090 inline iterator &operator++() noexcept {
2091 Q_ASSERT(e && *e);
2092 e = &(*e)->next;
2093 Q_ASSERT(e);
2094 if (!*e) {
2095 ++i;
2096 e = i.atEnd() ? nullptr : &i.node()->value;
2097 }
2098 return *this;
2099 }
2100 inline iterator operator++(int) noexcept {
2101 iterator r = *this;
2102 ++(*this);
2103 return r;
2104 }
2105
2106 inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
2107 inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
2108 };
2109 friend class iterator;
2110
2111 class const_iterator
2112 {
2113 using piter = typename QHashPrivate::iterator<Node>;
2114 friend class iterator;
2115 friend class QMultiHash<Key, T>;
2116 piter i;
2117 Chain **e = nullptr;
2118 explicit inline const_iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
2119 {
2120 if (!it.atEnd() && !e) {
2121 e = &it.node()->value;
2122 Q_ASSERT(e && *e);
2123 }
2124 }
2125
2126 public:
2127 typedef std::forward_iterator_tag iterator_category;
2128 typedef qptrdiff difference_type;
2129 typedef T value_type;
2130 typedef const T *pointer;
2131 typedef const T &reference;
2132
2133 constexpr const_iterator() noexcept = default;
2134 inline const_iterator(const iterator &o) noexcept : i(o.i), e(o.e) { }
2135
2136 inline const Key &key() const noexcept { return i.node()->key; }
2137 inline T &value() const noexcept { return (*e)->value; }
2138 inline T &operator*() const noexcept { return (*e)->value; }
2139 inline T *operator->() const noexcept { return &(*e)->value; }
2140 inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
2141 inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
2142
2143 inline const_iterator &operator++() noexcept {
2144 Q_ASSERT(e && *e);
2145 e = &(*e)->next;
2146 Q_ASSERT(e);
2147 if (!*e) {
2148 ++i;
2149 e = i.atEnd() ? nullptr : &i.node()->value;
2150 }
2151 return *this;
2152 }
2153 inline const_iterator operator++(int) noexcept
2154 {
2155 const_iterator r = *this;
2156 ++(*this);
2157 return r;
2158 }
2159 };
2160 friend class const_iterator;
2161
2162 class key_iterator
2163 {
2164 const_iterator i;
2165
2166 public:
2167 typedef typename const_iterator::iterator_category iterator_category;
2168 typedef qptrdiff difference_type;
2169 typedef Key value_type;
2170 typedef const Key *pointer;
2171 typedef const Key &reference;
2172
2173 key_iterator() noexcept = default;
2174 explicit key_iterator(const_iterator o) noexcept : i(o) { }
2175
2176 const Key &operator*() const noexcept { return i.key(); }
2177 const Key *operator->() const noexcept { return &i.key(); }
2178 bool operator==(key_iterator o) const noexcept { return i == o.i; }
2179 bool operator!=(key_iterator o) const noexcept { return i != o.i; }
2180
2181 inline key_iterator &operator++() noexcept { ++i; return *this; }
2182 inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
2183 const_iterator base() const noexcept { return i; }
2184 };
2185
2186 typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
2187 typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
2188
2189
2190 inline iterator begin() { if (!d) return iterator(); detach(); return iterator(d->begin()); }
2191 inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
2192 inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
2193 inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
2194 inline iterator end() noexcept { return iterator(); }
2195 inline const_iterator end() const noexcept { return const_iterator(); }
2196 inline const_iterator cend() const noexcept { return const_iterator(); }
2197 inline const_iterator constEnd() const noexcept { return const_iterator(); }
2198 inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
2199 inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
2200 inline key_value_iterator keyValueBegin() noexcept { return key_value_iterator(begin()); }
2201 inline key_value_iterator keyValueEnd() noexcept { return key_value_iterator(end()); }
2202 inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
2203 inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
2204 inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
2205 inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
2206 auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMultiHash &>(*this); }
2207 auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMultiHash &>(*this); }
2208 auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMultiHash>(std::move(*this)); }
2209 auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMultiHash>(std::move(*this)); }
2210
2211 iterator detach(const_iterator it)
2212 {
2213 auto i = it.i;
2214 Chain **e = it.e;
2215 if (d->ref.isShared()) {
2216
2217 qsizetype n = 0;
2218 Chain *entry = i.node()->value;
2219 while (entry != *it.e) {
2220 ++n;
2221 entry = entry->next;
2222 }
2223 Q_ASSERT(entry);
2224 detach_helper();
2225
2226 i = d->detachedIterator(i);
2227 e = &i.node()->value;
2228 while (n) {
2229 e = &(*e)->next;
2230 --n;
2231 }
2232 Q_ASSERT(e && *e);
2233 }
2234 return iterator(i, e);
2235 }
2236
2237 iterator erase(const_iterator it)
2238 {
2239 Q_ASSERT(d);
2240 iterator iter = detach(it);
2241 iterator i = iter;
2242 Chain *e = *i.e;
2243 Chain *next = e->next;
2244 *i.e = next;
2245 delete e;
2246 if (!next) {
2247 if (i.e == &i.i.node()->value) {
2248
2249 typename Data::Bucket bucket(i.i);
2250 d->erase(bucket);
2251 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
2252 i = iterator(++iter.i);
2253 else
2254 i = iterator(bucket.toIterator(d));
2255 } else {
2256 i = iterator(++iter.i);
2257 }
2258 }
2259 --m_size;
2260 Q_ASSERT(m_size >= 0);
2261 return i;
2262 }
2263
2264
2265 typedef iterator Iterator;
2266 typedef const_iterator ConstIterator;
2267 inline qsizetype count() const noexcept { return size(); }
2268
2269 private:
2270 template <typename K> iterator findImpl(const K &key)
2271 {
2272 if (isEmpty())
2273 return end();
2274 auto it = d->findBucket(key);
2275 size_t bucket = it.toBucketIndex(d);
2276 detach();
2277 it = typename Data::Bucket(d, bucket);
2278
2279 if (it.isUnused())
2280 return end();
2281 return iterator(it.toIterator(d));
2282 }
2283 template <typename K> const_iterator constFindImpl(const K &key) const noexcept
2284 {
2285 if (isEmpty())
2286 return end();
2287 auto it = d->findBucket(key);
2288 if (it.isUnused())
2289 return constEnd();
2290 return const_iterator(it.toIterator(d));
2291 }
2292 public:
2293 iterator find(const Key &key)
2294 {
2295 return findImpl(key);
2296 }
2297 const_iterator constFind(const Key &key) const noexcept
2298 {
2299 return constFindImpl(key);
2300 }
2301 const_iterator find(const Key &key) const noexcept
2302 {
2303 return constFindImpl(key);
2304 }
2305
2306 iterator insert(const Key &key, const T &value)
2307 {
2308 return emplace(key, value);
2309 }
2310
2311 iterator insert(const Key &key, T &&value)
2312 {
2313 return emplace(key, std::move(value));
2314 }
2315
2316 iterator insert(Key &&key, const T &value)
2317 {
2318 return emplace(std::move(key), value);
2319 }
2320
2321 iterator insert(Key &&key, T &&value)
2322 {
2323 return emplace(std::move(key), std::move(value));
2324 }
2325
2326 template <typename ...Args>
2327 iterator emplace(const Key &key, Args &&... args)
2328 {
2329 return emplace(Key(key), std::forward<Args>(args)...);
2330 }
2331
2332 template <typename ...Args>
2333 iterator emplace(Key &&key, Args &&... args)
2334 {
2335 if (isDetached()) {
2336 if (d->shouldGrow())
2337 return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
2338 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2339 }
2340
2341 const auto copy = *this;
2342 detach();
2343 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2344 }
2345
2346
2347 float load_factor() const noexcept { return d ? d->loadFactor() : 0; }
2348 static float max_load_factor() noexcept { return 0.5; }
2349 size_t bucket_count() const noexcept { return d ? d->numBuckets : 0; }
2350 static size_t max_bucket_count() noexcept { return Data::maxNumBuckets(); }
2351
2352 [[nodiscard]]
2353 inline bool empty() const noexcept { return isEmpty(); }
2354
2355 inline iterator replace(const Key &key, const T &value)
2356 {
2357 return emplaceReplace(key, value);
2358 }
2359
2360 template <typename ...Args>
2361 iterator emplaceReplace(const Key &key, Args &&... args)
2362 {
2363 return emplaceReplace(Key(key), std::forward<Args>(args)...);
2364 }
2365
2366 template <typename ...Args>
2367 iterator emplaceReplace(Key &&key, Args &&... args)
2368 {
2369 if (isDetached()) {
2370 if (d->shouldGrow())
2371 return emplaceReplace_helper(std::move(key), T(std::forward<Args>(args)...));
2372 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2373 }
2374
2375 const auto copy = *this;
2376 detach();
2377 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2378 }
2379
2380 inline QMultiHash &operator+=(const QMultiHash &other)
2381 { this->unite(other); return *this; }
2382 inline QMultiHash operator+(const QMultiHash &other) const
2383 { QMultiHash result = *this; result += other; return result; }
2384
2385 bool contains(const Key &key, const T &value) const noexcept
2386 {
2387 return containsImpl(key, value);
2388 }
2389 private:
2390 template <typename K> bool containsImpl(const K &key, const T &value) const noexcept
2391 {
2392 if (isEmpty())
2393 return false;
2394 auto n = d->findNode(key);
2395 if (n == nullptr)
2396 return false;
2397 return n->value->contains(value);
2398 }
2399
2400 public:
2401 qsizetype remove(const Key &key, const T &value)
2402 {
2403 return removeImpl(key, value);
2404 }
2405 private:
2406 template <typename K> qsizetype removeImpl(const K &key, const T &value)
2407 {
2408 if (isEmpty())
2409 return 0;
2410 auto it = d->findBucket(key);
2411 size_t bucket = it.toBucketIndex(d);
2412 detach();
2413 it = typename Data::Bucket(d, bucket);
2414
2415 if (it.isUnused())
2416 return 0;
2417 qsizetype n = 0;
2418 Chain **e = &it.node()->value;
2419 while (*e) {
2420 Chain *entry = *e;
2421 if (entry->value == value) {
2422 *e = entry->next;
2423 delete entry;
2424 ++n;
2425 } else {
2426 e = &entry->next;
2427 }
2428 }
2429 if (!it.node()->value)
2430 d->erase(it);
2431 m_size -= n;
2432 Q_ASSERT(m_size >= 0);
2433 return n;
2434 }
2435
2436 public:
2437 qsizetype count(const Key &key) const noexcept
2438 {
2439 return countImpl(key);
2440 }
2441 private:
2442 template <typename K> qsizetype countImpl(const K &key) const noexcept
2443 {
2444 if (!d)
2445 return 0;
2446 auto it = d->findBucket(key);
2447 if (it.isUnused())
2448 return 0;
2449 qsizetype n = 0;
2450 Chain *e = it.node()->value;
2451 while (e) {
2452 ++n;
2453 e = e->next;
2454 }
2455
2456 return n;
2457 }
2458
2459 public:
2460 qsizetype count(const Key &key, const T &value) const noexcept
2461 {
2462 return countImpl(key, value);
2463 }
2464 private:
2465 template <typename K> qsizetype countImpl(const K &key, const T &value) const noexcept
2466 {
2467 if (!d)
2468 return 0;
2469 auto it = d->findBucket(key);
2470 if (it.isUnused())
2471 return 0;
2472 qsizetype n = 0;
2473 Chain *e = it.node()->value;
2474 while (e) {
2475 if (e->value == value)
2476 ++n;
2477 e = e->next;
2478 }
2479
2480 return n;
2481 }
2482
2483 template <typename K> iterator findImpl(const K &key, const T &value)
2484 {
2485 if (isEmpty())
2486 return end();
2487 const auto copy = isDetached() ? QMultiHash() : *this;
2488 detach();
2489 auto it = constFind(key, value);
2490 return iterator(it.i, it.e);
2491 }
2492 template <typename K> const_iterator constFindImpl(const K &key, const T &value) const noexcept
2493 {
2494 const_iterator i(constFind(key));
2495 const_iterator end(constEnd());
2496 while (i != end && i.key() == key) {
2497 if (i.value() == value)
2498 return i;
2499 ++i;
2500 }
2501 return end;
2502 }
2503
2504 public:
2505 iterator find(const Key &key, const T &value)
2506 {
2507 return findImpl(key, value);
2508 }
2509
2510 const_iterator constFind(const Key &key, const T &value) const noexcept
2511 {
2512 return constFindImpl(key, value);
2513 }
2514 const_iterator find(const Key &key, const T &value) const noexcept
2515 {
2516 return constFind(key, value);
2517 }
2518
2519 QMultiHash &unite(const QMultiHash &other)
2520 {
2521 if (isEmpty()) {
2522 *this = other;
2523 } else if (other.isEmpty()) {
2524 ;
2525 } else {
2526 QMultiHash copy(other);
2527 detach();
2528 for (auto cit = copy.cbegin(); cit != copy.cend(); ++cit)
2529 insert(cit.key(), *cit);
2530 }
2531 return *this;
2532 }
2533
2534 QMultiHash &unite(const QHash<Key, T> &other)
2535 {
2536 for (auto cit = other.cbegin(); cit != other.cend(); ++cit)
2537 insert(cit.key(), *cit);
2538 return *this;
2539 }
2540
2541 QMultiHash &unite(QHash<Key, T> &&other)
2542 {
2543 if (!other.isDetached()) {
2544 unite(other);
2545 return *this;
2546 }
2547 auto it = other.d->begin();
2548 for (const auto end = other.d->end(); it != end; ++it)
2549 emplace(std::move(it.node()->key), it.node()->takeValue());
2550 other.clear();
2551 return *this;
2552 }
2553
2554 std::pair<iterator, iterator> equal_range(const Key &key)
2555 {
2556 return equal_range_impl(key);
2557 }
2558 private:
2559 template <typename K> std::pair<iterator, iterator> equal_range_impl(const K &key)
2560 {
2561 const auto copy = isDetached() ? QMultiHash() : *this;
2562 detach();
2563 auto pair = std::as_const(*this).equal_range(key);
2564 return {iterator(pair.first.i), iterator(pair.second.i)};
2565 }
2566
2567 public:
2568 std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
2569 {
2570 return equal_range_impl(key);
2571 }
2572 private:
2573 template <typename K> std::pair<const_iterator, const_iterator> equal_range_impl(const K &key) const noexcept
2574 {
2575 if (!d)
2576 return {end(), end()};
2577
2578 auto bucket = d->findBucket(key);
2579 if (bucket.isUnused())
2580 return {end(), end()};
2581 auto it = bucket.toIterator(d);
2582 auto end = it;
2583 ++end;
2584 return {const_iterator(it), const_iterator(end)};
2585 }
2586
2587 void detach_helper()
2588 {
2589 if (!d) {
2590 d = new Data;
2591 return;
2592 }
2593 Data *dd = new Data(*d);
2594 if (!d->ref.deref())
2595 delete d;
2596 d = dd;
2597 }
2598
2599 template<typename... Args>
2600 iterator emplace_helper(Key &&key, Args &&...args)
2601 {
2602 auto result = d->findOrInsert(key);
2603 if (!result.initialized)
2604 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2605 else
2606 result.it.node()->insertMulti(std::forward<Args>(args)...);
2607 ++m_size;
2608 return iterator(result.it);
2609 }
2610
2611 template<typename... Args>
2612 iterator emplaceReplace_helper(Key &&key, Args &&...args)
2613 {
2614 auto result = d->findOrInsert(key);
2615 if (!result.initialized) {
2616 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2617 ++m_size;
2618 } else {
2619 result.it.node()->emplaceValue(std::forward<Args>(args)...);
2620 }
2621 return iterator(result.it);
2622 }
2623
2624 template <typename K>
2625 using if_heterogeneously_searchable = QHashPrivate::if_heterogeneously_searchable_with<Key, K>;
2626
2627 template <typename K>
2628 using if_key_constructible_from = std::enable_if_t<std::is_constructible_v<Key, K>, bool>;
2629
2630 public:
2631 template <typename K, if_heterogeneously_searchable<K> = true>
2632 qsizetype remove(const K &key)
2633 {
2634 return removeImpl(key);
2635 }
2636 template <typename K, if_heterogeneously_searchable<K> = true>
2637 T take(const K &key)
2638 {
2639 return takeImpl(key);
2640 }
2641 template <typename K, if_heterogeneously_searchable<K> = true>
2642 bool contains(const K &key) const noexcept
2643 {
2644 if (!d)
2645 return false;
2646 return d->findNode(key) != nullptr;
2647 }
2648 template <typename K, if_heterogeneously_searchable<K> = true>
2649 T value(const K &key) const noexcept
2650 {
2651 if (auto *v = valueImpl(key))
2652 return *v;
2653 else
2654 return T();
2655 }
2656 template <typename K, if_heterogeneously_searchable<K> = true>
2657 T value(const K &key, const T &defaultValue) const noexcept
2658 {
2659 if (auto *v = valueImpl(key))
2660 return *v;
2661 else
2662 return defaultValue;
2663 }
2664 template <typename K, if_heterogeneously_searchable<K> = true, if_key_constructible_from<K> = true>
2665 T &operator[](const K &key)
2666 {
2667 return operatorIndexImpl(key);
2668 }
2669 template <typename K, if_heterogeneously_searchable<K> = true>
2670 const T operator[](const K &key) const noexcept
2671 {
2672 return value(key);
2673 }
2674 template <typename K, if_heterogeneously_searchable<K> = true>
2675 QList<T> values(const K &key)
2676 {
2677 return valuesImpl(key);
2678 }
2679 template <typename K, if_heterogeneously_searchable<K> = true>
2680 iterator find(const K &key)
2681 {
2682 return findImpl(key);
2683 }
2684 template <typename K, if_heterogeneously_searchable<K> = true>
2685 const_iterator constFind(const K &key) const noexcept
2686 {
2687 return constFindImpl(key);
2688 }
2689 template <typename K, if_heterogeneously_searchable<K> = true>
2690 const_iterator find(const K &key) const noexcept
2691 {
2692 return constFindImpl(key);
2693 }
2694 template <typename K, if_heterogeneously_searchable<K> = true>
2695 bool contains(const K &key, const T &value) const noexcept
2696 {
2697 return containsImpl(key, value);
2698 }
2699 template <typename K, if_heterogeneously_searchable<K> = true>
2700 qsizetype remove(const K &key, const T &value)
2701 {
2702 return removeImpl(key, value);
2703 }
2704 template <typename K, if_heterogeneously_searchable<K> = true>
2705 qsizetype count(const K &key) const noexcept
2706 {
2707 return countImpl(key);
2708 }
2709 template <typename K, if_heterogeneously_searchable<K> = true>
2710 qsizetype count(const K &key, const T &value) const noexcept
2711 {
2712 return countImpl(key, value);
2713 }
2714 template <typename K, if_heterogeneously_searchable<K> = true>
2715 iterator find(const K &key, const T &value)
2716 {
2717 return findImpl(key, value);
2718 }
2719 template <typename K, if_heterogeneously_searchable<K> = true>
2720 const_iterator constFind(const K &key, const T &value) const noexcept
2721 {
2722 return constFindImpl(key, value);
2723 }
2724 template <typename K, if_heterogeneously_searchable<K> = true>
2725 const_iterator find(const K &key, const T &value) const noexcept
2726 {
2727 return constFind(key, value);
2728 }
2729 template <typename K, if_heterogeneously_searchable<K> = true>
2730 std::pair<iterator, iterator>
2731 equal_range(const K &key)
2732 {
2733 return equal_range_impl(key);
2734 }
2735 template <typename K, if_heterogeneously_searchable<K> = true>
2736 std::pair<const_iterator, const_iterator>
2737 equal_range(const K &key) const noexcept
2738 {
2739 return equal_range_impl(key);
2740 }
2741 };
2742
2743 Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2744 Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2745 Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2746 Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2747
2748 template <class Key, class T>
2749 size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
2750 noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
2751 {
2752 const QtPrivate::QHashCombine combine(seed);
2753 size_t hash = 0;
2754 for (auto it = key.begin(), end = key.end(); it != end; ++it) {
2755 size_t h = combine(seed, it.key());
2756
2757 hash += combine(h, it.value());
2758 }
2759 return hash;
2760 }
2761
2762 template <class Key, class T>
2763 inline size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
2764 noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
2765 {
2766 const QtPrivate::QHashCombine combine(seed);
2767 size_t hash = 0;
2768 for (auto it = key.begin(), end = key.end(); it != end; ++it) {
2769 size_t h = combine(seed, it.key());
2770
2771 hash += combine(h, it.value());
2772 }
2773 return hash;
2774 }
2775
2776 template <typename Key, typename T, typename Predicate>
2777 qsizetype erase_if(QHash<Key, T> &hash, Predicate pred)
2778 {
2779 return QtPrivate::associative_erase_if(hash, pred);
2780 }
2781
2782 template <typename Key, typename T, typename Predicate>
2783 qsizetype erase_if(QMultiHash<Key, T> &hash, Predicate pred)
2784 {
2785 return QtPrivate::associative_erase_if(hash, pred);
2786 }
2787
2788 QT_END_NAMESPACE
2789
2790 #endif