Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-31 09:40:53

0001 // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
0002 // Copyright (C) 2021 The Qt Company Ltd.
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0004 // Qt-Security score:significant reason:default
0005 
0006 #ifndef QMAP_H
0007 #define QMAP_H
0008 
0009 #include <QtCore/qcompare.h>
0010 #include <QtCore/qhashfunctions.h>
0011 #include <QtCore/qiterator.h>
0012 #include <QtCore/qlist.h>
0013 #include <QtCore/qrefcount.h>
0014 #include <QtCore/qpair.h>
0015 #include <QtCore/qscopeguard.h>
0016 #include <QtCore/qshareddata.h>
0017 #include <QtCore/qshareddata_impl.h>
0018 #include <QtCore/qttypetraits.h>
0019 
0020 #include <functional>
0021 #include <initializer_list>
0022 #include <map>
0023 #include <algorithm>
0024 
0025 QT_BEGIN_NAMESPACE
0026 
0027 // common code shared between QMap and QMultimap
0028 template <typename AMap>
0029 class QMapData : public QSharedData
0030 {
0031 public:
0032     using Map = AMap;
0033     using Key = typename Map::key_type;
0034     using T = typename Map::mapped_type;
0035     using value_type = typename Map::value_type;
0036     using size_type = typename Map::size_type;
0037     using iterator = typename Map::iterator;
0038     using const_iterator = typename Map::const_iterator;
0039 
0040     static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
0041     static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0042 
0043     Map m;
0044 
0045     QMapData() = default;
0046     explicit QMapData(const Map &other)
0047         : m(other)
0048     {}
0049 
0050     explicit QMapData(Map &&other)
0051         : m(std::move(other))
0052     {}
0053 
0054     // used in remove(); copies from source all the values not matching key.
0055     // returns how many were NOT copied (removed).
0056     size_type copyIfNotEquivalentTo(const Map &source, const Key &key)
0057     {
0058         Q_ASSERT(m.empty());
0059 
0060         size_type result = 0;
0061 
0062         const auto keep = [this](auto it) { m.insert(m.cend(), *it); };
0063 
0064         auto it = source.cbegin();
0065         const auto end = source.cend();
0066         const auto &cmp = m.key_comp();
0067         // Keep all before:
0068         for (; it != end && cmp(it->first, key); ++it)
0069             keep(it);
0070         // Count and skip matches:
0071         for (; it != end && !cmp(key, it->first); ++it)
0072             ++result;
0073         // Keep all after:
0074         for (; it != end; ++it)
0075             keep(it);
0076 
0077         return result;
0078     }
0079 
0080     void copyExceptFor(const Map &source, const iterator &skipit)
0081     {
0082         Q_ASSERT(m.empty());
0083 
0084         auto it = source.cend();
0085         const auto end = source.cbegin();
0086         auto hint = m.end();
0087         if (it == end)
0088             return;
0089         do {
0090             --it;
0091             if (it == skipit)
0092                 continue;
0093             hint = m.emplace_hint(hint, it->first, it->second);
0094         } while (it != end);
0095     }
0096 
0097     // Merges the two sources into this one, giving preference to source2
0098     void fillWithMergeOf(const Map &source1, const Map &source2)
0099     {
0100         Q_ASSERT(m.empty());
0101 
0102         auto insertionHint = m.end();
0103         auto src1It = source1.crbegin();
0104         const auto src1End = source1.crend();
0105         auto src2It = source2.crbegin();
0106         const auto src2End = source2.crend();
0107         const auto &keyCompare = m.key_comp();
0108         while (src1It != src1End && src2It != src2End) {
0109             if (keyCompare(src2It->first, src1It->first)) {
0110                 insertionHint = m.emplace_hint(insertionHint, src1It->first, src1It->second);
0111                 ++src1It;
0112             } else if (keyCompare(src1It->first, src2It->first)) {
0113                 insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second);
0114                 ++src2It;
0115             } else {
0116                 // Equivalence, insert source2, forget source1
0117                 insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second);
0118                 ++src1It;
0119                 ++src2It;
0120             }
0121         }
0122         for (; src1It != src1End; ++src1It)
0123             insertionHint = m.emplace_hint(insertionHint, src1It->first, src1It->second);
0124         for (; src2It != src2End; ++src2It)
0125             insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second);
0126     }
0127 
0128     // Merge source into this one without changing source as std::map::merge would
0129     void insertMap(const Map &source)
0130     {
0131         Q_ASSERT(!m.empty());
0132         // copy in reverse order, trying to make effective use of insertionHint.
0133         auto insertionHint = m.end();
0134         auto it = source.crbegin();
0135         const auto end = source.crend();
0136         for (; it != end; ++it)
0137             insertionHint = m.emplace_hint(insertionHint, it->first, it->second);
0138     }
0139 
0140     // used in key(T), count(Key, T), find(key, T), etc; returns a
0141     // comparator object suitable for algorithms with std::(multi)map
0142     // iterators.
0143     static auto valueIsEqualTo(const T &value)
0144     {
0145         return [&value](const auto &v) { return v.second == value; };
0146     }
0147 
0148     Key key(const T &value, const Key &defaultKey) const
0149     {
0150         auto i = std::find_if(m.cbegin(),
0151                               m.cend(),
0152                               valueIsEqualTo(value));
0153         if (i != m.cend())
0154             return i->first;
0155 
0156         return defaultKey;
0157     }
0158 
0159     QList<Key> keys() const
0160     {
0161         QList<Key> result;
0162         result.reserve(m.size());
0163 
0164         const auto extractKey = [](const auto &v) { return v.first; };
0165 
0166         std::transform(m.cbegin(),
0167                        m.cend(),
0168                        std::back_inserter(result),
0169                        extractKey);
0170         return result;
0171     }
0172 
0173     QList<Key> keys(const T &value) const
0174     {
0175         QList<Key> result;
0176         result.reserve(m.size());
0177         // no std::transform_if...
0178         for (const auto &v : m) {
0179             if (v.second == value)
0180                 result.append(v.first);
0181         }
0182         result.shrink_to_fit();
0183         return result;
0184     }
0185 
0186     QList<T> values() const
0187     {
0188         QList<T> result;
0189         result.reserve(m.size());
0190 
0191         const auto extractValue = [](const auto &v) { return v.second; };
0192 
0193         std::transform(m.cbegin(),
0194                        m.cend(),
0195                        std::back_inserter(result),
0196                        extractValue);
0197         return result;
0198     }
0199 
0200     size_type count(const Key &key) const
0201     {
0202         return m.count(key);
0203     }
0204 
0205     // Used in erase. Allocates a new QMapData and copies, from this->m,
0206     // the elements not in the [first, last) range. The return contains
0207     // the new QMapData and an iterator in its map pointing at the first
0208     // element after the erase.
0209     struct EraseResult {
0210         QMapData *data;
0211         iterator it;
0212     };
0213 
0214     EraseResult erase(const_iterator first, const_iterator last) const
0215     {
0216         EraseResult result;
0217         result.data = new QMapData;
0218         result.it = result.data->m.end();
0219         const auto newDataEnd = result.it;
0220 
0221         auto i = m.begin();
0222         const auto e = m.end();
0223 
0224         // copy over all the elements before first
0225         while (i != first) {
0226             result.it = result.data->m.insert(newDataEnd, *i);
0227             ++i;
0228         }
0229 
0230         // skip until last
0231         while (i != last)
0232             ++i;
0233 
0234         // copy from last to the end
0235         while (i != e) {
0236             result.data->m.insert(newDataEnd, *i);
0237             ++i;
0238         }
0239 
0240         if (result.it != newDataEnd)
0241             ++result.it;
0242 
0243         return result;
0244     }
0245 };
0246 
0247 //
0248 // QMap
0249 //
0250 
0251 template <class Key, class T>
0252 class QMap
0253 {
0254     using Map = std::map<Key, T>;
0255     using MapData = QMapData<Map>;
0256     QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
0257 
0258     friend class QMultiMap<Key, T>;
0259 
0260 public:
0261     using key_type = Key;
0262     using mapped_type = T;
0263     using difference_type = qptrdiff;
0264     using size_type = qsizetype;
0265 
0266     QMap() = default;
0267 
0268     // implicitly generated special member functions are OK!
0269 
0270     void swap(QMap<Key, T> &other) noexcept
0271     {
0272         d.swap(other.d);
0273     }
0274 
0275     QMap(std::initializer_list<std::pair<Key, T>> list)
0276     {
0277         for (auto &p : list)
0278             insert(p.first, p.second);
0279     }
0280 
0281     explicit QMap(const std::map<Key, T> &other)
0282         : d(other.empty() ? nullptr : new MapData(other))
0283     {
0284     }
0285 
0286     explicit QMap(std::map<Key, T> &&other)
0287         : d(other.empty() ? nullptr : new MapData(std::move(other)))
0288     {
0289     }
0290 
0291     std::map<Key, T> toStdMap() const &
0292     {
0293         if (d)
0294             return d->m;
0295         return {};
0296     }
0297 
0298     std::map<Key, T> toStdMap() &&
0299     {
0300         if (d) {
0301             if (d.isShared())
0302                 return d->m;
0303             else
0304                 return std::move(d->m);
0305         }
0306 
0307         return {};
0308     }
0309 
0310 #ifndef Q_QDOC
0311 private:
0312     template <typename AKey = Key, typename AT = T,
0313               QTypeTraits::compare_eq_result_container<QMap, AKey, AT> = true>
0314     friend bool comparesEqual(const QMap &lhs, const QMap &rhs)
0315     {
0316         if (lhs.d == rhs.d)
0317             return true;
0318         if (!lhs.d)
0319             return rhs == lhs;
0320         Q_ASSERT(lhs.d);
0321         return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
0322     }
0323     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMap, QMap, /* non-constexpr */, noexcept(false),
0324                         template <typename AKey = Key, typename AT = T,
0325                                   QTypeTraits::compare_eq_result_container<QMap, AKey, AT> = true>)
0326     // TODO: add the other comparison operators; std::map has them.
0327 public:
0328 #else
0329     friend bool operator==(const QMap &lhs, const QMap &rhs);
0330     friend bool operator!=(const QMap &lhs, const QMap &rhs);
0331 #endif // Q_QDOC
0332 
0333     size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
0334 
0335     [[nodiscard]]
0336     bool isEmpty() const { return d ? d->m.empty() : true; }
0337 
0338     void detach()
0339     {
0340         if (d)
0341             d.detach();
0342         else
0343             d.reset(new MapData);
0344     }
0345 
0346     // A detach for holding an already shared copy, until calling function
0347     // is done using references to keys or values that might reference it.
0348     QMap referenceHoldingDetach()
0349     {
0350         if (!d) {
0351             d.reset(new MapData);
0352         } else if (d.isShared()) {
0353             auto hold = *this;
0354             d.detach();
0355             return hold;
0356         }
0357         return {};
0358     }
0359 
0360     // Specialized version of referenceHoldingDetach(), which will not copy key, if copying
0361     QMap referenceHoldingDetachExcept(const Key &key)
0362     {
0363         if (!d) {
0364             d.reset(new MapData);
0365         } else if (d.isShared()) {
0366             auto hold = *this;
0367             QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
0368             newData->copyIfNotEquivalentTo(d->m, key);
0369             d.swap(newData);
0370             return hold;
0371         }
0372         return {};
0373     }
0374 
0375     bool isDetached() const noexcept
0376     {
0377         return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
0378     }
0379 
0380     bool isSharedWith(const QMap<Key, T> &other) const noexcept
0381     {
0382         return d == other.d; // also this makes little sense?
0383     }
0384 
0385     void clear()
0386     {
0387         if (!d)
0388             return;
0389 
0390         if (!d.isShared())
0391             d->m.clear();
0392         else
0393             d.reset();
0394     }
0395 
0396     size_type remove(const Key &key)
0397     {
0398         if (!d)
0399             return 0;
0400 
0401         if (!d.isShared())
0402             return size_type(d->m.erase(key));
0403 
0404         MapData *newData = new MapData;
0405         size_type result = newData->copyIfNotEquivalentTo(d->m, key);
0406 
0407         d.reset(newData);
0408 
0409         return result;
0410     }
0411 
0412     template <typename Predicate>
0413     size_type removeIf(Predicate pred)
0414     {
0415         return QtPrivate::associative_erase_if(*this, pred);
0416     }
0417 
0418     T take(const Key &key)
0419     {
0420         if (!d)
0421             return T();
0422 
0423         if (d.isShared()) {
0424             Map m;
0425             // For historic reasons, we always un-share (was: detach()) when
0426             // this function is called, even if `key` isn't found
0427             const auto commit = qScopeGuard([&] { QMap{std::move(m)}.swap(*this); });
0428 
0429             // This way of copying ought to be O(N) (not NlogN) and not causing
0430             // any rebalancings in `m`, because we build in-order and with hint
0431             // [[citation needed]].
0432 
0433             const auto keep = [&m] (auto it) { m.insert(m.cend(), *it); };
0434 
0435             auto it = d->m.cbegin();
0436             const auto end = d->m.cend();
0437             const auto cmp = d->m.key_comp();
0438             while (it != end) {
0439                 if (cmp(it->first, key)) { // still before
0440                     keep(it);
0441                     ++it;
0442                 } else if (cmp(key, it->first)) { // after, iow: not found
0443                     // This should be faster than an actual range-insert, because
0444                     // the latter cannot assume that the input is sorted; we can:
0445                     while (it != end) {
0446                         keep(it);
0447                         ++it;
0448                     }
0449                     break;
0450                 } else { // found!
0451                     return [&] {
0452                         T r = it->second; // we cannot move (isShared()!)
0453                         while (++it != end)
0454                             keep(it);
0455                         return r;
0456                     }();
0457                 }
0458             }
0459             // if we reach here, `key` wasn't found:
0460             return T();
0461         }
0462 
0463 #ifdef __cpp_lib_node_extract
0464         if (const auto node = d->m.extract(key))
0465             return std::move(node.mapped());
0466 #else
0467         auto i = d->m.find(key);
0468         if (i != d->m.end()) {
0469             // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
0470             T result(std::move(i->second));
0471             d->m.erase(i);
0472             return result;
0473         }
0474 #endif
0475         return T();
0476     }
0477 
0478     bool contains(const Key &key) const
0479     {
0480         if (!d)
0481             return false;
0482         auto i = d->m.find(key);
0483         return i != d->m.end();
0484     }
0485 
0486     Key key(const T &value, const Key &defaultKey = Key()) const
0487     {
0488         if (!d)
0489             return defaultKey;
0490 
0491         return d->key(value, defaultKey);
0492     }
0493 
0494     T value(const Key &key, const T &defaultValue = T()) const
0495     {
0496         if (!d)
0497             return defaultValue;
0498         const auto i = d->m.find(key);
0499         if (i != d->m.cend())
0500             return i->second;
0501         return defaultValue;
0502     }
0503 
0504     T &operator[](const Key &key)
0505     {
0506         const auto hold = referenceHoldingDetach();
0507         auto i = d->m.find(key);
0508         if (i == d->m.end())
0509             i = d->m.insert({key, T()}).first;
0510         return i->second;
0511     }
0512 
0513     // CHANGE: return T, not const T!
0514     T operator[](const Key &key) const
0515     {
0516         return value(key);
0517     }
0518 
0519     QList<Key> keys() const
0520     {
0521         if (!d)
0522             return {};
0523         return d->keys();
0524     }
0525 
0526     QList<Key> keys(const T &value) const
0527     {
0528         if (!d)
0529             return {};
0530         return d->keys(value);
0531     }
0532 
0533     QList<T> values() const
0534     {
0535         if (!d)
0536             return {};
0537         return d->values();
0538     }
0539 
0540     size_type count(const Key &key) const
0541     {
0542         if (!d)
0543             return 0;
0544         return d->count(key);
0545     }
0546 
0547     size_type count() const
0548     {
0549         return size();
0550     }
0551 
0552     inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
0553     inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return (--constEnd()).key(); }
0554 
0555     inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
0556     inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
0557     inline T &last() { Q_ASSERT(!isEmpty()); return *(--end()); }
0558     inline const T &last() const { Q_ASSERT(!isEmpty()); return *(--constEnd()); }
0559 
0560     class const_iterator;
0561 
0562     class iterator
0563     {
0564         friend class QMap<Key, T>;
0565         friend class const_iterator;
0566 
0567         typename Map::iterator i;
0568         explicit iterator(typename Map::iterator it) : i(it) {}
0569     public:
0570         using iterator_category = std::bidirectional_iterator_tag;
0571         using difference_type = qptrdiff;
0572         using value_type = T;
0573         using pointer = T *;
0574         using reference = T &;
0575 
0576         iterator() = default;
0577 
0578         const Key &key() const { return i->first; }
0579         T &value() const { return i->second; }
0580         T &operator*() const { return i->second; }
0581         T *operator->() const { return &i->second; }
0582         friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
0583         friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
0584 
0585         iterator &operator++()
0586         {
0587             ++i;
0588             return *this;
0589         }
0590         iterator operator++(int)
0591         {
0592             iterator r = *this;
0593             ++i;
0594             return r;
0595         }
0596         iterator &operator--()
0597         {
0598             --i;
0599             return *this;
0600         }
0601         iterator operator--(int)
0602         {
0603             iterator r = *this;
0604             --i;
0605             return r;
0606         }
0607 
0608 #if QT_DEPRECATED_SINCE(6, 0)
0609         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
0610         //! [qmap-op-it-plus-step]
0611         friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
0612 
0613         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
0614         //! [qmap-op-it-minus-step]
0615         friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
0616 
0617         QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
0618         iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
0619 
0620         QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
0621         iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
0622 
0623         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
0624         //! [qmap-op-step-plus-it]
0625         friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
0626 
0627         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
0628         //! [qmap-op-step-minus-it]
0629         friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
0630 #endif
0631     };
0632 
0633     class const_iterator
0634     {
0635         friend class QMap<Key, T>;
0636         typename Map::const_iterator i;
0637         explicit const_iterator(typename Map::const_iterator it) : i(it) {}
0638 
0639     public:
0640         using iterator_category = std::bidirectional_iterator_tag;
0641         using difference_type = qptrdiff;
0642         using value_type = T;
0643         using pointer = const T *;
0644         using reference = const T &;
0645 
0646         const_iterator() = default;
0647         Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
0648 
0649         const Key &key() const { return i->first; }
0650         const T &value() const { return i->second; }
0651         const T &operator*() const { return i->second; }
0652         const T *operator->() const { return &i->second; }
0653         friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
0654         friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
0655 
0656         const_iterator &operator++()
0657         {
0658             ++i;
0659             return *this;
0660         }
0661         const_iterator operator++(int)
0662         {
0663             const_iterator r = *this;
0664             ++i;
0665             return r;
0666         }
0667         const_iterator &operator--()
0668         {
0669             --i;
0670             return *this;
0671         }
0672         const_iterator operator--(int)
0673         {
0674             const_iterator r = *this;
0675             --i;
0676             return r;
0677         }
0678 
0679 #if QT_DEPRECATED_SINCE(6, 0)
0680         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
0681         //! [qmap-op-it-plus-step-const]
0682         friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
0683 
0684         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
0685         //! [qmap-op-it-minus-step-const]
0686         friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
0687 
0688         QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
0689         const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
0690 
0691         QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
0692         const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
0693 
0694         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
0695         //! [qmap-op-step-plus-it-const]
0696         friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
0697 
0698         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
0699         //! [qmap-op-step-minus-it-const]
0700         friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
0701 #endif
0702     };
0703 
0704     class key_iterator
0705     {
0706         const_iterator i;
0707 
0708     public:
0709         typedef typename const_iterator::iterator_category iterator_category;
0710         typedef typename const_iterator::difference_type difference_type;
0711         typedef Key value_type;
0712         typedef const Key *pointer;
0713         typedef const Key &reference;
0714 
0715         key_iterator() = default;
0716         explicit key_iterator(const_iterator o) : i(o) { }
0717 
0718         const Key &operator*() const { return i.key(); }
0719         const Key *operator->() const { return &i.key(); }
0720         bool operator==(key_iterator o) const { return i == o.i; }
0721         bool operator!=(key_iterator o) const { return i != o.i; }
0722 
0723         inline key_iterator &operator++() { ++i; return *this; }
0724         inline key_iterator operator++(int) { return key_iterator(i++);}
0725         inline key_iterator &operator--() { --i; return *this; }
0726         inline key_iterator operator--(int) { return key_iterator(i--); }
0727         const_iterator base() const { return i; }
0728     };
0729 
0730     typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
0731     typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
0732 
0733     // STL style
0734     iterator begin() { detach(); return iterator(d->m.begin()); }
0735     const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
0736     const_iterator constBegin() const { return begin(); }
0737     const_iterator cbegin() const { return begin(); }
0738     iterator end() { detach(); return iterator(d->m.end()); }
0739     const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
0740     const_iterator constEnd() const { return end(); }
0741     const_iterator cend() const { return end(); }
0742     key_iterator keyBegin() const { return key_iterator(begin()); }
0743     key_iterator keyEnd() const { return key_iterator(end()); }
0744     key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
0745     key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
0746     const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
0747     const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
0748     const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
0749     const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
0750     auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMap &>(*this); }
0751     auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMap &>(*this); }
0752     auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMap>(std::move(*this)); }
0753     auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMap>(std::move(*this)); }
0754 
0755     iterator erase(const_iterator it)
0756     {
0757         return erase(it, std::next(it));
0758     }
0759 
0760     iterator erase(const_iterator afirst, const_iterator alast)
0761     {
0762         if (!d)
0763             return iterator();
0764 
0765         if (!d.isShared())
0766             return iterator(d->m.erase(afirst.i, alast.i));
0767 
0768         auto result = d->erase(afirst.i, alast.i);
0769         d.reset(result.data);
0770         return iterator(result.it);
0771     }
0772 
0773     // more Qt
0774     typedef iterator Iterator;
0775     typedef const_iterator ConstIterator;
0776 
0777     iterator find(const Key &key)
0778     {
0779         const auto hold = referenceHoldingDetach();
0780         return iterator(d->m.find(key));
0781     }
0782 
0783     const_iterator find(const Key &key) const
0784     {
0785         if (!d)
0786             return const_iterator();
0787         return const_iterator(d->m.find(key));
0788     }
0789 
0790     const_iterator constFind(const Key &key) const
0791     {
0792         return find(key);
0793     }
0794 
0795     iterator lowerBound(const Key &key)
0796     {
0797         const auto hold = referenceHoldingDetach();
0798         return iterator(d->m.lower_bound(key));
0799     }
0800 
0801     const_iterator lowerBound(const Key &key) const
0802     {
0803         if (!d)
0804             return const_iterator();
0805         return const_iterator(d->m.lower_bound(key));
0806     }
0807 
0808     iterator upperBound(const Key &key)
0809     {
0810         const auto hold = referenceHoldingDetach();
0811         return iterator(d->m.upper_bound(key));
0812     }
0813 
0814     const_iterator upperBound(const Key &key) const
0815     {
0816         if (!d)
0817             return const_iterator();
0818         return const_iterator(d->m.upper_bound(key));
0819     }
0820 
0821     iterator insert(const Key &key, const T &value)
0822     {
0823         const auto hold = referenceHoldingDetachExcept(key);
0824         return iterator(d->m.insert_or_assign(key, value).first);
0825     }
0826 
0827     iterator insert(const_iterator pos, const Key &key, const T &value)
0828     {
0829         if (!d) {
0830             detach();
0831             return iterator(d->m.emplace(key, value).first);
0832         } else if (d.isShared()) {
0833             auto posDistance = std::distance(d->m.cbegin(), pos.i);
0834             const auto hold = referenceHoldingDetachExcept(key);
0835             auto dpos = std::next(d->m.cbegin(), posDistance);
0836             return iterator(d->m.insert_or_assign(dpos, key, value));
0837         }
0838         return iterator(d->m.insert_or_assign(pos.i, key, value));
0839     }
0840 
0841     void insert(const QMap<Key, T> &map)
0842     {
0843         if (map.isEmpty())
0844             return;
0845 
0846         if (isEmpty()) {
0847             *this = map;
0848             return;
0849         }
0850 
0851         if (d.isShared()) {
0852             QtPrivate::QExplicitlySharedDataPointerV2<MapData> newD(new MapData);
0853             const auto commit = qScopeGuard([&] { newD.swap(d); });
0854             newD->fillWithMergeOf(d->m, map.d->m);
0855             return;
0856         }
0857 
0858 #ifdef __cpp_lib_node_extract
0859         // Since std::map::merge is destructive only use it when not shared
0860         auto copy = map.d->m;
0861         copy.merge(d->m);
0862         d->m = std::move(copy);
0863 #else
0864         QtPrivate::QExplicitlySharedDataPointerV2<MapData> newD(new MapData);
0865         const auto commit = qScopeGuard([&] { newD.swap(d); });
0866         newD->fillWithMergeOf(d->m, map.d->m);
0867 
0868 #endif
0869     }
0870 
0871     void insert(QMap<Key, T> &&map)
0872     {
0873         if (map.isEmpty() || map.d.isShared()) {
0874             // fall back to a regular copy
0875             insert(map);
0876             return;
0877         }
0878 
0879         // Otherwise insert into map, and do a swap on return
0880         const auto commit = qScopeGuard([&] { map.swap(*this); });
0881         if (isEmpty())
0882             return;
0883 
0884         if (d.isShared()) {
0885             map.d->insertMap(d->m);
0886             return;
0887         }
0888 
0889 #ifdef __cpp_lib_node_extract
0890         map.d->m.merge(std::move(d->m));
0891 #else
0892         // same as above
0893         map.d->insertMap(d->m);
0894 #endif
0895     }
0896 
0897     // STL compatibility
0898     [[nodiscard]]
0899     inline bool empty() const
0900     {
0901         return isEmpty();
0902     }
0903 
0904     std::pair<iterator, iterator> equal_range(const Key &akey)
0905     {
0906         const auto hold = referenceHoldingDetach();
0907         auto result = d->m.equal_range(akey);
0908         return {iterator(result.first), iterator(result.second)};
0909     }
0910 
0911     std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
0912     {
0913         if (!d)
0914             return {};
0915         auto result = d->m.equal_range(akey);
0916         return {const_iterator(result.first), const_iterator(result.second)};
0917     }
0918 
0919 private:
0920 #ifdef Q_QDOC
0921     friend size_t qHash(const QMap &key, size_t seed = 0);
0922 #else
0923 # if defined(Q_CC_GHS) || defined (Q_CC_MSVC)
0924     // GHS and MSVC tries to intantiate qHash() for the noexcept running into a
0925     // non-SFINAE'ed hard error... Create an artificial SFINAE context as a
0926     // work-around:
0927     template <typename M, std::enable_if_t<std::is_same_v<M, QMap>, bool> = true>
0928     friend QtPrivate::QHashMultiReturnType<typename M::key_type, typename M::mapped_type>
0929 # else
0930     using M = QMap;
0931     friend size_t
0932 # endif
0933     qHash(const M &key, size_t seed = 0)
0934         noexcept(QHashPrivate::noexceptPairHash<typename M::key_type, typename M::mapped_type>())
0935     {
0936         if (!key.d)
0937             return seed;
0938         // don't use qHashRange to avoid its compile-time overhead:
0939         return std::accumulate(key.d->m.begin(), key.d->m.end(), seed,
0940                                QtPrivate::QHashCombine{seed});
0941     }
0942 #endif // !Q_QDOC
0943 };
0944 
0945 Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
0946 Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map)
0947 
0948 template <typename Key, typename T, typename Predicate>
0949 qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
0950 {
0951     return QtPrivate::associative_erase_if(map, pred);
0952 }
0953 
0954 
0955 //
0956 // QMultiMap
0957 //
0958 
0959 template <class Key, class T>
0960 class QMultiMap
0961 {
0962     using Map = std::multimap<Key, T>;
0963     using MapData = QMapData<Map>;
0964     QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
0965 
0966     // Note: methods that look up a single element by key use lower_bound() rather
0967     // than find(). The C++ standard permits std::multimap::find() to return any
0968     // element with the matching key; libc++ 22 changed which one it returns.
0969     // lower_bound() is where insert() places new elements, so it consistently
0970     // identifies the most-recently-inserted one.
0971 
0972     auto findIteratorByKey(const Key &key) const
0973     {
0974         auto i = d->m.lower_bound(key);
0975         const auto &cmp = d->m.key_comp();
0976         if (i != d->m.end() && !cmp(key, i->first))
0977             return i;
0978         return d->m.end();
0979     }
0980     auto findIteratorByKey(const Key &key)
0981     {
0982         auto i = d->m.lower_bound(key);
0983         const auto &cmp = d->m.key_comp();
0984         if (i != d->m.end() && !cmp(key, i->first))
0985             return i;
0986         return d->m.end();
0987     }
0988 
0989 public:
0990     using key_type = Key;
0991     using mapped_type = T;
0992     using difference_type = qptrdiff;
0993     using size_type = qsizetype;
0994 
0995     QMultiMap() = default;
0996 
0997     // implicitly generated special member functions are OK!
0998 
0999     QMultiMap(std::initializer_list<std::pair<Key,T>> list)
1000     {
1001         for (auto &p : list)
1002             insert(p.first, p.second);
1003     }
1004 
1005     void swap(QMultiMap<Key, T> &other) noexcept
1006     {
1007         d.swap(other.d);
1008     }
1009 
1010     explicit QMultiMap(const QMap<Key, T> &other)
1011         : d(other.isEmpty() ? nullptr : new MapData)
1012     {
1013         if (d) {
1014             Q_ASSERT(other.d);
1015             d->m.insert(other.d->m.begin(),
1016                         other.d->m.end());
1017         }
1018     }
1019 
1020     explicit QMultiMap(QMap<Key, T> &&other)
1021         : d(other.isEmpty() ? nullptr : new MapData)
1022     {
1023         if (d) {
1024             Q_ASSERT(other.d);
1025             if (other.d.isShared()) {
1026                 d->m.insert(other.d->m.begin(),
1027                             other.d->m.end());
1028             } else {
1029 #ifdef __cpp_lib_node_extract
1030                 d->m.merge(std::move(other.d->m));
1031 #else
1032                 d->m.insert(std::make_move_iterator(other.d->m.begin()),
1033                             std::make_move_iterator(other.d->m.end()));
1034 #endif
1035             }
1036         }
1037     }
1038 
1039     explicit QMultiMap(const std::multimap<Key, T> &other)
1040         : d(other.empty() ? nullptr : new MapData(other))
1041     {
1042     }
1043 
1044     explicit QMultiMap(std::multimap<Key, T> &&other)
1045         : d(other.empty() ? nullptr : new MapData(std::move(other)))
1046     {
1047     }
1048 
1049     // CHANGE: return type
1050     Q_DECL_DEPRECATED_X("Use toStdMultiMap instead")
1051     std::multimap<Key, T> toStdMap() const
1052     {
1053         return toStdMultiMap();
1054     }
1055 
1056     std::multimap<Key, T> toStdMultiMap() const &
1057     {
1058         if (d)
1059             return d->m;
1060         return {};
1061     }
1062 
1063     std::multimap<Key, T> toStdMultiMap() &&
1064     {
1065         if (d) {
1066             if (d.isShared())
1067                 return d->m;
1068             else
1069                 return std::move(d->m);
1070         }
1071 
1072         return {};
1073     }
1074 
1075 #ifndef Q_QDOC
1076 private:
1077     template <typename AKey = Key, typename AT = T,
1078               QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>
1079     friend bool comparesEqual(const QMultiMap &lhs, const QMultiMap &rhs)
1080     {
1081         if (lhs.d == rhs.d)
1082             return true;
1083         if (!lhs.d)
1084             return rhs == lhs;
1085         Q_ASSERT(lhs.d);
1086         return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
1087     }
1088     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1089                  template <typename AKey = Key, typename AT = T,
1090                            QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>)
1091     // TODO: add the other comparison operators; std::multimap has them.
1092 public:
1093 #else
1094     friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs);
1095     friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs);
1096 #endif // Q_QDOC
1097 
1098     size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
1099 
1100     [[nodiscard]]
1101     bool isEmpty() const { return d ? d->m.empty() : true; }
1102 
1103     void detach()
1104     {
1105         if (d)
1106             d.detach();
1107         else
1108             d.reset(new MapData);
1109     }
1110 
1111     // A detach for holding an already shared copy, until calling function
1112     // is done using references to keys or values that might reference it.
1113     [[nodiscard]] QMultiMap referenceHoldingDetach()
1114     {
1115         if (!d) {
1116             d.reset(new MapData);
1117         } else if (d.isShared()) {
1118             auto hold = *this;
1119             d.detach();
1120             return hold;
1121         }
1122         return {};
1123     }
1124 
1125     // Specialized version of referenceHoldingDetach(), which will not copy skipit, if copying
1126     [[nodiscard]] QMultiMap referenceHoldingDetachExceptFor(const typename Map::iterator &skipit)
1127     {
1128         Q_ASSERT(d.isShared());
1129         auto hold = *this;
1130         QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1131         newData->copyExceptFor(d->m, skipit);
1132         d.swap(newData);
1133         return hold;
1134     }
1135 
1136     bool isDetached() const noexcept
1137     {
1138         return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
1139     }
1140 
1141     bool isSharedWith(const QMultiMap<Key, T> &other) const noexcept
1142     {
1143         return d == other.d; // also this makes little sense?
1144     }
1145 
1146     void clear()
1147     {
1148         if (!d)
1149             return;
1150 
1151         if (!d.isShared())
1152             d->m.clear();
1153         else
1154             d.reset();
1155     }
1156 
1157     size_type remove(const Key &key)
1158     {
1159         if (!d)
1160             return 0;
1161 
1162         if (!d.isShared())
1163             return size_type(d->m.erase(key));
1164 
1165         MapData *newData = new MapData;
1166         size_type result = newData->copyIfNotEquivalentTo(d->m, key);
1167 
1168         d.reset(newData);
1169 
1170         return result;
1171     }
1172 
1173     size_type remove(const Key &key, const T &value)
1174     {
1175         if (!d)
1176             return 0;
1177 
1178         size_type result = 0;
1179         const auto &keyCompare = d->m.key_comp();
1180 
1181         if (d.isShared()) {
1182             QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1183             const auto keep = [&newData](auto it) { newData->m.insert(newData->m.cend(), *it); };
1184 
1185             auto it = d->m.cbegin();
1186             const auto end = d->m.cend();
1187             for (; it != end && keyCompare(it->first, key); ++it)
1188                 keep(it);
1189             // Keep matching keys if value match, otherwise skip and count
1190             for (; it != end && !keyCompare(key, it->first); ++it) {
1191                 if (!(it->second == value))
1192                     keep(it);
1193                 else
1194                     ++result;
1195             }
1196             for (; it != end; ++it)
1197                 keep(it);
1198 
1199             d.swap(newData);
1200             return result;
1201         }
1202 
1203         // d->m.erase_if(....) would be nice, but that's C++20.
1204         // So let's do like find(keyCopy, valueCopy):
1205         auto [i, e] = d->m.equal_range(key);
1206         if (i == e)
1207             return result;
1208 
1209         // value may belong to this map. As such, we need to copy it to ensure
1210         // it stays valid throughout the iteration below (which may destroy it)
1211         const T valueCopy = value;
1212         while (i != e) {
1213             if (i->second == valueCopy) {
1214                 i = d->m.erase(i);
1215                 ++result;
1216             } else {
1217                 ++i;
1218             }
1219         }
1220 
1221         return result;
1222     }
1223 
1224     template <typename Predicate>
1225     size_type removeIf(Predicate pred)
1226     {
1227         return QtPrivate::associative_erase_if(*this, pred);
1228     }
1229 
1230     T take(const Key &key)
1231     {
1232         if (!d)
1233             return T();
1234 
1235         auto i = findIteratorByKey(key);
1236         if (d.isShared()) {
1237             if (i == d->m.end()) {
1238                 // NB: take always detaches, even if the key isn't found. This is for historic reasons.
1239                 detach();
1240                 return T();
1241             }
1242             const auto hold = referenceHoldingDetachExceptFor(i);
1243             return i->second;
1244         }
1245 
1246         if (i == d->m.end())
1247             return T();
1248 
1249 #ifdef __cpp_lib_node_extract
1250         return d->m.extract(i).mapped();
1251 #else
1252         // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
1253         T result(std::move(i->second));
1254         d->m.erase(i);
1255         return result;
1256 #endif
1257     }
1258 
1259     bool contains(const Key &key) const
1260     {
1261         if (!d)
1262             return false;
1263         auto i = d->m.find(key);
1264         return i != d->m.end();
1265     }
1266 
1267     bool contains(const Key &key, const T &value) const
1268     {
1269         return find(key, value) != end();
1270     }
1271 
1272     Key key(const T &value, const Key &defaultKey = Key()) const
1273     {
1274         if (!d)
1275             return defaultKey;
1276 
1277         return d->key(value, defaultKey);
1278     }
1279 
1280     T value(const Key &key, const T &defaultValue = T()) const
1281     {
1282         if (!d)
1283             return defaultValue;
1284         auto i = findIteratorByKey(key);
1285         if (i != d->m.cend())
1286             return i->second;
1287         return defaultValue;
1288     }
1289 
1290     QList<Key> keys() const
1291     {
1292         if (!d)
1293             return {};
1294         return d->keys();
1295     }
1296 
1297     QList<Key> keys(const T &value) const
1298     {
1299         if (!d)
1300             return {};
1301         return d->keys(value);
1302     }
1303 
1304     QList<Key> uniqueKeys() const
1305     {
1306         QList<Key> result;
1307         if (!d)
1308             return result;
1309 
1310         result.reserve(size());
1311 
1312         std::unique_copy(keyBegin(), keyEnd(),
1313                          std::back_inserter(result));
1314 
1315         result.shrink_to_fit();
1316         return result;
1317     }
1318 
1319     QList<T> values() const
1320     {
1321         if (!d)
1322             return {};
1323         return d->values();
1324     }
1325 
1326     QList<T> values(const Key &key) const
1327     {
1328         QList<T> result;
1329         const auto range = equal_range(key);
1330         result.reserve(std::distance(range.first, range.second));
1331         std::copy(range.first, range.second, std::back_inserter(result));
1332         return result;
1333     }
1334 
1335     size_type count(const Key &key) const
1336     {
1337         if (!d)
1338             return 0;
1339         return d->count(key);
1340     }
1341 
1342     size_type count(const Key &key, const T &value) const
1343     {
1344         if (!d)
1345             return 0;
1346 
1347         // TODO: improve; no need of scanning the equal_range twice.
1348         auto range = d->m.equal_range(key);
1349 
1350         return size_type(std::count_if(range.first,
1351                                        range.second,
1352                                        MapData::valueIsEqualTo(value)));
1353     }
1354 
1355     inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
1356     inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return std::next(constEnd(), -1).key(); }
1357 
1358     inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
1359     inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
1360     inline T &last() { Q_ASSERT(!isEmpty()); return *std::next(end(), -1); }
1361     inline const T &last() const { Q_ASSERT(!isEmpty()); return *std::next(constEnd(), -1); }
1362 
1363     class const_iterator;
1364 
1365     class iterator
1366     {
1367         friend class QMultiMap<Key, T>;
1368         friend class const_iterator;
1369 
1370         typename Map::iterator i;
1371         explicit iterator(typename Map::iterator it) : i(it) {}
1372     public:
1373         using iterator_category = std::bidirectional_iterator_tag;
1374         using difference_type = qptrdiff;
1375         using value_type = T;
1376         using pointer = T *;
1377         using reference = T &;
1378 
1379         iterator() = default;
1380 
1381         const Key &key() const { return i->first; }
1382         T &value() const { return i->second; }
1383         T &operator*() const { return i->second; }
1384         T *operator->() const { return &i->second; }
1385         friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
1386         friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
1387 
1388         iterator &operator++()
1389         {
1390             ++i;
1391             return *this;
1392         }
1393         iterator operator++(int)
1394         {
1395             iterator r = *this;
1396             ++i;
1397             return r;
1398         }
1399         iterator &operator--()
1400         {
1401             --i;
1402             return *this;
1403         }
1404         iterator operator--(int)
1405         {
1406             iterator r = *this;
1407             --i;
1408             return r;
1409         }
1410 
1411 #if QT_DEPRECATED_SINCE(6, 0)
1412         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1413         //! [qmultimap-op-it-plus-step]
1414         friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
1415 
1416         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1417         //! [qmultimap-op-it-minus-step]
1418         friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
1419 
1420         QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1421         iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1422 
1423         QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1424         iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1425 
1426         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1427         //! [qmultimap-op-step-plus-it]
1428         friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
1429 
1430         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1431         //! [qmultimap-op-step-minus-it]
1432         friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
1433 #endif
1434     };
1435 
1436     class const_iterator
1437     {
1438         friend class QMultiMap<Key, T>;
1439         typename Map::const_iterator i;
1440         explicit const_iterator(typename Map::const_iterator it) : i(it) {}
1441 
1442     public:
1443         using iterator_category = std::bidirectional_iterator_tag;
1444         using difference_type = qptrdiff;
1445         using value_type = T;
1446         using pointer = const T *;
1447         using reference = const T &;
1448 
1449         const_iterator() = default;
1450         Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
1451 
1452         const Key &key() const { return i->first; }
1453         const T &value() const { return i->second; }
1454         const T &operator*() const { return i->second; }
1455         const T *operator->() const { return &i->second; }
1456         friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
1457         friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
1458 
1459         const_iterator &operator++()
1460         {
1461             ++i;
1462             return *this;
1463         }
1464         const_iterator operator++(int)
1465         {
1466             const_iterator r = *this;
1467             ++i;
1468             return r;
1469         }
1470         const_iterator &operator--()
1471         {
1472             --i;
1473             return *this;
1474         }
1475         const_iterator operator--(int)
1476         {
1477             const_iterator r = *this;
1478             --i;
1479             return r;
1480         }
1481 
1482 #if QT_DEPRECATED_SINCE(6, 0)
1483         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1484         //! [qmultimap-op-it-plus-step-const]
1485         friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
1486 
1487         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1488         //! [qmultimap-op-it-minus-step-const]
1489         friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
1490 
1491         QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1492         const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1493 
1494         QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1495         const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1496 
1497         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1498         //! [qmultimap-op-step-plus-it-const]
1499         friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
1500 
1501         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1502         //! [qmultimap-op-step-minus-it-const]
1503         friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
1504 #endif
1505     };
1506 
1507     class key_iterator
1508     {
1509         const_iterator i;
1510 
1511     public:
1512         typedef typename const_iterator::iterator_category iterator_category;
1513         typedef typename const_iterator::difference_type difference_type;
1514         typedef Key value_type;
1515         typedef const Key *pointer;
1516         typedef const Key &reference;
1517 
1518         key_iterator() = default;
1519         explicit key_iterator(const_iterator o) : i(o) { }
1520 
1521         const Key &operator*() const { return i.key(); }
1522         const Key *operator->() const { return &i.key(); }
1523         bool operator==(key_iterator o) const { return i == o.i; }
1524         bool operator!=(key_iterator o) const { return i != o.i; }
1525 
1526         inline key_iterator &operator++() { ++i; return *this; }
1527         inline key_iterator operator++(int) { return key_iterator(i++);}
1528         inline key_iterator &operator--() { --i; return *this; }
1529         inline key_iterator operator--(int) { return key_iterator(i--); }
1530         const_iterator base() const { return i; }
1531     };
1532 
1533     typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1534     typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1535 
1536     // STL style
1537     iterator begin() { detach(); return iterator(d->m.begin()); }
1538     const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
1539     const_iterator constBegin() const { return begin(); }
1540     const_iterator cbegin() const { return begin(); }
1541     iterator end() { detach(); return iterator(d->m.end()); }
1542     const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
1543     const_iterator constEnd() const { return end(); }
1544     const_iterator cend() const { return end(); }
1545     key_iterator keyBegin() const { return key_iterator(begin()); }
1546     key_iterator keyEnd() const { return key_iterator(end()); }
1547     key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
1548     key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
1549     const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
1550     const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
1551     const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
1552     const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
1553     auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMultiMap &>(*this); }
1554     auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMultiMap &>(*this); }
1555     auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1556     auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1557 
1558     iterator erase(const_iterator it)
1559     {
1560         return erase(it, std::next(it));
1561     }
1562 
1563     iterator erase(const_iterator afirst, const_iterator alast)
1564     {
1565         if (!d)
1566             return iterator();
1567 
1568         if (!d.isShared())
1569             return iterator(d->m.erase(afirst.i, alast.i));
1570 
1571         auto result = d->erase(afirst.i, alast.i);
1572         d.reset(result.data);
1573         return iterator(result.it);
1574     }
1575 
1576     // more Qt
1577     typedef iterator Iterator;
1578     typedef const_iterator ConstIterator;
1579 
1580     size_type count() const
1581     {
1582         return size();
1583     }
1584 
1585     iterator find(const Key &key)
1586     {
1587         const auto hold = referenceHoldingDetach();
1588         return iterator(findIteratorByKey(key));
1589     }
1590 
1591     const_iterator find(const Key &key) const
1592     {
1593         if (!d)
1594             return const_iterator();
1595         return const_iterator(findIteratorByKey(key));
1596     }
1597 
1598     const_iterator constFind(const Key &key) const
1599     {
1600         return find(key);
1601     }
1602 
1603     iterator find(const Key &key, const T &value)
1604     {
1605         const auto hold = referenceHoldingDetach();
1606 
1607         auto range = d->m.equal_range(key);
1608         auto i = std::find_if(range.first, range.second,
1609                               MapData::valueIsEqualTo(value));
1610 
1611         if (i != range.second)
1612             return iterator(i);
1613         return iterator(d->m.end());
1614     }
1615 
1616     const_iterator find(const Key &key, const T &value) const
1617     {
1618         if (!d)
1619             return const_iterator();
1620 
1621         auto range = d->m.equal_range(key);
1622         auto i = std::find_if(range.first, range.second,
1623                               MapData::valueIsEqualTo(value));
1624 
1625         if (i != range.second)
1626             return const_iterator(i);
1627         return const_iterator(d->m.end());
1628     }
1629 
1630     const_iterator constFind(const Key &key, const T &value) const
1631     {
1632         return find(key, value);
1633     }
1634 
1635     iterator lowerBound(const Key &key)
1636     {
1637         const auto hold = referenceHoldingDetach();
1638         return iterator(d->m.lower_bound(key));
1639     }
1640 
1641     const_iterator lowerBound(const Key &key) const
1642     {
1643         if (!d)
1644             return const_iterator();
1645         return const_iterator(d->m.lower_bound(key));
1646     }
1647 
1648     iterator upperBound(const Key &key)
1649     {
1650         const auto hold = referenceHoldingDetach();
1651         return iterator(d->m.upper_bound(key));
1652     }
1653 
1654     const_iterator upperBound(const Key &key) const
1655     {
1656         if (!d)
1657             return const_iterator();
1658         return const_iterator(d->m.upper_bound(key));
1659     }
1660 
1661     iterator insert(const Key &key, const T &value)
1662     {
1663         const auto hold = referenceHoldingDetach();
1664         // note that std::multimap inserts at the end of an equal_range for a key,
1665         // QMultiMap at the beginning.
1666         auto i = d->m.lower_bound(key);
1667         return iterator(d->m.insert(i, {key, value}));
1668     }
1669 
1670     iterator insert(const_iterator pos, const Key &key, const T &value)
1671     {
1672         if (!d) {
1673             d.reset(new MapData);
1674             return iterator(d->m.insert({ key, value }));
1675         } else if (d.isShared()) {
1676             auto posDistance = std::distance(d->m.cbegin(), pos.i);
1677             auto hold = referenceHoldingDetach();
1678             auto dpos = std::next(d->m.cbegin(), posDistance);
1679             return iterator(d->m.insert(dpos, {key, value}));
1680         }
1681 
1682         return iterator(d->m.insert(pos.i, {key, value}));
1683     }
1684 
1685 #if QT_DEPRECATED_SINCE(6, 0)
1686     QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1687     iterator insertMulti(const Key &key, const T &value)
1688     {
1689         return insert(key, value);
1690     }
1691     QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1692     iterator insertMulti(const_iterator pos, const Key &key, const T &value)
1693     {
1694         return insert(pos, key, value);
1695     }
1696 
1697     QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1698     void insert(const QMultiMap<Key, T> &map)
1699     {
1700         unite(map);
1701     }
1702 
1703     QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1704     void insert(QMultiMap<Key, T> &&map)
1705     {
1706         unite(std::move(map));
1707     }
1708 #endif
1709 
1710     iterator replace(const Key &key, const T &value)
1711     {
1712         if (!d) {
1713             d.reset(new MapData);
1714             return iterator(d->m.insert({ key, value }));
1715         }
1716         auto i = findIteratorByKey(key);
1717         if (d.isShared()) {
1718             const auto hold = referenceHoldingDetachExceptFor(i);
1719             return iterator(d->m.insert({ key, value }));
1720         }
1721 
1722         // Similarly, improve here (e.g. lower_bound and hinted insert);
1723         // there's no insert_or_assign on multimaps
1724         if (i != d->m.end())
1725             i->second = value;
1726         else
1727             i = d->m.insert({key, value});
1728 
1729         return iterator(i);
1730     }
1731 
1732     // STL compatibility
1733     [[nodiscard]]
1734     inline bool empty() const { return isEmpty(); }
1735 
1736     std::pair<iterator, iterator> equal_range(const Key &akey)
1737     {
1738         const auto hold = referenceHoldingDetach();
1739         auto result = d->m.equal_range(akey);
1740         return {iterator(result.first), iterator(result.second)};
1741     }
1742 
1743     std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
1744     {
1745         if (!d)
1746             return {};
1747         auto result = d->m.equal_range(akey);
1748         return {const_iterator(result.first), const_iterator(result.second)};
1749     }
1750 
1751     QMultiMap &unite(const QMultiMap &other)
1752     {
1753         if (other.isEmpty())
1754             return *this;
1755 
1756         detach();
1757 
1758         auto copy = other.d->m;
1759 #ifdef __cpp_lib_node_extract
1760         copy.merge(std::move(d->m));
1761 #else
1762         copy.insert(std::make_move_iterator(d->m.begin()),
1763                     std::make_move_iterator(d->m.end()));
1764 #endif
1765         d->m = std::move(copy);
1766         return *this;
1767     }
1768 
1769     QMultiMap &unite(QMultiMap<Key, T> &&other)
1770     {
1771         if (!other.d || other.d->m.empty())
1772             return *this;
1773 
1774         if (other.d.isShared()) {
1775             // fall back to a regular copy
1776             unite(other);
1777             return *this;
1778         }
1779 
1780         detach();
1781 
1782 #ifdef __cpp_lib_node_extract
1783         other.d->m.merge(std::move(d->m));
1784 #else
1785         other.d->m.insert(std::make_move_iterator(d->m.begin()),
1786                           std::make_move_iterator(d->m.end()));
1787 #endif
1788         *this = std::move(other);
1789         return *this;
1790     }
1791 };
1792 
1793 Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap)
1794 Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap)
1795 
1796 template <typename Key, typename T>
1797 QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1798 {
1799     auto result = lhs;
1800     result += rhs;
1801     return result;
1802 }
1803 
1804 template <typename Key, typename T>
1805 QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1806 {
1807     return lhs.unite(rhs);
1808 }
1809 
1810 template <typename Key, typename T, typename Predicate>
1811 qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
1812 {
1813     return QtPrivate::associative_erase_if(map, pred);
1814 }
1815 
1816 QT_END_NAMESPACE
1817 
1818 #endif // QMAP_H