Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:25

0001 // Copyright (C) 2020 The Qt Company Ltd.
0002 // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
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 
0015 #include <initializer_list>
0016 #include <functional> // for std::hash
0017 
0018 class tst_QHash; // for befriending
0019 
0020 QT_BEGIN_NAMESPACE
0021 
0022 struct QHashDummyValue
0023 {
0024     bool operator==(const QHashDummyValue &) const noexcept { return true; }
0025 };
0026 
0027 namespace QHashPrivate {
0028 
0029 template <typename T, typename = void>
0030 constexpr inline bool HasQHashOverload = false;
0031 
0032 template <typename T>
0033 constexpr inline bool HasQHashOverload<T, std::enable_if_t<
0034     std::is_convertible_v<decltype(qHash(std::declval<const T &>(), std::declval<size_t>())), size_t>
0035 >> = true;
0036 
0037 template <typename T, typename = void>
0038 constexpr inline bool HasStdHashSpecializationWithSeed = false;
0039 
0040 template <typename T>
0041 constexpr inline bool HasStdHashSpecializationWithSeed<T, std::enable_if_t<
0042     std::is_convertible_v<decltype(std::hash<T>()(std::declval<const T &>(), std::declval<size_t>())), size_t>
0043 >> = true;
0044 
0045 template <typename T, typename = void>
0046 constexpr inline bool HasStdHashSpecializationWithoutSeed = false;
0047 
0048 template <typename T>
0049 constexpr inline bool HasStdHashSpecializationWithoutSeed<T, std::enable_if_t<
0050     std::is_convertible_v<decltype(std::hash<T>()(std::declval<const T &>())), size_t>
0051 >> = true;
0052 
0053 template <typename T>
0054 size_t calculateHash(const T &t, size_t seed = 0)
0055 {
0056     if constexpr (HasQHashOverload<T>) {
0057         return qHash(t, seed);
0058     } else if constexpr (HasStdHashSpecializationWithSeed<T>) {
0059         return std::hash<T>()(t, seed);
0060     } else if constexpr (HasStdHashSpecializationWithoutSeed<T>) {
0061         Q_UNUSED(seed);
0062         return std::hash<T>()(t);
0063     } else {
0064         static_assert(sizeof(T) == 0, "The key type must have a qHash overload or a std::hash specialization");
0065         return 0;
0066     }
0067 }
0068 
0069 template <typename Key, typename T>
0070 struct Node
0071 {
0072     using KeyType = Key;
0073     using ValueType = T;
0074 
0075     Key key;
0076     T value;
0077     template<typename ...Args>
0078     static void createInPlace(Node *n, Key &&k, Args &&... args)
0079     { new (n) Node{ std::move(k), T(std::forward<Args>(args)...) }; }
0080     template<typename ...Args>
0081     static void createInPlace(Node *n, const Key &k, Args &&... args)
0082     { new (n) Node{ Key(k), T(std::forward<Args>(args)...) }; }
0083     template<typename ...Args>
0084     void emplaceValue(Args &&... args)
0085     {
0086         value = T(std::forward<Args>(args)...);
0087     }
0088     T &&takeValue() noexcept(std::is_nothrow_move_assignable_v<T>)
0089     {
0090         return std::move(value);
0091     }
0092     bool valuesEqual(const Node *other) const { return value == other->value; }
0093 };
0094 
0095 template <typename Key>
0096 struct Node<Key, QHashDummyValue> {
0097     using KeyType = Key;
0098     using ValueType = QHashDummyValue;
0099 
0100     Key key;
0101     template<typename ...Args>
0102     static void createInPlace(Node *n, Key &&k, Args &&...)
0103     { new (n) Node{ std::move(k) }; }
0104     template<typename ...Args>
0105     static void createInPlace(Node *n, const Key &k, Args &&...)
0106     { new (n) Node{ k }; }
0107     template<typename ...Args>
0108     void emplaceValue(Args &&...)
0109     {
0110     }
0111     ValueType takeValue() { return QHashDummyValue(); }
0112     bool valuesEqual(const Node *) const { return true; }
0113 };
0114 
0115 template <typename T>
0116 struct MultiNodeChain
0117 {
0118     T value;
0119     MultiNodeChain *next = nullptr;
0120     ~MultiNodeChain()
0121     {
0122     }
0123     qsizetype free() noexcept(std::is_nothrow_destructible_v<T>)
0124     {
0125         qsizetype nEntries = 0;
0126         MultiNodeChain *e = this;
0127         while (e) {
0128             MultiNodeChain *n = e->next;
0129             ++nEntries;
0130             delete e;
0131             e = n;
0132         }
0133         return  nEntries;
0134     }
0135     bool contains(const T &val) const noexcept
0136     {
0137         const MultiNodeChain *e = this;
0138         while (e) {
0139             if (e->value == val)
0140                 return true;
0141             e = e->next;
0142         }
0143         return false;
0144     }
0145 };
0146 
0147 template <typename Key, typename T>
0148 struct MultiNode
0149 {
0150     using KeyType = Key;
0151     using ValueType = T;
0152     using Chain = MultiNodeChain<T>;
0153 
0154     Key key;
0155     Chain *value;
0156 
0157     template<typename ...Args>
0158     static void createInPlace(MultiNode *n, Key &&k, Args &&... args)
0159     { new (n) MultiNode(std::move(k), new Chain{ T(std::forward<Args>(args)...), nullptr }); }
0160     template<typename ...Args>
0161     static void createInPlace(MultiNode *n, const Key &k, Args &&... args)
0162     { new (n) MultiNode(k, new Chain{ T(std::forward<Args>(args)...), nullptr }); }
0163 
0164     MultiNode(const Key &k, Chain *c)
0165         : key(k),
0166           value(c)
0167     {}
0168     MultiNode(Key &&k, Chain *c) noexcept(std::is_nothrow_move_assignable_v<Key>)
0169         : key(std::move(k)),
0170           value(c)
0171     {}
0172 
0173     MultiNode(MultiNode &&other)
0174         : key(other.key),
0175           value(std::exchange(other.value, nullptr))
0176     {
0177     }
0178 
0179     MultiNode(const MultiNode &other)
0180         : key(other.key)
0181     {
0182         Chain *c = other.value;
0183         Chain **e = &value;
0184         while (c) {
0185             Chain *chain = new Chain{ c->value, nullptr };
0186             *e = chain;
0187             e = &chain->next;
0188             c = c->next;
0189         }
0190     }
0191     ~MultiNode()
0192     {
0193         if (value)
0194             value->free();
0195     }
0196     static qsizetype freeChain(MultiNode *n) noexcept(std::is_nothrow_destructible_v<T>)
0197     {
0198         qsizetype size = n->value->free();
0199         n->value = nullptr;
0200         return size;
0201     }
0202     template<typename ...Args>
0203     void insertMulti(Args &&... args)
0204     {
0205         Chain *e = new Chain{ T(std::forward<Args>(args)...), nullptr };
0206         e->next = std::exchange(value, e);
0207     }
0208     template<typename ...Args>
0209     void emplaceValue(Args &&... args)
0210     {
0211         value->value = T(std::forward<Args>(args)...);
0212     }
0213 };
0214 
0215 template<typename  Node>
0216 constexpr bool isRelocatable()
0217 {
0218     return QTypeInfo<typename Node::KeyType>::isRelocatable && QTypeInfo<typename Node::ValueType>::isRelocatable;
0219 }
0220 
0221 struct SpanConstants {
0222     static constexpr size_t SpanShift = 7;
0223     static constexpr size_t NEntries = (1 << SpanShift);
0224     static constexpr size_t LocalBucketMask = (NEntries - 1);
0225     static constexpr size_t UnusedEntry = 0xff;
0226 
0227     static_assert ((NEntries & LocalBucketMask) == 0, "NEntries must be a power of two.");
0228 };
0229 
0230 // Regular hash tables consist of a list of buckets that can store Nodes. But simply allocating one large array of buckets
0231 // would waste a lot of memory. To avoid this, we split the vector of buckets up into a vector of Spans. Each Span represents
0232 // NEntries buckets. To quickly find the correct Span that holds a bucket, NEntries must be a power of two.
0233 //
0234 // Inside each Span, there is an offset array that represents the actual buckets. offsets contains either an index into the
0235 // actual storage space for the Nodes (the 'entries' member) or 0xff (UnusedEntry) to flag that the bucket is empty.
0236 // As we have only 128 entries per Span, the offset array can be represented using an unsigned char. This trick makes the hash
0237 // table have a very small memory overhead compared to many other implementations.
0238 template<typename Node>
0239 struct Span {
0240     // Entry is a slot available for storing a Node. The Span holds a pointer to
0241     // an array of Entries. Upon construction of the array, those entries are
0242     // unused, and nextFree() is being used to set up a singly linked list
0243     // of free entries.
0244     // When a node gets inserted, the first free entry is being picked, removed
0245     // from the singly linked list and the Node gets constructed in place.
0246     struct Entry {
0247         struct { alignas(Node) unsigned char data[sizeof(Node)]; } storage;
0248 
0249         unsigned char &nextFree() { return *reinterpret_cast<unsigned char *>(&storage); }
0250         Node &node() { return *reinterpret_cast<Node *>(&storage); }
0251     };
0252 
0253     unsigned char offsets[SpanConstants::NEntries];
0254     Entry *entries = nullptr;
0255     unsigned char allocated = 0;
0256     unsigned char nextFree = 0;
0257     Span() noexcept
0258     {
0259         memset(offsets, SpanConstants::UnusedEntry, sizeof(offsets));
0260     }
0261     ~Span()
0262     {
0263         freeData();
0264     }
0265     void freeData() noexcept(std::is_nothrow_destructible<Node>::value)
0266     {
0267         if (entries) {
0268             if constexpr (!std::is_trivially_destructible<Node>::value) {
0269                 for (auto o : offsets) {
0270                     if (o != SpanConstants::UnusedEntry)
0271                         entries[o].node().~Node();
0272                 }
0273             }
0274             delete[] entries;
0275             entries = nullptr;
0276         }
0277     }
0278     Node *insert(size_t i)
0279     {
0280         Q_ASSERT(i < SpanConstants::NEntries);
0281         Q_ASSERT(offsets[i] == SpanConstants::UnusedEntry);
0282         if (nextFree == allocated)
0283             addStorage();
0284         unsigned char entry = nextFree;
0285         Q_ASSERT(entry < allocated);
0286         nextFree = entries[entry].nextFree();
0287         offsets[i] = entry;
0288         return &entries[entry].node();
0289     }
0290     void erase(size_t bucket) noexcept(std::is_nothrow_destructible<Node>::value)
0291     {
0292         Q_ASSERT(bucket < SpanConstants::NEntries);
0293         Q_ASSERT(offsets[bucket] != SpanConstants::UnusedEntry);
0294 
0295         unsigned char entry = offsets[bucket];
0296         offsets[bucket] = SpanConstants::UnusedEntry;
0297 
0298         entries[entry].node().~Node();
0299         entries[entry].nextFree() = nextFree;
0300         nextFree = entry;
0301     }
0302     size_t offset(size_t i) const noexcept
0303     {
0304         return offsets[i];
0305     }
0306     bool hasNode(size_t i) const noexcept
0307     {
0308         return (offsets[i] != SpanConstants::UnusedEntry);
0309     }
0310     Node &at(size_t i) noexcept
0311     {
0312         Q_ASSERT(i < SpanConstants::NEntries);
0313         Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
0314 
0315         return entries[offsets[i]].node();
0316     }
0317     const Node &at(size_t i) const noexcept
0318     {
0319         Q_ASSERT(i < SpanConstants::NEntries);
0320         Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
0321 
0322         return entries[offsets[i]].node();
0323     }
0324     Node &atOffset(size_t o) noexcept
0325     {
0326         Q_ASSERT(o < allocated);
0327 
0328         return entries[o].node();
0329     }
0330     const Node &atOffset(size_t o) const noexcept
0331     {
0332         Q_ASSERT(o < allocated);
0333 
0334         return entries[o].node();
0335     }
0336     void moveLocal(size_t from, size_t to) noexcept
0337     {
0338         Q_ASSERT(offsets[from] != SpanConstants::UnusedEntry);
0339         Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
0340         offsets[to] = offsets[from];
0341         offsets[from] = SpanConstants::UnusedEntry;
0342     }
0343     void moveFromSpan(Span &fromSpan, size_t fromIndex, size_t to) noexcept(std::is_nothrow_move_constructible_v<Node>)
0344     {
0345         Q_ASSERT(to < SpanConstants::NEntries);
0346         Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
0347         Q_ASSERT(fromIndex < SpanConstants::NEntries);
0348         Q_ASSERT(fromSpan.offsets[fromIndex] != SpanConstants::UnusedEntry);
0349         if (nextFree == allocated)
0350             addStorage();
0351         Q_ASSERT(nextFree < allocated);
0352         offsets[to] = nextFree;
0353         Entry &toEntry = entries[nextFree];
0354         nextFree = toEntry.nextFree();
0355 
0356         size_t fromOffset = fromSpan.offsets[fromIndex];
0357         fromSpan.offsets[fromIndex] = SpanConstants::UnusedEntry;
0358         Entry &fromEntry = fromSpan.entries[fromOffset];
0359 
0360         if constexpr (isRelocatable<Node>()) {
0361             memcpy(&toEntry, &fromEntry, sizeof(Entry));
0362         } else {
0363             new (&toEntry.node()) Node(std::move(fromEntry.node()));
0364             fromEntry.node().~Node();
0365         }
0366         fromEntry.nextFree() = fromSpan.nextFree;
0367         fromSpan.nextFree = static_cast<unsigned char>(fromOffset);
0368     }
0369 
0370     void addStorage()
0371     {
0372         Q_ASSERT(allocated < SpanConstants::NEntries);
0373         Q_ASSERT(nextFree == allocated);
0374         // the hash table should always be between 25 and 50% full
0375         // this implies that we on average have between 32 and 64 entries
0376         // in here. More exactly, we have a binominal distribution of the amount of
0377         // occupied entries.
0378         // For a 25% filled table, the average is 32 entries, with a 95% chance that we have between
0379         // 23 and 41 entries.
0380         // For a 50% filled table, the average is 64 entries, with a 95% chance that we have between
0381         // 53 and 75 entries.
0382         // Since we only resize the table once it's 50% filled and we want to avoid copies of
0383         // data where possible, we initially allocate 48 entries, then resize to 80 entries, after that
0384         // resize by increments of 16. That way, we usually only get one resize of the table
0385         // while filling it.
0386         size_t alloc;
0387         static_assert(SpanConstants::NEntries % 8 == 0);
0388         if (!allocated)
0389             alloc = SpanConstants::NEntries / 8 * 3;
0390         else if (allocated == SpanConstants::NEntries / 8 * 3)
0391             alloc = SpanConstants::NEntries / 8 * 5;
0392         else
0393             alloc = allocated + SpanConstants::NEntries/8;
0394         Entry *newEntries = new Entry[alloc];
0395         // we only add storage if the previous storage was fully filled, so
0396         // simply copy the old data over
0397         if constexpr (isRelocatable<Node>()) {
0398             if (allocated)
0399                 memcpy(newEntries, entries, allocated * sizeof(Entry));
0400         } else {
0401             for (size_t i = 0; i < allocated; ++i) {
0402                 new (&newEntries[i].node()) Node(std::move(entries[i].node()));
0403                 entries[i].node().~Node();
0404             }
0405         }
0406         for (size_t i = allocated; i < alloc; ++i) {
0407             newEntries[i].nextFree() = uchar(i + 1);
0408         }
0409         delete[] entries;
0410         entries = newEntries;
0411         allocated = uchar(alloc);
0412     }
0413 };
0414 
0415 // QHash uses a power of two growth policy.
0416 namespace GrowthPolicy {
0417 inline constexpr size_t bucketsForCapacity(size_t requestedCapacity) noexcept
0418 {
0419     constexpr int SizeDigits = std::numeric_limits<size_t>::digits;
0420 
0421     // We want to use at minimum a full span (128 entries), so we hardcode it for any requested
0422     // capacity <= 64. Any capacity above that gets rounded to a later power of two.
0423     if (requestedCapacity <= 64)
0424         return SpanConstants::NEntries;
0425 
0426     // Same as
0427     //    qNextPowerOfTwo(2 * requestedCapacity);
0428     //
0429     // but ensuring neither our multiplication nor the function overflow.
0430     // Additionally, the maximum memory allocation is 2^31-1 or 2^63-1 bytes
0431     // (limited by qsizetype and ptrdiff_t).
0432     int count = qCountLeadingZeroBits(requestedCapacity);
0433     if (count < 2)
0434         return (std::numeric_limits<size_t>::max)();    // will cause std::bad_alloc
0435     return size_t(1) << (SizeDigits - count + 1);
0436 }
0437 inline constexpr size_t bucketForHash(size_t nBuckets, size_t hash) noexcept
0438 {
0439     return hash & (nBuckets - 1);
0440 }
0441 } // namespace GrowthPolicy
0442 
0443 template <typename Node>
0444 struct iterator;
0445 
0446 template <typename Node>
0447 struct Data
0448 {
0449     using Key = typename Node::KeyType;
0450     using T = typename Node::ValueType;
0451     using Span = QHashPrivate::Span<Node>;
0452     using iterator = QHashPrivate::iterator<Node>;
0453 
0454     QtPrivate::RefCount ref = {{1}};
0455     size_t size = 0;
0456     size_t numBuckets = 0;
0457     size_t seed = 0;
0458     Span *spans = nullptr;
0459 
0460     static constexpr size_t maxNumBuckets() noexcept
0461     {
0462         return (std::numeric_limits<ptrdiff_t>::max)() / sizeof(Span);
0463     }
0464 
0465     struct Bucket {
0466         Span *span;
0467         size_t index;
0468 
0469         Bucket(Span *s, size_t i) noexcept
0470             : span(s), index(i)
0471         {}
0472         Bucket(const Data *d, size_t bucket) noexcept
0473             : span(d->spans + (bucket >> SpanConstants::SpanShift)),
0474             index(bucket & SpanConstants::LocalBucketMask)
0475         {}
0476         Bucket(iterator it) noexcept
0477             : Bucket(it.d, it.bucket)
0478         {}
0479 
0480         size_t toBucketIndex(const Data *d) const noexcept
0481         {
0482             return ((span - d->spans) << SpanConstants::SpanShift) | index;
0483         }
0484         iterator toIterator(const Data *d) const noexcept { return iterator{d, toBucketIndex(d)}; }
0485         void advanceWrapped(const Data *d) noexcept
0486         {
0487             advance_impl(d, d->spans);
0488         }
0489         void advance(const Data *d) noexcept
0490         {
0491             advance_impl(d, nullptr);
0492         }
0493         bool isUnused() const noexcept
0494         {
0495             return !span->hasNode(index);
0496         }
0497         size_t offset() const noexcept
0498         {
0499             return span->offset(index);
0500         }
0501         Node &nodeAtOffset(size_t offset)
0502         {
0503             return span->atOffset(offset);
0504         }
0505         Node *node()
0506         {
0507             return &span->at(index);
0508         }
0509         Node *insert() const
0510         {
0511             return span->insert(index);
0512         }
0513 
0514     private:
0515         friend bool operator==(Bucket lhs, Bucket rhs) noexcept
0516         {
0517             return lhs.span == rhs.span && lhs.index == rhs.index;
0518         }
0519         friend bool operator!=(Bucket lhs, Bucket rhs) noexcept { return !(lhs == rhs); }
0520 
0521         void advance_impl(const Data *d, Span *whenAtEnd) noexcept
0522         {
0523             Q_ASSERT(span);
0524             ++index;
0525             if (Q_UNLIKELY(index == SpanConstants::NEntries)) {
0526                 index = 0;
0527                 ++span;
0528                 if (span - d->spans == ptrdiff_t(d->numBuckets >> SpanConstants::SpanShift))
0529                     span = whenAtEnd;
0530             }
0531         }
0532     };
0533 
0534     static auto allocateSpans(size_t numBuckets)
0535     {
0536         struct R {
0537             Span *spans;
0538             size_t nSpans;
0539         };
0540 
0541         constexpr qptrdiff MaxSpanCount = (std::numeric_limits<qptrdiff>::max)() / sizeof(Span);
0542         constexpr size_t MaxBucketCount = MaxSpanCount << SpanConstants::SpanShift;
0543 
0544         if (numBuckets > MaxBucketCount) {
0545             Q_CHECK_PTR(false);
0546             Q_UNREACHABLE();    // no exceptions and no assertions -> no error reporting
0547         }
0548 
0549         size_t nSpans = numBuckets >> SpanConstants::SpanShift;
0550         return R{ new Span[nSpans], nSpans };
0551     }
0552 
0553     Data(size_t reserve = 0)
0554     {
0555         numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
0556         spans = allocateSpans(numBuckets).spans;
0557         seed = QHashSeed::globalSeed();
0558     }
0559 
0560     void reallocationHelper(const Data &other, size_t nSpans, bool resized)
0561     {
0562         for (size_t s = 0; s < nSpans; ++s) {
0563             const Span &span = other.spans[s];
0564             for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
0565                 if (!span.hasNode(index))
0566                     continue;
0567                 const Node &n = span.at(index);
0568                 auto it = resized ? findBucket(n.key) : Bucket { spans + s, index };
0569                 Q_ASSERT(it.isUnused());
0570                 Node *newNode = it.insert();
0571                 new (newNode) Node(n);
0572             }
0573         }
0574     }
0575 
0576     Data(const Data &other) : size(other.size), numBuckets(other.numBuckets), seed(other.seed)
0577     {
0578         auto r = allocateSpans(numBuckets);
0579         spans = r.spans;
0580         reallocationHelper(other, r.nSpans, false);
0581     }
0582     Data(const Data &other, size_t reserved) : size(other.size), seed(other.seed)
0583     {
0584         numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
0585         spans = allocateSpans(numBuckets).spans;
0586         size_t otherNSpans = other.numBuckets >> SpanConstants::SpanShift;
0587         reallocationHelper(other, otherNSpans, true);
0588     }
0589 
0590     static Data *detached(Data *d)
0591     {
0592         if (!d)
0593             return new Data;
0594         Data *dd = new Data(*d);
0595         if (!d->ref.deref())
0596             delete d;
0597         return dd;
0598     }
0599     static Data *detached(Data *d, size_t size)
0600     {
0601         if (!d)
0602             return new Data(size);
0603         Data *dd = new Data(*d, size);
0604         if (!d->ref.deref())
0605             delete d;
0606         return dd;
0607     }
0608 
0609     void clear()
0610     {
0611         delete[] spans;
0612         spans = nullptr;
0613         size = 0;
0614         numBuckets = 0;
0615     }
0616 
0617     iterator detachedIterator(iterator other) const noexcept
0618     {
0619         return iterator{this, other.bucket};
0620     }
0621 
0622     iterator begin() const noexcept
0623     {
0624         iterator it{ this, 0 };
0625         if (it.isUnused())
0626             ++it;
0627         return it;
0628     }
0629 
0630     constexpr iterator end() const noexcept
0631     {
0632         return iterator();
0633     }
0634 
0635     void rehash(size_t sizeHint = 0)
0636     {
0637         if (sizeHint == 0)
0638             sizeHint = size;
0639         size_t newBucketCount = GrowthPolicy::bucketsForCapacity(sizeHint);
0640 
0641         Span *oldSpans = spans;
0642         size_t oldBucketCount = numBuckets;
0643         spans = allocateSpans(newBucketCount).spans;
0644         numBuckets = newBucketCount;
0645         size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
0646 
0647         for (size_t s = 0; s < oldNSpans; ++s) {
0648             Span &span = oldSpans[s];
0649             for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
0650                 if (!span.hasNode(index))
0651                     continue;
0652                 Node &n = span.at(index);
0653                 auto it = findBucket(n.key);
0654                 Q_ASSERT(it.isUnused());
0655                 Node *newNode = it.insert();
0656                 new (newNode) Node(std::move(n));
0657             }
0658             span.freeData();
0659         }
0660         delete[] oldSpans;
0661     }
0662 
0663     size_t nextBucket(size_t bucket) const noexcept
0664     {
0665         ++bucket;
0666         if (bucket == numBuckets)
0667             bucket = 0;
0668         return bucket;
0669     }
0670 
0671     float loadFactor() const noexcept
0672     {
0673         return float(size)/numBuckets;
0674     }
0675     bool shouldGrow() const noexcept
0676     {
0677         return size >= (numBuckets >> 1);
0678     }
0679 
0680     Bucket findBucket(const Key &key) const noexcept
0681     {
0682         Q_ASSERT(numBuckets > 0);
0683         size_t hash = QHashPrivate::calculateHash(key, seed);
0684         Bucket bucket(this, GrowthPolicy::bucketForHash(numBuckets, hash));
0685         // loop over the buckets until we find the entry we search for
0686         // or an empty slot, in which case we know the entry doesn't exist
0687         while (true) {
0688             size_t offset = bucket.offset();
0689             if (offset == SpanConstants::UnusedEntry) {
0690                 return bucket;
0691             } else {
0692                 Node &n = bucket.nodeAtOffset(offset);
0693                 if (qHashEquals(n.key, key))
0694                     return bucket;
0695             }
0696             bucket.advanceWrapped(this);
0697         }
0698     }
0699 
0700     Node *findNode(const Key &key) const noexcept
0701     {
0702         auto bucket = findBucket(key);
0703         if (bucket.isUnused())
0704             return nullptr;
0705         return bucket.node();
0706     }
0707 
0708     struct InsertionResult
0709     {
0710         iterator it;
0711         bool initialized;
0712     };
0713 
0714     InsertionResult findOrInsert(const Key &key) noexcept
0715     {
0716         Bucket it(static_cast<Span *>(nullptr), 0);
0717         if (numBuckets > 0) {
0718             it = findBucket(key);
0719             if (!it.isUnused())
0720                 return { it.toIterator(this), true };
0721         }
0722         if (shouldGrow()) {
0723             rehash(size + 1);
0724             it = findBucket(key); // need to get a new iterator after rehashing
0725         }
0726         Q_ASSERT(it.span != nullptr);
0727         Q_ASSERT(it.isUnused());
0728         it.insert();
0729         ++size;
0730         return { it.toIterator(this), false };
0731     }
0732 
0733     void erase(Bucket bucket) noexcept(std::is_nothrow_destructible<Node>::value)
0734     {
0735         Q_ASSERT(bucket.span->hasNode(bucket.index));
0736         bucket.span->erase(bucket.index);
0737         --size;
0738 
0739         // re-insert the following entries to avoid holes
0740         Bucket next = bucket;
0741         while (true) {
0742             next.advanceWrapped(this);
0743             size_t offset = next.offset();
0744             if (offset == SpanConstants::UnusedEntry)
0745                 return;
0746             size_t hash = QHashPrivate::calculateHash(next.nodeAtOffset(offset).key, seed);
0747             Bucket newBucket(this, GrowthPolicy::bucketForHash(numBuckets, hash));
0748             while (true) {
0749                 if (newBucket == next) {
0750                     // nothing to do, item is at the right plae
0751                     break;
0752                 } else if (newBucket == bucket) {
0753                     // move into the hole we created earlier
0754                     if (next.span == bucket.span) {
0755                         bucket.span->moveLocal(next.index, bucket.index);
0756                     } else {
0757                         // move between spans, more expensive
0758                         bucket.span->moveFromSpan(*next.span, next.index, bucket.index);
0759                     }
0760                     bucket = next;
0761                     break;
0762                 }
0763                 newBucket.advanceWrapped(this);
0764             }
0765         }
0766     }
0767 
0768     ~Data()
0769     {
0770         delete [] spans;
0771     }
0772 };
0773 
0774 template <typename Node>
0775 struct iterator {
0776     using Span = QHashPrivate::Span<Node>;
0777 
0778     const Data<Node> *d = nullptr;
0779     size_t bucket = 0;
0780 
0781     size_t span() const noexcept { return bucket >> SpanConstants::SpanShift; }
0782     size_t index() const noexcept { return bucket & SpanConstants::LocalBucketMask; }
0783     inline bool isUnused() const noexcept { return !d->spans[span()].hasNode(index()); }
0784 
0785     inline Node *node() const noexcept
0786     {
0787         Q_ASSERT(!isUnused());
0788         return &d->spans[span()].at(index());
0789     }
0790     bool atEnd() const noexcept { return !d; }
0791 
0792     iterator operator++() noexcept
0793     {
0794         while (true) {
0795             ++bucket;
0796             if (bucket == d->numBuckets) {
0797                 d = nullptr;
0798                 bucket = 0;
0799                 break;
0800             }
0801             if (!isUnused())
0802                 break;
0803         }
0804         return *this;
0805     }
0806     bool operator==(iterator other) const noexcept
0807     { return d == other.d && bucket == other.bucket; }
0808     bool operator!=(iterator other) const noexcept
0809     { return !(*this == other); }
0810 };
0811 
0812 
0813 
0814 } // namespace QHashPrivate
0815 
0816 template <typename Key, typename T>
0817 class QHash
0818 {
0819     using Node = QHashPrivate::Node<Key, T>;
0820     using Data = QHashPrivate::Data<Node>;
0821     friend class QSet<Key>;
0822     friend class QMultiHash<Key, T>;
0823     friend tst_QHash;
0824 
0825     Data *d = nullptr;
0826 
0827 public:
0828     using key_type = Key;
0829     using mapped_type = T;
0830     using value_type = T;
0831     using size_type = qsizetype;
0832     using difference_type = qsizetype;
0833     using reference = T &;
0834     using const_reference = const T &;
0835 
0836     inline QHash() noexcept = default;
0837     inline QHash(std::initializer_list<std::pair<Key,T> > list)
0838         : d(new Data(list.size()))
0839     {
0840         for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
0841             insert(it->first, it->second);
0842     }
0843     QHash(const QHash &other) noexcept
0844         : d(other.d)
0845     {
0846         if (d)
0847             d->ref.ref();
0848     }
0849     ~QHash()
0850     {
0851         static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
0852         static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0853 
0854         if (d && !d->ref.deref())
0855             delete d;
0856     }
0857 
0858     QHash &operator=(const QHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
0859     {
0860         if (d != other.d) {
0861             Data *o = other.d;
0862             if (o)
0863                 o->ref.ref();
0864             if (d && !d->ref.deref())
0865                 delete d;
0866             d = o;
0867         }
0868         return *this;
0869     }
0870 
0871     QHash(QHash &&other) noexcept
0872         : d(std::exchange(other.d, nullptr))
0873     {
0874     }
0875     QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHash)
0876 #ifdef Q_QDOC
0877     template <typename InputIterator>
0878     QHash(InputIterator f, InputIterator l);
0879 #else
0880     template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
0881     QHash(InputIterator f, InputIterator l)
0882         : QHash()
0883     {
0884         QtPrivate::reserveIfForwardIterator(this, f, l);
0885         for (; f != l; ++f)
0886             insert(f.key(), f.value());
0887     }
0888 
0889     template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
0890     QHash(InputIterator f, InputIterator l)
0891         : QHash()
0892     {
0893         QtPrivate::reserveIfForwardIterator(this, f, l);
0894         for (; f != l; ++f)
0895             insert(f->first, f->second);
0896     }
0897 #endif
0898     void swap(QHash &other) noexcept { qt_ptr_swap(d, other.d); }
0899 
0900 #ifndef Q_QDOC
0901     template <typename AKey = Key, typename AT = T>
0902     QTypeTraits::compare_eq_result_container<QHash, AKey, AT> operator==(const QHash &other) const noexcept
0903     {
0904         if (d == other.d)
0905             return true;
0906         if (size() != other.size())
0907             return false;
0908 
0909         for (const_iterator it = other.begin(); it != other.end(); ++it) {
0910             const_iterator i = find(it.key());
0911             if (i == end() || !i.i.node()->valuesEqual(it.i.node()))
0912                 return false;
0913         }
0914         // all values must be the same as size is the same
0915         return true;
0916     }
0917     template <typename AKey = Key, typename AT = T>
0918     QTypeTraits::compare_eq_result_container<QHash, AKey, AT> operator!=(const QHash &other) const noexcept
0919     { return !(*this == other); }
0920 #else
0921     bool operator==(const QHash &other) const;
0922     bool operator!=(const QHash &other) const;
0923 #endif // Q_QDOC
0924 
0925     inline qsizetype size() const noexcept { return d ? qsizetype(d->size) : 0; }
0926     inline bool isEmpty() const noexcept { return !d || d->size == 0; }
0927 
0928     inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
0929     void reserve(qsizetype size)
0930     {
0931         // reserve(0) is used in squeeze()
0932         if (size && (this->capacity() >= size))
0933             return;
0934         if (isDetached())
0935             d->rehash(size);
0936         else
0937             d = Data::detached(d, size_t(size));
0938     }
0939     inline void squeeze()
0940     {
0941         if (capacity())
0942             reserve(0);
0943     }
0944 
0945     inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
0946     inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
0947     bool isSharedWith(const QHash &other) const noexcept { return d == other.d; }
0948 
0949     void clear() noexcept(std::is_nothrow_destructible<Node>::value)
0950     {
0951         if (d && !d->ref.deref())
0952             delete d;
0953         d = nullptr;
0954     }
0955 
0956     bool remove(const Key &key)
0957     {
0958         if (isEmpty()) // prevents detaching shared null
0959             return false;
0960         auto it = d->findBucket(key);
0961         size_t bucket = it.toBucketIndex(d);
0962         detach();
0963         it = typename Data::Bucket(d, bucket); // reattach in case of detach
0964 
0965         if (it.isUnused())
0966             return false;
0967         d->erase(it);
0968         return true;
0969     }
0970     template <typename Predicate>
0971     qsizetype removeIf(Predicate pred)
0972     {
0973         return QtPrivate::associative_erase_if(*this, pred);
0974     }
0975     T take(const Key &key)
0976     {
0977         if (isEmpty()) // prevents detaching shared null
0978             return T();
0979         auto it = d->findBucket(key);
0980         size_t bucket = it.toBucketIndex(d);
0981         detach();
0982         it = typename Data::Bucket(d, bucket); // reattach in case of detach
0983 
0984         if (it.isUnused())
0985             return T();
0986         T value = it.node()->takeValue();
0987         d->erase(it);
0988         return value;
0989     }
0990 
0991     bool contains(const Key &key) const noexcept
0992     {
0993         if (!d)
0994             return false;
0995         return d->findNode(key) != nullptr;
0996     }
0997     qsizetype count(const Key &key) const noexcept
0998     {
0999         return contains(key) ? 1 : 0;
1000     }
1001 
1002 private:
1003     const Key *keyImpl(const T &value) const noexcept
1004     {
1005         if (d) {
1006             const_iterator i = begin();
1007             while (i != end()) {
1008                 if (i.value() == value)
1009                     return &i.key();
1010                 ++i;
1011             }
1012         }
1013 
1014         return nullptr;
1015     }
1016 
1017 public:
1018     Key key(const T &value) const noexcept
1019     {
1020         if (auto *k = keyImpl(value))
1021             return *k;
1022         else
1023             return Key();
1024     }
1025     Key key(const T &value, const Key &defaultKey) const noexcept
1026     {
1027         if (auto *k = keyImpl(value))
1028             return *k;
1029         else
1030             return defaultKey;
1031     }
1032 
1033 private:
1034     T *valueImpl(const Key &key) const noexcept
1035     {
1036         if (d) {
1037             Node *n = d->findNode(key);
1038             if (n)
1039                 return &n->value;
1040         }
1041         return nullptr;
1042     }
1043 public:
1044     T value(const Key &key) const noexcept
1045     {
1046         if (T *v = valueImpl(key))
1047             return *v;
1048         else
1049             return T();
1050     }
1051 
1052     T value(const Key &key, const T &defaultValue) const noexcept
1053     {
1054         if (T *v = valueImpl(key))
1055             return *v;
1056         else
1057             return defaultValue;
1058     }
1059 
1060     T &operator[](const Key &key)
1061     {
1062         const auto copy = isDetached() ? QHash() : *this; // keep 'key' alive across the detach
1063         detach();
1064         auto result = d->findOrInsert(key);
1065         Q_ASSERT(!result.it.atEnd());
1066         if (!result.initialized)
1067             Node::createInPlace(result.it.node(), key, T());
1068         return result.it.node()->value;
1069     }
1070 
1071     const T operator[](const Key &key) const noexcept
1072     {
1073         return value(key);
1074     }
1075 
1076     QList<Key> keys() const { return QList<Key>(keyBegin(), keyEnd()); }
1077     QList<Key> keys(const T &value) const
1078     {
1079         QList<Key> res;
1080         const_iterator i = begin();
1081         while (i != end()) {
1082             if (i.value() == value)
1083                 res.append(i.key());
1084             ++i;
1085         }
1086         return res;
1087     }
1088     QList<T> values() const { return QList<T>(begin(), end()); }
1089 
1090     class const_iterator;
1091 
1092     class iterator
1093     {
1094         using piter = typename QHashPrivate::iterator<Node>;
1095         friend class const_iterator;
1096         friend class QHash<Key, T>;
1097         friend class QSet<Key>;
1098         piter i;
1099         explicit inline iterator(piter it) noexcept : i(it) { }
1100 
1101     public:
1102         typedef std::forward_iterator_tag iterator_category;
1103         typedef qptrdiff difference_type;
1104         typedef T value_type;
1105         typedef T *pointer;
1106         typedef T &reference;
1107 
1108         constexpr iterator() noexcept = default;
1109 
1110         inline const Key &key() const noexcept { return i.node()->key; }
1111         inline T &value() const noexcept { return i.node()->value; }
1112         inline T &operator*() const noexcept { return i.node()->value; }
1113         inline T *operator->() const noexcept { return &i.node()->value; }
1114         inline bool operator==(const iterator &o) const noexcept { return i == o.i; }
1115         inline bool operator!=(const iterator &o) const noexcept { return i != o.i; }
1116 
1117         inline iterator &operator++() noexcept
1118         {
1119             ++i;
1120             return *this;
1121         }
1122         inline iterator operator++(int) noexcept
1123         {
1124             iterator r = *this;
1125             ++i;
1126             return r;
1127         }
1128 
1129         inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
1130         inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
1131     };
1132     friend class iterator;
1133 
1134     class const_iterator
1135     {
1136         using piter = typename QHashPrivate::iterator<Node>;
1137         friend class iterator;
1138         friend class QHash<Key, T>;
1139         friend class QSet<Key>;
1140         piter i;
1141         explicit inline const_iterator(piter it) : i(it) { }
1142 
1143     public:
1144         typedef std::forward_iterator_tag iterator_category;
1145         typedef qptrdiff difference_type;
1146         typedef T value_type;
1147         typedef const T *pointer;
1148         typedef const T &reference;
1149 
1150         constexpr const_iterator() noexcept = default;
1151         inline const_iterator(const iterator &o) noexcept : i(o.i) { }
1152 
1153         inline const Key &key() const noexcept { return i.node()->key; }
1154         inline const T &value() const noexcept { return i.node()->value; }
1155         inline const T &operator*() const noexcept { return i.node()->value; }
1156         inline const T *operator->() const noexcept { return &i.node()->value; }
1157         inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
1158         inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
1159 
1160         inline const_iterator &operator++() noexcept
1161         {
1162             ++i;
1163             return *this;
1164         }
1165         inline const_iterator operator++(int) noexcept
1166         {
1167             const_iterator r = *this;
1168             ++i;
1169             return r;
1170         }
1171     };
1172     friend class const_iterator;
1173 
1174     class key_iterator
1175     {
1176         const_iterator i;
1177 
1178     public:
1179         typedef typename const_iterator::iterator_category iterator_category;
1180         typedef qptrdiff difference_type;
1181         typedef Key value_type;
1182         typedef const Key *pointer;
1183         typedef const Key &reference;
1184 
1185         key_iterator() noexcept = default;
1186         explicit key_iterator(const_iterator o) noexcept : i(o) { }
1187 
1188         const Key &operator*() const noexcept { return i.key(); }
1189         const Key *operator->() const noexcept { return &i.key(); }
1190         bool operator==(key_iterator o) const noexcept { return i == o.i; }
1191         bool operator!=(key_iterator o) const noexcept { return i != o.i; }
1192 
1193         inline key_iterator &operator++() noexcept { ++i; return *this; }
1194         inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
1195         const_iterator base() const noexcept { return i; }
1196     };
1197 
1198     typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1199     typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1200 
1201     // STL style
1202     inline iterator begin() { detach(); return iterator(d->begin()); }
1203     inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1204     inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1205     inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1206     inline iterator end() noexcept { return iterator(); }
1207     inline const_iterator end() const noexcept { return const_iterator(); }
1208     inline const_iterator cend() const noexcept { return const_iterator(); }
1209     inline const_iterator constEnd() const noexcept { return const_iterator(); }
1210     inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
1211     inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
1212     inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
1213     inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
1214     inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
1215     inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
1216     inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
1217     inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
1218     auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
1219     auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
1220     auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
1221     auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
1222 
1223     iterator erase(const_iterator it)
1224     {
1225         Q_ASSERT(it != constEnd());
1226         detach();
1227         // ensure a valid iterator across the detach:
1228         iterator i = iterator{d->detachedIterator(it.i)};
1229         typename Data::Bucket bucket(i.i);
1230 
1231         d->erase(bucket);
1232         if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
1233             ++i;
1234         return i;
1235     }
1236 
1237     std::pair<iterator, iterator> equal_range(const Key &key)
1238     {
1239         auto first = find(key);
1240         auto second = first;
1241         if (second != iterator())
1242             ++second;
1243         return {first, second};
1244     }
1245 
1246     std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
1247     {
1248         auto first = find(key);
1249         auto second = first;
1250         if (second != iterator())
1251             ++second;
1252         return {first, second};
1253     }
1254 
1255     typedef iterator Iterator;
1256     typedef const_iterator ConstIterator;
1257     inline qsizetype count() const noexcept { return d ? qsizetype(d->size) : 0; }
1258     iterator find(const Key &key)
1259     {
1260         if (isEmpty()) // prevents detaching shared null
1261             return end();
1262         auto it = d->findBucket(key);
1263         size_t bucket = it.toBucketIndex(d);
1264         detach();
1265         it = typename Data::Bucket(d, bucket); // reattach in case of detach
1266         if (it.isUnused())
1267             return end();
1268         return iterator(it.toIterator(d));
1269     }
1270     const_iterator find(const Key &key) const noexcept
1271     {
1272         if (isEmpty())
1273             return end();
1274         auto it = d->findBucket(key);
1275         if (it.isUnused())
1276             return end();
1277         return const_iterator({d, it.toBucketIndex(d)});
1278     }
1279     const_iterator constFind(const Key &key) const noexcept
1280     {
1281         return find(key);
1282     }
1283     iterator insert(const Key &key, const T &value)
1284     {
1285         return emplace(key, value);
1286     }
1287 
1288     void insert(const QHash &hash)
1289     {
1290         if (d == hash.d || !hash.d)
1291             return;
1292         if (!d) {
1293             *this = hash;
1294             return;
1295         }
1296 
1297         detach();
1298 
1299         for (auto it = hash.begin(); it != hash.end(); ++it)
1300             emplace(it.key(), it.value());
1301     }
1302 
1303     template <typename ...Args>
1304     iterator emplace(const Key &key, Args &&... args)
1305     {
1306         Key copy = key; // Needs to be explicit for MSVC 2019
1307         return emplace(std::move(copy), std::forward<Args>(args)...);
1308     }
1309 
1310     template <typename ...Args>
1311     iterator emplace(Key &&key, Args &&... args)
1312     {
1313         if (isDetached()) {
1314             if (d->shouldGrow()) // Construct the value now so that no dangling references are used
1315                 return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
1316             return emplace_helper(std::move(key), std::forward<Args>(args)...);
1317         }
1318         // else: we must detach
1319         const auto copy = *this; // keep 'args' alive across the detach/growth
1320         detach();
1321         return emplace_helper(std::move(key), std::forward<Args>(args)...);
1322     }
1323 
1324     float load_factor() const noexcept { return d ? d->loadFactor() : 0; }
1325     static float max_load_factor() noexcept { return 0.5; }
1326     size_t bucket_count() const noexcept { return d ? d->numBuckets : 0; }
1327     static size_t max_bucket_count() noexcept { return Data::maxNumBuckets(); }
1328 
1329     inline bool empty() const noexcept { return isEmpty(); }
1330 
1331 private:
1332     template <typename ...Args>
1333     iterator emplace_helper(Key &&key, Args &&... args)
1334     {
1335         auto result = d->findOrInsert(key);
1336         if (!result.initialized)
1337             Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
1338         else
1339             result.it.node()->emplaceValue(std::forward<Args>(args)...);
1340         return iterator(result.it);
1341     }
1342 };
1343 
1344 
1345 
1346 template <typename Key, typename T>
1347 class QMultiHash
1348 {
1349     using Node = QHashPrivate::MultiNode<Key, T>;
1350     using Data = QHashPrivate::Data<Node>;
1351     using Chain = QHashPrivate::MultiNodeChain<T>;
1352 
1353     Data *d = nullptr;
1354     qsizetype m_size = 0;
1355 
1356 public:
1357     using key_type = Key;
1358     using mapped_type = T;
1359     using value_type = T;
1360     using size_type = qsizetype;
1361     using difference_type = qsizetype;
1362     using reference = T &;
1363     using const_reference = const T &;
1364 
1365     QMultiHash() noexcept = default;
1366     inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
1367         : d(new Data(list.size()))
1368     {
1369         for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
1370             insert(it->first, it->second);
1371     }
1372 #ifdef Q_QDOC
1373     template <typename InputIterator>
1374     QMultiHash(InputIterator f, InputIterator l);
1375 #else
1376     template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
1377     QMultiHash(InputIterator f, InputIterator l)
1378     {
1379         QtPrivate::reserveIfForwardIterator(this, f, l);
1380         for (; f != l; ++f)
1381             insert(f.key(), f.value());
1382     }
1383 
1384     template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
1385     QMultiHash(InputIterator f, InputIterator l)
1386     {
1387         QtPrivate::reserveIfForwardIterator(this, f, l);
1388         for (; f != l; ++f)
1389             insert(f->first, f->second);
1390     }
1391 #endif
1392     QMultiHash(const QMultiHash &other) noexcept
1393         : d(other.d), m_size(other.m_size)
1394     {
1395         if (d)
1396             d->ref.ref();
1397     }
1398     ~QMultiHash()
1399     {
1400         static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
1401         static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
1402 
1403         if (d && !d->ref.deref())
1404             delete d;
1405     }
1406 
1407     QMultiHash &operator=(const QMultiHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
1408     {
1409         if (d != other.d) {
1410             Data *o = other.d;
1411             if (o)
1412                 o->ref.ref();
1413             if (d && !d->ref.deref())
1414                 delete d;
1415             d = o;
1416             m_size = other.m_size;
1417         }
1418         return *this;
1419     }
1420     QMultiHash(QMultiHash &&other) noexcept
1421         : d(std::exchange(other.d, nullptr)),
1422           m_size(std::exchange(other.m_size, 0))
1423     {
1424     }
1425     QMultiHash &operator=(QMultiHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
1426     {
1427         QMultiHash moved(std::move(other));
1428         swap(moved);
1429         return *this;
1430     }
1431 
1432     explicit QMultiHash(const QHash<Key, T> &other)
1433         : QMultiHash(other.begin(), other.end())
1434     {}
1435 
1436     explicit QMultiHash(QHash<Key, T> &&other)
1437     {
1438         unite(std::move(other));
1439     }
1440 
1441     void swap(QMultiHash &other) noexcept
1442     {
1443         qt_ptr_swap(d, other.d);
1444         std::swap(m_size, other.m_size);
1445     }
1446 
1447 #ifndef Q_QDOC
1448     template <typename AKey = Key, typename AT = T>
1449     QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> operator==(const QMultiHash &other) const noexcept
1450     {
1451         if (d == other.d)
1452             return true;
1453         if (m_size != other.m_size)
1454             return false;
1455         if (m_size == 0)
1456             return true;
1457         // equal size, and both non-zero size => d pointers allocated for both
1458         Q_ASSERT(d);
1459         Q_ASSERT(other.d);
1460         if (d->size != other.d->size)
1461             return false;
1462         for (auto it = other.d->begin(); it != other.d->end(); ++it) {
1463             auto *n = d->findNode(it.node()->key);
1464             if (!n)
1465                 return false;
1466             Chain *e = it.node()->value;
1467             while (e) {
1468                 Chain *oe = n->value;
1469                 while (oe) {
1470                     if (oe->value == e->value)
1471                         break;
1472                     oe = oe->next;
1473                 }
1474                 if (!oe)
1475                     return false;
1476                 e = e->next;
1477             }
1478         }
1479         // all values must be the same as size is the same
1480         return true;
1481     }
1482     template <typename AKey = Key, typename AT = T>
1483     QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> operator!=(const QMultiHash &other) const noexcept
1484     { return !(*this == other); }
1485 #else
1486     bool operator==(const QMultiHash &other) const;
1487     bool operator!=(const QMultiHash &other) const;
1488 #endif // Q_QDOC
1489 
1490     inline qsizetype size() const noexcept { return m_size; }
1491 
1492     inline bool isEmpty() const noexcept { return !m_size; }
1493 
1494     inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
1495     void reserve(qsizetype size)
1496     {
1497         // reserve(0) is used in squeeze()
1498         if (size && (this->capacity() >= size))
1499             return;
1500         if (isDetached())
1501             d->rehash(size);
1502         else
1503             d = Data::detached(d, size_t(size));
1504     }
1505     inline void squeeze() { reserve(0); }
1506 
1507     inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
1508     inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
1509     bool isSharedWith(const QMultiHash &other) const noexcept { return d == other.d; }
1510 
1511     void clear() noexcept(std::is_nothrow_destructible<Node>::value)
1512     {
1513         if (d && !d->ref.deref())
1514             delete d;
1515         d = nullptr;
1516         m_size = 0;
1517     }
1518 
1519     qsizetype remove(const Key &key)
1520     {
1521         if (isEmpty()) // prevents detaching shared null
1522             return 0;
1523         auto it = d->findBucket(key);
1524         size_t bucket = it.toBucketIndex(d);
1525         detach();
1526         it = typename Data::Bucket(d, bucket); // reattach in case of detach
1527 
1528         if (it.isUnused())
1529             return 0;
1530         qsizetype n = Node::freeChain(it.node());
1531         m_size -= n;
1532         Q_ASSERT(m_size >= 0);
1533         d->erase(it);
1534         return n;
1535     }
1536     template <typename Predicate>
1537     qsizetype removeIf(Predicate pred)
1538     {
1539         return QtPrivate::associative_erase_if(*this, pred);
1540     }
1541     T take(const Key &key)
1542     {
1543         if (isEmpty()) // prevents detaching shared null
1544             return T();
1545         auto it = d->findBucket(key);
1546         size_t bucket = it.toBucketIndex(d);
1547         detach();
1548         it = typename Data::Bucket(d, bucket); // reattach in case of detach
1549 
1550         if (it.isUnused())
1551             return T();
1552         Chain *e = it.node()->value;
1553         Q_ASSERT(e);
1554         T t = std::move(e->value);
1555         if (e->next) {
1556             it.node()->value = e->next;
1557             delete e;
1558         } else {
1559             // erase() deletes the values.
1560             d->erase(it);
1561         }
1562         --m_size;
1563         Q_ASSERT(m_size >= 0);
1564         return t;
1565     }
1566 
1567     bool contains(const Key &key) const noexcept
1568     {
1569         if (!d)
1570             return false;
1571         return d->findNode(key) != nullptr;
1572     }
1573 
1574 private:
1575     const Key *keyImpl(const T &value) const noexcept
1576     {
1577         if (d) {
1578             auto i = d->begin();
1579             while (i != d->end()) {
1580                 Chain *e = i.node()->value;
1581                 if (e->contains(value))
1582                     return &i.node()->key;
1583                 ++i;
1584             }
1585         }
1586 
1587         return nullptr;
1588     }
1589 public:
1590     Key key(const T &value) const noexcept
1591     {
1592         if (auto *k = keyImpl(value))
1593             return *k;
1594         else
1595             return Key();
1596     }
1597     Key key(const T &value, const Key &defaultKey) const noexcept
1598     {
1599         if (auto *k = keyImpl(value))
1600             return *k;
1601         else
1602             return defaultKey;
1603     }
1604 
1605 private:
1606     T *valueImpl(const Key &key) const noexcept
1607     {
1608         if (d) {
1609             Node *n = d->findNode(key);
1610             if (n) {
1611                 Q_ASSERT(n->value);
1612                 return &n->value->value;
1613             }
1614         }
1615         return nullptr;
1616     }
1617 public:
1618     T value(const Key &key) const noexcept
1619     {
1620         if (auto *v = valueImpl(key))
1621             return *v;
1622         else
1623             return T();
1624     }
1625     T value(const Key &key, const T &defaultValue) const noexcept
1626     {
1627         if (auto *v = valueImpl(key))
1628             return *v;
1629         else
1630             return defaultValue;
1631     }
1632 
1633     T &operator[](const Key &key)
1634     {
1635         const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key' alive across the detach
1636         detach();
1637         auto result = d->findOrInsert(key);
1638         Q_ASSERT(!result.it.atEnd());
1639         if (!result.initialized) {
1640             Node::createInPlace(result.it.node(), key, T());
1641             ++m_size;
1642         }
1643         return result.it.node()->value->value;
1644     }
1645 
1646     const T operator[](const Key &key) const noexcept
1647     {
1648         return value(key);
1649     }
1650 
1651     QList<Key> uniqueKeys() const
1652     {
1653         QList<Key> res;
1654         if (d) {
1655             auto i = d->begin();
1656             while (i != d->end()) {
1657                 res.append(i.node()->key);
1658                 ++i;
1659             }
1660         }
1661         return res;
1662     }
1663 
1664     QList<Key> keys() const { return QList<Key>(keyBegin(), keyEnd()); }
1665     QList<Key> keys(const T &value) const
1666     {
1667         QList<Key> res;
1668         const_iterator i = begin();
1669         while (i != end()) {
1670             if (i.value() == value)
1671                 res.append(i.key());
1672             ++i;
1673         }
1674         return res;
1675     }
1676     QList<T> values() const { return QList<T>(begin(), end()); }
1677     QList<T> values(const Key &key) const
1678     {
1679         QList<T> values;
1680         if (d) {
1681             Node *n = d->findNode(key);
1682             if (n) {
1683                 Chain *e = n->value;
1684                 while (e) {
1685                     values.append(e->value);
1686                     e = e->next;
1687                 }
1688             }
1689         }
1690         return values;
1691     }
1692 
1693     class const_iterator;
1694 
1695     class iterator
1696     {
1697         using piter = typename QHashPrivate::iterator<Node>;
1698         friend class const_iterator;
1699         friend class QMultiHash<Key, T>;
1700         piter i;
1701         Chain **e = nullptr;
1702         explicit inline iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
1703         {
1704             if (!it.atEnd() && !e) {
1705                 e = &it.node()->value;
1706                 Q_ASSERT(e && *e);
1707             }
1708         }
1709 
1710     public:
1711         typedef std::forward_iterator_tag iterator_category;
1712         typedef qptrdiff difference_type;
1713         typedef T value_type;
1714         typedef T *pointer;
1715         typedef T &reference;
1716 
1717         constexpr iterator() noexcept = default;
1718 
1719         inline const Key &key() const noexcept { return i.node()->key; }
1720         inline T &value() const noexcept { return (*e)->value; }
1721         inline T &operator*() const noexcept { return (*e)->value; }
1722         inline T *operator->() const noexcept { return &(*e)->value; }
1723         inline bool operator==(const iterator &o) const noexcept { return e == o.e; }
1724         inline bool operator!=(const iterator &o) const noexcept { return e != o.e; }
1725 
1726         inline iterator &operator++() noexcept {
1727             Q_ASSERT(e && *e);
1728             e = &(*e)->next;
1729             Q_ASSERT(e);
1730             if (!*e) {
1731                 ++i;
1732                 e = i.atEnd() ? nullptr : &i.node()->value;
1733             }
1734             return *this;
1735         }
1736         inline iterator operator++(int) noexcept {
1737             iterator r = *this;
1738             ++(*this);
1739             return r;
1740         }
1741 
1742         inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
1743         inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
1744     };
1745     friend class iterator;
1746 
1747     class const_iterator
1748     {
1749         using piter = typename QHashPrivate::iterator<Node>;
1750         friend class iterator;
1751         friend class QMultiHash<Key, T>;
1752         piter i;
1753         Chain **e = nullptr;
1754         explicit inline const_iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
1755         {
1756             if (!it.atEnd() && !e) {
1757                 e = &it.node()->value;
1758                 Q_ASSERT(e && *e);
1759             }
1760         }
1761 
1762     public:
1763         typedef std::forward_iterator_tag iterator_category;
1764         typedef qptrdiff difference_type;
1765         typedef T value_type;
1766         typedef const T *pointer;
1767         typedef const T &reference;
1768 
1769         constexpr const_iterator() noexcept = default;
1770         inline const_iterator(const iterator &o) noexcept : i(o.i), e(o.e) { }
1771 
1772         inline const Key &key() const noexcept { return i.node()->key; }
1773         inline T &value() const noexcept { return (*e)->value; }
1774         inline T &operator*() const noexcept { return (*e)->value; }
1775         inline T *operator->() const noexcept { return &(*e)->value; }
1776         inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
1777         inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
1778 
1779         inline const_iterator &operator++() noexcept {
1780             Q_ASSERT(e && *e);
1781             e = &(*e)->next;
1782             Q_ASSERT(e);
1783             if (!*e) {
1784                 ++i;
1785                 e = i.atEnd() ? nullptr : &i.node()->value;
1786             }
1787             return *this;
1788         }
1789         inline const_iterator operator++(int) noexcept
1790         {
1791             const_iterator r = *this;
1792             ++(*this);
1793             return r;
1794         }
1795     };
1796     friend class const_iterator;
1797 
1798     class key_iterator
1799     {
1800         const_iterator i;
1801 
1802     public:
1803         typedef typename const_iterator::iterator_category iterator_category;
1804         typedef qptrdiff difference_type;
1805         typedef Key value_type;
1806         typedef const Key *pointer;
1807         typedef const Key &reference;
1808 
1809         key_iterator() noexcept = default;
1810         explicit key_iterator(const_iterator o) noexcept : i(o) { }
1811 
1812         const Key &operator*() const noexcept { return i.key(); }
1813         const Key *operator->() const noexcept { return &i.key(); }
1814         bool operator==(key_iterator o) const noexcept { return i == o.i; }
1815         bool operator!=(key_iterator o) const noexcept { return i != o.i; }
1816 
1817         inline key_iterator &operator++() noexcept { ++i; return *this; }
1818         inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
1819         const_iterator base() const noexcept { return i; }
1820     };
1821 
1822     typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1823     typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1824 
1825     // STL style
1826     inline iterator begin() { detach(); return iterator(d->begin()); }
1827     inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1828     inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1829     inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
1830     inline iterator end() noexcept { return iterator(); }
1831     inline const_iterator end() const noexcept { return const_iterator(); }
1832     inline const_iterator cend() const noexcept { return const_iterator(); }
1833     inline const_iterator constEnd() const noexcept { return const_iterator(); }
1834     inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
1835     inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
1836     inline key_value_iterator keyValueBegin() noexcept { return key_value_iterator(begin()); }
1837     inline key_value_iterator keyValueEnd() noexcept { return key_value_iterator(end()); }
1838     inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
1839     inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
1840     inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
1841     inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
1842     auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
1843     auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
1844     auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
1845     auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
1846 
1847     iterator detach(const_iterator it)
1848     {
1849         auto i = it.i;
1850         Chain **e = it.e;
1851         if (d->ref.isShared()) {
1852             // need to store iterator position before detaching
1853             qsizetype n = 0;
1854             Chain *entry = i.node()->value;
1855             while (entry != *it.e) {
1856                 ++n;
1857                 entry = entry->next;
1858             }
1859             Q_ASSERT(entry);
1860             detach_helper();
1861 
1862             i = d->detachedIterator(i);
1863             e = &i.node()->value;
1864             while (n) {
1865                 e = &(*e)->next;
1866                 --n;
1867             }
1868             Q_ASSERT(e && *e);
1869         }
1870         return iterator(i, e);
1871     }
1872 
1873     iterator erase(const_iterator it)
1874     {
1875         Q_ASSERT(d);
1876         iterator iter = detach(it);
1877         iterator i = iter;
1878         Chain *e = *i.e;
1879         Chain *next = e->next;
1880         *i.e = next;
1881         delete e;
1882         if (!next) {
1883             if (i.e == &i.i.node()->value) {
1884                 // last remaining entry, erase
1885                 typename Data::Bucket bucket(i.i);
1886                 d->erase(bucket);
1887                 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
1888                     i = iterator(++iter.i);
1889                 else // 'i' currently has a nullptr chain. So, we must recreate it
1890                     i = iterator(bucket.toIterator(d));
1891             } else {
1892                 i = iterator(++iter.i);
1893             }
1894         }
1895         --m_size;
1896         Q_ASSERT(m_size >= 0);
1897         return i;
1898     }
1899 
1900     // more Qt
1901     typedef iterator Iterator;
1902     typedef const_iterator ConstIterator;
1903     inline qsizetype count() const noexcept { return size(); }
1904     iterator find(const Key &key)
1905     {
1906         if (isEmpty())
1907             return end();
1908         auto it = d->findBucket(key);
1909         size_t bucket = it.toBucketIndex(d);
1910         detach();
1911         it = typename Data::Bucket(d, bucket); // reattach in case of detach
1912 
1913         if (it.isUnused())
1914             return end();
1915         return iterator(it.toIterator(d));
1916     }
1917     const_iterator find(const Key &key) const noexcept
1918     {
1919         return constFind(key);
1920     }
1921     const_iterator constFind(const Key &key) const noexcept
1922     {
1923         if (isEmpty())
1924             return end();
1925         auto it = d->findBucket(key);
1926         if (it.isUnused())
1927             return constEnd();
1928         return const_iterator(it.toIterator(d));
1929     }
1930     iterator insert(const Key &key, const T &value)
1931     {
1932         return emplace(key, value);
1933     }
1934 
1935     template <typename ...Args>
1936     iterator emplace(const Key &key, Args &&... args)
1937     {
1938         return emplace(Key(key), std::forward<Args>(args)...);
1939     }
1940 
1941     template <typename ...Args>
1942     iterator emplace(Key &&key, Args &&... args)
1943     {
1944         if (isDetached()) {
1945             if (d->shouldGrow()) // Construct the value now so that no dangling references are used
1946                 return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
1947             return emplace_helper(std::move(key), std::forward<Args>(args)...);
1948         }
1949         // else: we must detach
1950         const auto copy = *this; // keep 'args' alive across the detach/growth
1951         detach();
1952         return emplace_helper(std::move(key), std::forward<Args>(args)...);
1953     }
1954 
1955 
1956     float load_factor() const noexcept { return d ? d->loadFactor() : 0; }
1957     static float max_load_factor() noexcept { return 0.5; }
1958     size_t bucket_count() const noexcept { return d ? d->numBuckets : 0; }
1959     static size_t max_bucket_count() noexcept { return Data::maxNumBuckets(); }
1960 
1961     inline bool empty() const noexcept { return isEmpty(); }
1962 
1963     inline iterator replace(const Key &key, const T &value)
1964     {
1965         return emplaceReplace(key, value);
1966     }
1967 
1968     template <typename ...Args>
1969     iterator emplaceReplace(const Key &key, Args &&... args)
1970     {
1971         return emplaceReplace(Key(key), std::forward<Args>(args)...);
1972     }
1973 
1974     template <typename ...Args>
1975     iterator emplaceReplace(Key &&key, Args &&... args)
1976     {
1977         if (isDetached()) {
1978             if (d->shouldGrow()) // Construct the value now so that no dangling references are used
1979                 return emplaceReplace_helper(std::move(key), T(std::forward<Args>(args)...));
1980             return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
1981         }
1982         // else: we must detach
1983         const auto copy = *this; // keep 'args' alive across the detach/growth
1984         detach();
1985         return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
1986     }
1987 
1988     inline QMultiHash &operator+=(const QMultiHash &other)
1989     { this->unite(other); return *this; }
1990     inline QMultiHash operator+(const QMultiHash &other) const
1991     { QMultiHash result = *this; result += other; return result; }
1992 
1993     bool contains(const Key &key, const T &value) const noexcept
1994     {
1995         if (isEmpty())
1996             return false;
1997         auto n = d->findNode(key);
1998         if (n == nullptr)
1999             return false;
2000         return n->value->contains(value);
2001     }
2002 
2003     qsizetype remove(const Key &key, const T &value)
2004     {
2005         if (isEmpty()) // prevents detaching shared null
2006             return 0;
2007         auto it = d->findBucket(key);
2008         size_t bucket = it.toBucketIndex(d);
2009         detach();
2010         it = typename Data::Bucket(d, bucket); // reattach in case of detach
2011 
2012         if (it.isUnused())
2013             return 0;
2014         qsizetype n = 0;
2015         Chain **e = &it.node()->value;
2016         while (*e) {
2017             Chain *entry = *e;
2018             if (entry->value == value) {
2019                 *e = entry->next;
2020                 delete entry;
2021                 ++n;
2022             } else {
2023                 e = &entry->next;
2024             }
2025         }
2026         if (!it.node()->value)
2027             d->erase(it);
2028         m_size -= n;
2029         Q_ASSERT(m_size >= 0);
2030         return n;
2031     }
2032 
2033     qsizetype count(const Key &key) const noexcept
2034     {
2035         if (!d)
2036             return 0;
2037         auto it = d->findBucket(key);
2038         if (it.isUnused())
2039             return 0;
2040         qsizetype n = 0;
2041         Chain *e = it.node()->value;
2042         while (e) {
2043             ++n;
2044             e = e->next;
2045         }
2046 
2047         return n;
2048     }
2049 
2050     qsizetype count(const Key &key, const T &value) const noexcept
2051     {
2052         if (!d)
2053             return 0;
2054         auto it = d->findBucket(key);
2055         if (it.isUnused())
2056             return 0;
2057         qsizetype n = 0;
2058         Chain *e = it.node()->value;
2059         while (e) {
2060             if (e->value == value)
2061                 ++n;
2062             e = e->next;
2063         }
2064 
2065         return n;
2066     }
2067 
2068     iterator find(const Key &key, const T &value)
2069     {
2070         if (isEmpty())
2071             return end();
2072         const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key'/'value' alive across the detach
2073         detach();
2074         auto it = constFind(key, value);
2075         return iterator(it.i, it.e);
2076     }
2077     const_iterator find(const Key &key, const T &value) const noexcept
2078     {
2079         return constFind(key, value);
2080     }
2081     const_iterator constFind(const Key &key, const T &value) const noexcept
2082     {
2083         const_iterator i(constFind(key));
2084         const_iterator end(constEnd());
2085         while (i != end && i.key() == key) {
2086             if (i.value() == value)
2087                 return i;
2088             ++i;
2089         }
2090         return end;
2091     }
2092 
2093     QMultiHash &unite(const QMultiHash &other)
2094     {
2095         if (isEmpty()) {
2096             *this = other;
2097         } else if (other.isEmpty()) {
2098             ;
2099         } else {
2100             QMultiHash copy(other);
2101             detach();
2102             for (auto cit = copy.cbegin(); cit != copy.cend(); ++cit)
2103                 insert(cit.key(), *cit);
2104         }
2105         return *this;
2106     }
2107 
2108     QMultiHash &unite(const QHash<Key, T> &other)
2109     {
2110         for (auto cit = other.cbegin(); cit != other.cend(); ++cit)
2111             insert(cit.key(), *cit);
2112         return *this;
2113     }
2114 
2115     QMultiHash &unite(QHash<Key, T> &&other)
2116     {
2117         if (!other.isDetached()) {
2118             unite(other);
2119             return *this;
2120         }
2121         auto it = other.d->begin();
2122         for (const auto end = other.d->end(); it != end; ++it)
2123             emplace(std::move(it.node()->key), std::move(it.node()->takeValue()));
2124         other.clear();
2125         return *this;
2126     }
2127 
2128     std::pair<iterator, iterator> equal_range(const Key &key)
2129     {
2130         const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key' alive across the detach
2131         detach();
2132         auto pair = std::as_const(*this).equal_range(key);
2133         return {iterator(pair.first.i), iterator(pair.second.i)};
2134     }
2135 
2136     std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
2137     {
2138         if (!d)
2139             return {end(), end()};
2140 
2141         auto bucket = d->findBucket(key);
2142         if (bucket.isUnused())
2143             return {end(), end()};
2144         auto it = bucket.toIterator(d);
2145         auto end = it;
2146         ++end;
2147         return {const_iterator(it), const_iterator(end)};
2148     }
2149 
2150 private:
2151     void detach_helper()
2152     {
2153         if (!d) {
2154             d = new Data;
2155             return;
2156         }
2157         Data *dd = new Data(*d);
2158         if (!d->ref.deref())
2159             delete d;
2160         d = dd;
2161     }
2162 
2163     template<typename... Args>
2164     iterator emplace_helper(Key &&key, Args &&...args)
2165     {
2166         auto result = d->findOrInsert(key);
2167         if (!result.initialized)
2168             Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2169         else
2170             result.it.node()->insertMulti(std::forward<Args>(args)...);
2171         ++m_size;
2172         return iterator(result.it);
2173     }
2174 
2175     template<typename... Args>
2176     iterator emplaceReplace_helper(Key &&key, Args &&...args)
2177     {
2178         auto result = d->findOrInsert(key);
2179         if (!result.initialized) {
2180             Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2181             ++m_size;
2182         } else {
2183             result.it.node()->emplaceValue(std::forward<Args>(args)...);
2184         }
2185         return iterator(result.it);
2186     }
2187 };
2188 
2189 Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2190 Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2191 Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2192 Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2193 
2194 template <class Key, class T>
2195 size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
2196     noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
2197 {
2198     size_t hash = 0;
2199     for (auto it = key.begin(), end = key.end(); it != end; ++it) {
2200         QtPrivate::QHashCombine combine;
2201         size_t h = combine(seed, it.key());
2202         // use + to keep the result independent of the ordering of the keys
2203         hash += combine(h, it.value());
2204     }
2205     return hash;
2206 }
2207 
2208 template <class Key, class T>
2209 inline size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
2210     noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
2211 {
2212     size_t hash = 0;
2213     for (auto it = key.begin(), end = key.end(); it != end; ++it) {
2214         QtPrivate::QHashCombine combine;
2215         size_t h = combine(seed, it.key());
2216         // use + to keep the result independent of the ordering of the keys
2217         hash += combine(h, it.value());
2218     }
2219     return hash;
2220 }
2221 
2222 template <typename Key, typename T, typename Predicate>
2223 qsizetype erase_if(QHash<Key, T> &hash, Predicate pred)
2224 {
2225     return QtPrivate::associative_erase_if(hash, pred);
2226 }
2227 
2228 template <typename Key, typename T, typename Predicate>
2229 qsizetype erase_if(QMultiHash<Key, T> &hash, Predicate pred)
2230 {
2231     return QtPrivate::associative_erase_if(hash, pred);
2232 }
2233 
2234 QT_END_NAMESPACE
2235 
2236 #endif // QHASH_H