Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-02 09:27:15

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 public:
0967     using key_type = Key;
0968     using mapped_type = T;
0969     using difference_type = qptrdiff;
0970     using size_type = qsizetype;
0971 
0972     QMultiMap() = default;
0973 
0974     // implicitly generated special member functions are OK!
0975 
0976     QMultiMap(std::initializer_list<std::pair<Key,T>> list)
0977     {
0978         for (auto &p : list)
0979             insert(p.first, p.second);
0980     }
0981 
0982     void swap(QMultiMap<Key, T> &other) noexcept
0983     {
0984         d.swap(other.d);
0985     }
0986 
0987     explicit QMultiMap(const QMap<Key, T> &other)
0988         : d(other.isEmpty() ? nullptr : new MapData)
0989     {
0990         if (d) {
0991             Q_ASSERT(other.d);
0992             d->m.insert(other.d->m.begin(),
0993                         other.d->m.end());
0994         }
0995     }
0996 
0997     explicit QMultiMap(QMap<Key, T> &&other)
0998         : d(other.isEmpty() ? nullptr : new MapData)
0999     {
1000         if (d) {
1001             Q_ASSERT(other.d);
1002             if (other.d.isShared()) {
1003                 d->m.insert(other.d->m.begin(),
1004                             other.d->m.end());
1005             } else {
1006 #ifdef __cpp_lib_node_extract
1007                 d->m.merge(std::move(other.d->m));
1008 #else
1009                 d->m.insert(std::make_move_iterator(other.d->m.begin()),
1010                             std::make_move_iterator(other.d->m.end()));
1011 #endif
1012             }
1013         }
1014     }
1015 
1016     explicit QMultiMap(const std::multimap<Key, T> &other)
1017         : d(other.empty() ? nullptr : new MapData(other))
1018     {
1019     }
1020 
1021     explicit QMultiMap(std::multimap<Key, T> &&other)
1022         : d(other.empty() ? nullptr : new MapData(std::move(other)))
1023     {
1024     }
1025 
1026     // CHANGE: return type
1027     Q_DECL_DEPRECATED_X("Use toStdMultiMap instead")
1028     std::multimap<Key, T> toStdMap() const
1029     {
1030         return toStdMultiMap();
1031     }
1032 
1033     std::multimap<Key, T> toStdMultiMap() const &
1034     {
1035         if (d)
1036             return d->m;
1037         return {};
1038     }
1039 
1040     std::multimap<Key, T> toStdMultiMap() &&
1041     {
1042         if (d) {
1043             if (d.isShared())
1044                 return d->m;
1045             else
1046                 return std::move(d->m);
1047         }
1048 
1049         return {};
1050     }
1051 
1052 #ifndef Q_QDOC
1053 private:
1054     template <typename AKey = Key, typename AT = T,
1055               QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>
1056     friend bool comparesEqual(const QMultiMap &lhs, const QMultiMap &rhs)
1057     {
1058         if (lhs.d == rhs.d)
1059             return true;
1060         if (!lhs.d)
1061             return rhs == lhs;
1062         Q_ASSERT(lhs.d);
1063         return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
1064     }
1065     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1066                  template <typename AKey = Key, typename AT = T,
1067                            QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>)
1068     // TODO: add the other comparison operators; std::multimap has them.
1069 public:
1070 #else
1071     friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs);
1072     friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs);
1073 #endif // Q_QDOC
1074 
1075     size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
1076 
1077     [[nodiscard]]
1078     bool isEmpty() const { return d ? d->m.empty() : true; }
1079 
1080     void detach()
1081     {
1082         if (d)
1083             d.detach();
1084         else
1085             d.reset(new MapData);
1086     }
1087 
1088     // A detach for holding an already shared copy, until calling function
1089     // is done using references to keys or values that might reference it.
1090     [[nodiscard]] QMultiMap referenceHoldingDetach()
1091     {
1092         if (!d) {
1093             d.reset(new MapData);
1094         } else if (d.isShared()) {
1095             auto hold = *this;
1096             d.detach();
1097             return hold;
1098         }
1099         return {};
1100     }
1101 
1102     // Specialized version of referenceHoldingDetach(), which will not copy skipit, if copying
1103     [[nodiscard]] QMultiMap referenceHoldingDetachExceptFor(const typename Map::iterator &skipit)
1104     {
1105         Q_ASSERT(d.isShared());
1106         auto hold = *this;
1107         QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1108         newData->copyExceptFor(d->m, skipit);
1109         d.swap(newData);
1110         return hold;
1111     }
1112 
1113     bool isDetached() const noexcept
1114     {
1115         return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
1116     }
1117 
1118     bool isSharedWith(const QMultiMap<Key, T> &other) const noexcept
1119     {
1120         return d == other.d; // also this makes little sense?
1121     }
1122 
1123     void clear()
1124     {
1125         if (!d)
1126             return;
1127 
1128         if (!d.isShared())
1129             d->m.clear();
1130         else
1131             d.reset();
1132     }
1133 
1134     size_type remove(const Key &key)
1135     {
1136         if (!d)
1137             return 0;
1138 
1139         if (!d.isShared())
1140             return size_type(d->m.erase(key));
1141 
1142         MapData *newData = new MapData;
1143         size_type result = newData->copyIfNotEquivalentTo(d->m, key);
1144 
1145         d.reset(newData);
1146 
1147         return result;
1148     }
1149 
1150     size_type remove(const Key &key, const T &value)
1151     {
1152         if (!d)
1153             return 0;
1154 
1155         size_type result = 0;
1156         const auto &keyCompare = d->m.key_comp();
1157 
1158         if (d.isShared()) {
1159             QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1160             const auto keep = [&newData](auto it) { newData->m.insert(newData->m.cend(), *it); };
1161 
1162             auto it = d->m.cbegin();
1163             const auto end = d->m.cend();
1164             for (; it != end && keyCompare(it->first, key); ++it)
1165                 keep(it);
1166             // Keep matching keys if value match, otherwise skip and count
1167             for (; it != end && !keyCompare(key, it->first); ++it) {
1168                 if (!(it->second == value))
1169                     keep(it);
1170                 else
1171                     ++result;
1172             }
1173             for (; it != end; ++it)
1174                 keep(it);
1175 
1176             d.swap(newData);
1177             return result;
1178         }
1179 
1180         // d->m.erase_if(....) would be nice, but that's C++20.
1181         // So let's do like find(keyCopy, valueCopy):
1182         auto [i, e] = d->m.equal_range(key);
1183         if (i == e)
1184             return result;
1185 
1186         // value may belong to this map. As such, we need to copy it to ensure
1187         // it stays valid throughout the iteration below (which may destroy it)
1188         const T valueCopy = value;
1189         while (i != e) {
1190             if (i->second == valueCopy) {
1191                 i = d->m.erase(i);
1192                 ++result;
1193             } else {
1194                 ++i;
1195             }
1196         }
1197 
1198         return result;
1199     }
1200 
1201     template <typename Predicate>
1202     size_type removeIf(Predicate pred)
1203     {
1204         return QtPrivate::associative_erase_if(*this, pred);
1205     }
1206 
1207     T take(const Key &key)
1208     {
1209         if (!d)
1210             return T();
1211 
1212         if (d.isShared()) {
1213             auto i = d->m.find(key);
1214             const auto hold = referenceHoldingDetachExceptFor(i);
1215             return i->second;
1216         }
1217 
1218 #ifdef __cpp_lib_node_extract
1219         if (const auto node = d->m.extract(key))
1220             return std::move(node.mapped());
1221 #else
1222         auto i = d->m.find(key);
1223         if (i != d->m.end()) {
1224             // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
1225             T result(std::move(i->second));
1226             d->m.erase(i);
1227             return result;
1228         }
1229 #endif
1230         return T();
1231     }
1232 
1233     bool contains(const Key &key) const
1234     {
1235         if (!d)
1236             return false;
1237         auto i = d->m.find(key);
1238         return i != d->m.end();
1239     }
1240 
1241     bool contains(const Key &key, const T &value) const
1242     {
1243         return find(key, value) != end();
1244     }
1245 
1246     Key key(const T &value, const Key &defaultKey = Key()) const
1247     {
1248         if (!d)
1249             return defaultKey;
1250 
1251         return d->key(value, defaultKey);
1252     }
1253 
1254     T value(const Key &key, const T &defaultValue = T()) const
1255     {
1256         if (!d)
1257             return defaultValue;
1258         const auto i = d->m.find(key);
1259         if (i != d->m.cend())
1260             return i->second;
1261         return defaultValue;
1262     }
1263 
1264     QList<Key> keys() const
1265     {
1266         if (!d)
1267             return {};
1268         return d->keys();
1269     }
1270 
1271     QList<Key> keys(const T &value) const
1272     {
1273         if (!d)
1274             return {};
1275         return d->keys(value);
1276     }
1277 
1278     QList<Key> uniqueKeys() const
1279     {
1280         QList<Key> result;
1281         if (!d)
1282             return result;
1283 
1284         result.reserve(size());
1285 
1286         std::unique_copy(keyBegin(), keyEnd(),
1287                          std::back_inserter(result));
1288 
1289         result.shrink_to_fit();
1290         return result;
1291     }
1292 
1293     QList<T> values() const
1294     {
1295         if (!d)
1296             return {};
1297         return d->values();
1298     }
1299 
1300     QList<T> values(const Key &key) const
1301     {
1302         QList<T> result;
1303         const auto range = equal_range(key);
1304         result.reserve(std::distance(range.first, range.second));
1305         std::copy(range.first, range.second, std::back_inserter(result));
1306         return result;
1307     }
1308 
1309     size_type count(const Key &key) const
1310     {
1311         if (!d)
1312             return 0;
1313         return d->count(key);
1314     }
1315 
1316     size_type count(const Key &key, const T &value) const
1317     {
1318         if (!d)
1319             return 0;
1320 
1321         // TODO: improve; no need of scanning the equal_range twice.
1322         auto range = d->m.equal_range(key);
1323 
1324         return size_type(std::count_if(range.first,
1325                                        range.second,
1326                                        MapData::valueIsEqualTo(value)));
1327     }
1328 
1329     inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
1330     inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return std::next(constEnd(), -1).key(); }
1331 
1332     inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
1333     inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
1334     inline T &last() { Q_ASSERT(!isEmpty()); return *std::next(end(), -1); }
1335     inline const T &last() const { Q_ASSERT(!isEmpty()); return *std::next(constEnd(), -1); }
1336 
1337     class const_iterator;
1338 
1339     class iterator
1340     {
1341         friend class QMultiMap<Key, T>;
1342         friend class const_iterator;
1343 
1344         typename Map::iterator i;
1345         explicit iterator(typename Map::iterator it) : i(it) {}
1346     public:
1347         using iterator_category = std::bidirectional_iterator_tag;
1348         using difference_type = qptrdiff;
1349         using value_type = T;
1350         using pointer = T *;
1351         using reference = T &;
1352 
1353         iterator() = default;
1354 
1355         const Key &key() const { return i->first; }
1356         T &value() const { return i->second; }
1357         T &operator*() const { return i->second; }
1358         T *operator->() const { return &i->second; }
1359         friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
1360         friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
1361 
1362         iterator &operator++()
1363         {
1364             ++i;
1365             return *this;
1366         }
1367         iterator operator++(int)
1368         {
1369             iterator r = *this;
1370             ++i;
1371             return r;
1372         }
1373         iterator &operator--()
1374         {
1375             --i;
1376             return *this;
1377         }
1378         iterator operator--(int)
1379         {
1380             iterator r = *this;
1381             --i;
1382             return r;
1383         }
1384 
1385 #if QT_DEPRECATED_SINCE(6, 0)
1386         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1387         //! [qmultimap-op-it-plus-step]
1388         friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
1389 
1390         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1391         //! [qmultimap-op-it-minus-step]
1392         friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
1393 
1394         QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1395         iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1396 
1397         QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1398         iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1399 
1400         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1401         //! [qmultimap-op-step-plus-it]
1402         friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
1403 
1404         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1405         //! [qmultimap-op-step-minus-it]
1406         friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
1407 #endif
1408     };
1409 
1410     class const_iterator
1411     {
1412         friend class QMultiMap<Key, T>;
1413         typename Map::const_iterator i;
1414         explicit const_iterator(typename Map::const_iterator it) : i(it) {}
1415 
1416     public:
1417         using iterator_category = std::bidirectional_iterator_tag;
1418         using difference_type = qptrdiff;
1419         using value_type = T;
1420         using pointer = const T *;
1421         using reference = const T &;
1422 
1423         const_iterator() = default;
1424         Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
1425 
1426         const Key &key() const { return i->first; }
1427         const T &value() const { return i->second; }
1428         const T &operator*() const { return i->second; }
1429         const T *operator->() const { return &i->second; }
1430         friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
1431         friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
1432 
1433         const_iterator &operator++()
1434         {
1435             ++i;
1436             return *this;
1437         }
1438         const_iterator operator++(int)
1439         {
1440             const_iterator r = *this;
1441             ++i;
1442             return r;
1443         }
1444         const_iterator &operator--()
1445         {
1446             --i;
1447             return *this;
1448         }
1449         const_iterator operator--(int)
1450         {
1451             const_iterator r = *this;
1452             --i;
1453             return r;
1454         }
1455 
1456 #if QT_DEPRECATED_SINCE(6, 0)
1457         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1458         //! [qmultimap-op-it-plus-step-const]
1459         friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
1460 
1461         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1462         //! [qmultimap-op-it-minus-step-const]
1463         friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
1464 
1465         QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1466         const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1467 
1468         QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1469         const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1470 
1471         QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1472         //! [qmultimap-op-step-plus-it-const]
1473         friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
1474 
1475         QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1476         //! [qmultimap-op-step-minus-it-const]
1477         friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
1478 #endif
1479     };
1480 
1481     class key_iterator
1482     {
1483         const_iterator i;
1484 
1485     public:
1486         typedef typename const_iterator::iterator_category iterator_category;
1487         typedef typename const_iterator::difference_type difference_type;
1488         typedef Key value_type;
1489         typedef const Key *pointer;
1490         typedef const Key &reference;
1491 
1492         key_iterator() = default;
1493         explicit key_iterator(const_iterator o) : i(o) { }
1494 
1495         const Key &operator*() const { return i.key(); }
1496         const Key *operator->() const { return &i.key(); }
1497         bool operator==(key_iterator o) const { return i == o.i; }
1498         bool operator!=(key_iterator o) const { return i != o.i; }
1499 
1500         inline key_iterator &operator++() { ++i; return *this; }
1501         inline key_iterator operator++(int) { return key_iterator(i++);}
1502         inline key_iterator &operator--() { --i; return *this; }
1503         inline key_iterator operator--(int) { return key_iterator(i--); }
1504         const_iterator base() const { return i; }
1505     };
1506 
1507     typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1508     typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1509 
1510     // STL style
1511     iterator begin() { detach(); return iterator(d->m.begin()); }
1512     const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
1513     const_iterator constBegin() const { return begin(); }
1514     const_iterator cbegin() const { return begin(); }
1515     iterator end() { detach(); return iterator(d->m.end()); }
1516     const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
1517     const_iterator constEnd() const { return end(); }
1518     const_iterator cend() const { return end(); }
1519     key_iterator keyBegin() const { return key_iterator(begin()); }
1520     key_iterator keyEnd() const { return key_iterator(end()); }
1521     key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
1522     key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
1523     const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
1524     const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
1525     const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
1526     const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
1527     auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMultiMap &>(*this); }
1528     auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMultiMap &>(*this); }
1529     auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1530     auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1531 
1532     iterator erase(const_iterator it)
1533     {
1534         return erase(it, std::next(it));
1535     }
1536 
1537     iterator erase(const_iterator afirst, const_iterator alast)
1538     {
1539         if (!d)
1540             return iterator();
1541 
1542         if (!d.isShared())
1543             return iterator(d->m.erase(afirst.i, alast.i));
1544 
1545         auto result = d->erase(afirst.i, alast.i);
1546         d.reset(result.data);
1547         return iterator(result.it);
1548     }
1549 
1550     // more Qt
1551     typedef iterator Iterator;
1552     typedef const_iterator ConstIterator;
1553 
1554     size_type count() const
1555     {
1556         return size();
1557     }
1558 
1559     iterator find(const Key &key)
1560     {
1561         const auto hold = referenceHoldingDetach();
1562         return iterator(d->m.find(key));
1563     }
1564 
1565     const_iterator find(const Key &key) const
1566     {
1567         if (!d)
1568             return const_iterator();
1569         return const_iterator(d->m.find(key));
1570     }
1571 
1572     const_iterator constFind(const Key &key) const
1573     {
1574         return find(key);
1575     }
1576 
1577     iterator find(const Key &key, const T &value)
1578     {
1579         const auto hold = referenceHoldingDetach();
1580 
1581         auto range = d->m.equal_range(key);
1582         auto i = std::find_if(range.first, range.second,
1583                               MapData::valueIsEqualTo(value));
1584 
1585         if (i != range.second)
1586             return iterator(i);
1587         return iterator(d->m.end());
1588     }
1589 
1590     const_iterator find(const Key &key, const T &value) const
1591     {
1592         if (!d)
1593             return const_iterator();
1594 
1595         auto range = d->m.equal_range(key);
1596         auto i = std::find_if(range.first, range.second,
1597                               MapData::valueIsEqualTo(value));
1598 
1599         if (i != range.second)
1600             return const_iterator(i);
1601         return const_iterator(d->m.end());
1602     }
1603 
1604     const_iterator constFind(const Key &key, const T &value) const
1605     {
1606         return find(key, value);
1607     }
1608 
1609     iterator lowerBound(const Key &key)
1610     {
1611         const auto hold = referenceHoldingDetach();
1612         return iterator(d->m.lower_bound(key));
1613     }
1614 
1615     const_iterator lowerBound(const Key &key) const
1616     {
1617         if (!d)
1618             return const_iterator();
1619         return const_iterator(d->m.lower_bound(key));
1620     }
1621 
1622     iterator upperBound(const Key &key)
1623     {
1624         const auto hold = referenceHoldingDetach();
1625         return iterator(d->m.upper_bound(key));
1626     }
1627 
1628     const_iterator upperBound(const Key &key) const
1629     {
1630         if (!d)
1631             return const_iterator();
1632         return const_iterator(d->m.upper_bound(key));
1633     }
1634 
1635     iterator insert(const Key &key, const T &value)
1636     {
1637         const auto hold = referenceHoldingDetach();
1638         // note that std::multimap inserts at the end of an equal_range for a key,
1639         // QMultiMap at the beginning.
1640         auto i = d->m.lower_bound(key);
1641         return iterator(d->m.insert(i, {key, value}));
1642     }
1643 
1644     iterator insert(const_iterator pos, const Key &key, const T &value)
1645     {
1646         if (!d) {
1647             d.reset(new MapData);
1648             return iterator(d->m.insert({ key, value }));
1649         } else if (d.isShared()) {
1650             auto posDistance = std::distance(d->m.cbegin(), pos.i);
1651             auto hold = referenceHoldingDetach();
1652             auto dpos = std::next(d->m.cbegin(), posDistance);
1653             return iterator(d->m.insert(dpos, {key, value}));
1654         }
1655 
1656         return iterator(d->m.insert(pos.i, {key, value}));
1657     }
1658 
1659 #if QT_DEPRECATED_SINCE(6, 0)
1660     QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1661     iterator insertMulti(const Key &key, const T &value)
1662     {
1663         return insert(key, value);
1664     }
1665     QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1666     iterator insertMulti(const_iterator pos, const Key &key, const T &value)
1667     {
1668         return insert(pos, key, value);
1669     }
1670 
1671     QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1672     void insert(const QMultiMap<Key, T> &map)
1673     {
1674         unite(map);
1675     }
1676 
1677     QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1678     void insert(QMultiMap<Key, T> &&map)
1679     {
1680         unite(std::move(map));
1681     }
1682 #endif
1683 
1684     iterator replace(const Key &key, const T &value)
1685     {
1686         if (!d) {
1687             d.reset(new MapData);
1688             return iterator(d->m.insert({ key, value }));
1689         }
1690         auto i = d->m.find(key);
1691         if (d.isShared()) {
1692             const auto hold = referenceHoldingDetachExceptFor(i);
1693             return iterator(d->m.insert({ key, value }));
1694         }
1695 
1696         // Similarly, improve here (e.g. lower_bound and hinted insert);
1697         // there's no insert_or_assign on multimaps
1698         if (i != d->m.end())
1699             i->second = value;
1700         else
1701             i = d->m.insert({key, value});
1702 
1703         return iterator(i);
1704     }
1705 
1706     // STL compatibility
1707     [[nodiscard]]
1708     inline bool empty() const { return isEmpty(); }
1709 
1710     std::pair<iterator, iterator> equal_range(const Key &akey)
1711     {
1712         const auto hold = referenceHoldingDetach();
1713         auto result = d->m.equal_range(akey);
1714         return {iterator(result.first), iterator(result.second)};
1715     }
1716 
1717     std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
1718     {
1719         if (!d)
1720             return {};
1721         auto result = d->m.equal_range(akey);
1722         return {const_iterator(result.first), const_iterator(result.second)};
1723     }
1724 
1725     QMultiMap &unite(const QMultiMap &other)
1726     {
1727         if (other.isEmpty())
1728             return *this;
1729 
1730         detach();
1731 
1732         auto copy = other.d->m;
1733 #ifdef __cpp_lib_node_extract
1734         copy.merge(std::move(d->m));
1735 #else
1736         copy.insert(std::make_move_iterator(d->m.begin()),
1737                     std::make_move_iterator(d->m.end()));
1738 #endif
1739         d->m = std::move(copy);
1740         return *this;
1741     }
1742 
1743     QMultiMap &unite(QMultiMap<Key, T> &&other)
1744     {
1745         if (!other.d || other.d->m.empty())
1746             return *this;
1747 
1748         if (other.d.isShared()) {
1749             // fall back to a regular copy
1750             unite(other);
1751             return *this;
1752         }
1753 
1754         detach();
1755 
1756 #ifdef __cpp_lib_node_extract
1757         other.d->m.merge(std::move(d->m));
1758 #else
1759         other.d->m.insert(std::make_move_iterator(d->m.begin()),
1760                           std::make_move_iterator(d->m.end()));
1761 #endif
1762         *this = std::move(other);
1763         return *this;
1764     }
1765 };
1766 
1767 Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap)
1768 Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap)
1769 
1770 template <typename Key, typename T>
1771 QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1772 {
1773     auto result = lhs;
1774     result += rhs;
1775     return result;
1776 }
1777 
1778 template <typename Key, typename T>
1779 QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1780 {
1781     return lhs.unite(rhs);
1782 }
1783 
1784 template <typename Key, typename T, typename Predicate>
1785 qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
1786 {
1787     return QtPrivate::associative_erase_if(map, pred);
1788 }
1789 
1790 QT_END_NAMESPACE
1791 
1792 #endif // QMAP_H