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