Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:04:31

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