diff options
Diffstat (limited to 'src/corelib/tools/qmap.h')
-rw-r--r-- | src/corelib/tools/qmap.h | 493 |
1 files changed, 323 insertions, 170 deletions
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 2780c46b7d..7ee0be1e51 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -1,46 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QMAP_H #define QMAP_H +#include <QtCore/qhashfunctions.h> #include <QtCore/qiterator.h> #include <QtCore/qlist.h> #include <QtCore/qrefcount.h> @@ -68,6 +33,9 @@ public: using iterator = typename Map::iterator; using const_iterator = typename Map::const_iterator; + static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers."); + static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers."); + Map m; QMapData() = default; @@ -217,7 +185,8 @@ public: template <class Key, class T> class QMap { - using MapData = QMapData<std::map<Key, T>>; + using Map = std::map<Key, T>; + using MapData = QMapData<Map>; QtPrivate::QExplicitlySharedDataPointerV2<MapData> d; friend class QMultiMap<Key, T>; @@ -234,7 +203,7 @@ public: void swap(QMap<Key, T> &other) noexcept { - qSwap(d, other.d); + d.swap(other.d); } QMap(std::initializer_list<std::pair<Key, T>> list) @@ -272,13 +241,28 @@ public: return {}; } - // CHANGE: non-member equality comparison - template <typename AKey, typename AT> - friend QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs); - template <typename AKey, typename AT> - friend QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs); +#ifndef Q_QDOC + template <typename AKey = Key, typename AT = T> friend + QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator==(const QMap &lhs, const QMap &rhs) + { + if (lhs.d == rhs.d) + return true; + if (!lhs.d) + return rhs == lhs; + Q_ASSERT(lhs.d); + return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty(); + } + template <typename AKey = Key, typename AT = T> friend + QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator!=(const QMap &lhs, const QMap &rhs) + { + return !(lhs == rhs); + } // TODO: add the other comparison operators; std::map has them. +#else + friend bool operator==(const QMap &lhs, const QMap &rhs); + friend bool operator!=(const QMap &lhs, const QMap &rhs); +#endif // Q_QDOC size_type size() const { return d ? size_type(d->m.size()) : size_type(0); } @@ -329,11 +313,18 @@ public: return result; } + template <typename Predicate> + size_type removeIf(Predicate pred) + { + return QtPrivate::associative_erase_if(*this, pred); + } + T take(const Key &key) { if (!d) return T(); + const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach // TODO: improve. There is no need of copying all the // elements (the one to be removed can be skipped). detach(); @@ -355,8 +346,6 @@ public: return i != d->m.end(); } - // ### Qt 6: deprecate value->key lookup. - //Q_DECL_DEPRECATED_X("This function is inefficient; don't use it") Key key(const T &value, const Key &defaultKey = Key()) const { if (!d) @@ -377,6 +366,7 @@ public: T &operator[](const Key &key) { + const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach detach(); auto i = d->m.find(key); if (i == d->m.end()) @@ -390,7 +380,6 @@ public: return value(key); } - // ### Qt 6: this stuff should be deprecated as well QList<Key> keys() const { if (!d) @@ -439,14 +428,14 @@ public: friend class QMap<Key, T>; friend class const_iterator; - typename MapData::Map::iterator i; - explicit iterator(typename MapData::Map::iterator it) : i(it) {} + typename Map::iterator i; + explicit iterator(typename Map::iterator it) : i(it) {} public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef qptrdiff difference_type; - typedef T value_type; - typedef T *pointer; - typedef T &reference; + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = qptrdiff; + using value_type = T; + using pointer = T *; + using reference = T &; iterator() = default; @@ -479,23 +468,47 @@ public: --i; return r; } + +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access") + //! [qmap-op-it-plus-step] + friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access") + //! [qmap-op-it-minus-step] + friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access") + iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access") + iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access") + //! [qmap-op-step-plus-it] + friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access") + //! [qmap-op-step-minus-it] + friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); } +#endif }; class const_iterator { friend class QMap<Key, T>; - typename MapData::Map::const_iterator i; - explicit const_iterator(typename MapData::Map::const_iterator it) : i(it) {} + typename Map::const_iterator i; + explicit const_iterator(typename Map::const_iterator it) : i(it) {} public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef qptrdiff difference_type; - typedef T value_type; - typedef const T *pointer; - typedef const T &reference; + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = qptrdiff; + using value_type = T; + using pointer = const T *; + using reference = const T &; const_iterator() = default; - /* implicit */ const_iterator(const iterator &o) { i = o.i; } + Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {} const Key &key() const { return i->first; } const T &value() const { return i->second; } @@ -526,6 +539,30 @@ public: --i; return r; } + +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access") + //! [qmap-op-it-plus-step-const] + friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access") + //! [qmap-op-it-minus-step-const] + friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access") + const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access") + const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access") + //! [qmap-op-step-plus-it-const] + friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access") + //! [qmap-op-step-minus-it-const] + friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); } +#endif }; class key_iterator @@ -574,6 +611,10 @@ public: const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); } const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); } const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); } + auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); } + auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); } + auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); } + auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); } iterator erase(const_iterator it) { @@ -599,6 +640,7 @@ public: iterator find(const Key &key) { + const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach detach(); return iterator(d->m.find(key)); } @@ -617,6 +659,7 @@ public: iterator lowerBound(const Key &key) { + const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach detach(); return iterator(d->m.lower_bound(key)); } @@ -630,6 +673,7 @@ public: iterator upperBound(const Key &key) { + const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach detach(); return iterator(d->m.upper_bound(key)); } @@ -643,6 +687,7 @@ public: iterator insert(const Key &key, const T &value) { + const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach // TODO: improve. In case of assignment, why copying first? detach(); return iterator(d->m.insert_or_assign(key, value).first); @@ -651,10 +696,16 @@ public: iterator insert(const_iterator pos, const Key &key, const T &value) { // TODO: improve. In case of assignment, why copying first? - auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0; - detach(); - auto detachedPos = std::next(d->m.cbegin(), posDistance); - return iterator(d->m.insert_or_assign(detachedPos, key, value)); + typename Map::const_iterator dpos; + const auto copy = d.isShared() ? *this : QMap(); // keep `key`/`value` alive across the detach + if (!d || d.isShared()) { + auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0; + detach(); + dpos = std::next(d->m.cbegin(), posDistance); + } else { + dpos = pos.i; + } + return iterator(d->m.insert_or_assign(dpos, key, value)); } void insert(const QMap<Key, T> &map) @@ -712,40 +763,55 @@ public: return isEmpty(); } - QPair<iterator, iterator> equal_range(const Key &akey) + std::pair<iterator, iterator> equal_range(const Key &akey) { + const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach detach(); auto result = d->m.equal_range(akey); return {iterator(result.first), iterator(result.second)}; } - QPair<const_iterator, const_iterator> equal_range(const Key &akey) const + std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const { if (!d) return {}; auto result = d->m.equal_range(akey); return {const_iterator(result.first), const_iterator(result.second)}; } + +private: +#ifdef Q_QDOC + friend size_t qHash(const QMap &key, size_t seed = 0); +#else +# if defined(Q_CC_GHS) || defined (Q_CC_MSVC) + // GHS and MSVC tries to intantiate qHash() for the noexcept running into a + // non-SFINAE'ed hard error... Create an artificial SFINAE context as a + // work-around: + template <typename M, std::enable_if_t<std::is_same_v<M, QMap>, bool> = true> + friend QtPrivate::QHashMultiReturnType<typename M::key_type, typename M::mapped_type> +# else + using M = QMap; + friend size_t +# endif + qHash(const M &key, size_t seed = 0) + noexcept(QHashPrivate::noexceptPairHash<typename M::key_type, typename M::mapped_type>()) + { + if (!key.d) + return seed; + // don't use qHashRange to avoid its compile-time overhead: + return std::accumulate(key.d->m.begin(), key.d->m.end(), seed, + QtPrivate::QHashCombine{}); + } +#endif // !Q_QDOC }; Q_DECLARE_ASSOCIATIVE_ITERATOR(Map) Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map) -template <typename AKey, typename AT> -QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs) -{ - if (lhs.d == rhs.d) - return true; - if (!lhs.d) - return rhs == lhs; - Q_ASSERT(lhs.d); - return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty(); -} - -template <typename AKey, typename AT> -QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs) +template <typename Key, typename T, typename Predicate> +qsizetype erase_if(QMap<Key, T> &map, Predicate pred) { - return !(lhs == rhs); + return QtPrivate::associative_erase_if(map, pred); } @@ -756,7 +822,8 @@ QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap<AKey, AT> &lhs, c template <class Key, class T> class QMultiMap { - using MapData = QMapData<std::multimap<Key, T>>; + using Map = std::multimap<Key, T>; + using MapData = QMapData<Map>; QtPrivate::QExplicitlySharedDataPointerV2<MapData> d; public: @@ -777,7 +844,7 @@ public: void swap(QMultiMap<Key, T> &other) noexcept { - qSwap(d, other.d); + d.swap(other.d); } explicit QMultiMap(const QMap<Key, T> &other) @@ -845,13 +912,28 @@ public: return {}; } - // CHANGE: non-member equality comparison - template <typename AKey, typename AT> - friend QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs); - template <typename AKey, typename AT> - friend QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs); +#ifndef Q_QDOC + template <typename AKey = Key, typename AT = T> friend + QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator==(const QMultiMap &lhs, const QMultiMap &rhs) + { + if (lhs.d == rhs.d) + return true; + if (!lhs.d) + return rhs == lhs; + Q_ASSERT(lhs.d); + return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty(); + } + template <typename AKey = Key, typename AT = T> friend + QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator!=(const QMultiMap &lhs, const QMultiMap &rhs) + { + return !(lhs == rhs); + } // TODO: add the other comparison operators; std::multimap has them. +#else + friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs); + friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs); +#endif // Q_QDOC size_type size() const { return d ? size_type(d->m.size()) : size_type(0); } @@ -907,15 +989,15 @@ public: if (!d) return 0; - // TODO: improve. Copy over only the elements not to be removed. - detach(); - // key and value may belong to this map. As such, we need to copy - // them to ensure they stay valid througout the iteration below + // them to ensure they stay valid throughout the iteration below // (which may destroy them) const Key keyCopy = key; const T valueCopy = value; + // TODO: improve. Copy over only the elements not to be removed. + detach(); + size_type result = 0; const auto &keyCompare = d->m.key_comp(); @@ -934,11 +1016,19 @@ public: return result; } + template <typename Predicate> + size_type removeIf(Predicate pred) + { + return QtPrivate::associative_erase_if(*this, pred); + } + T take(const Key &key) { if (!d) return T(); + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach + // TODO: improve. There is no need of copying all the // elements (the one to be removed can be skipped). detach(); @@ -965,8 +1055,6 @@ public: return find(key, value) != end(); } - // ### Qt 6: deprecate value->key lookup. - //Q_DECL_DEPRECATED_X("This function is inefficient; don't use it") Key key(const T &value, const Key &defaultKey = Key()) const { if (!d) @@ -985,7 +1073,6 @@ public: return defaultValue; } - // ### Qt 6: deprecate value->key lookup. QList<Key> keys() const { if (!d) @@ -1066,14 +1153,14 @@ public: friend class QMultiMap<Key, T>; friend class const_iterator; - typename MapData::Map::iterator i; - explicit iterator(typename MapData::Map::iterator it) : i(it) {} + typename Map::iterator i; + explicit iterator(typename Map::iterator it) : i(it) {} public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef qptrdiff difference_type; - typedef T value_type; - typedef T *pointer; - typedef T &reference; + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = qptrdiff; + using value_type = T; + using pointer = T *; + using reference = T &; iterator() = default; @@ -1106,23 +1193,47 @@ public: --i; return r; } + +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access") + //! [qmultimap-op-it-plus-step] + friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access") + //! [qmultimap-op-it-minus-step] + friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access") + iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access") + iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access") + //! [qmultimap-op-step-plus-it] + friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access") + //! [qmultimap-op-step-minus-it] + friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); } +#endif }; class const_iterator { friend class QMultiMap<Key, T>; - typename MapData::Map::const_iterator i; - explicit const_iterator(typename MapData::Map::const_iterator it) : i(it) {} + typename Map::const_iterator i; + explicit const_iterator(typename Map::const_iterator it) : i(it) {} public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef qptrdiff difference_type; - typedef T value_type; - typedef const T *pointer; - typedef const T &reference; + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = qptrdiff; + using value_type = T; + using pointer = const T *; + using reference = const T &; const_iterator() = default; - /* implicit */ const_iterator(const iterator &o) { i = o.i; } + Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {} const Key &key() const { return i->first; } const T &value() const { return i->second; } @@ -1153,6 +1264,30 @@ public: --i; return r; } + +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access") + //! [qmultimap-op-it-plus-step-const] + friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access") + //! [qmultimap-op-it-minus-step-const] + friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access") + const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access") + const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; } + + QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access") + //! [qmultimap-op-step-plus-it-const] + friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); } + + QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access") + //! [qmultimap-op-step-minus-it-const] + friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); } +#endif }; class key_iterator @@ -1201,6 +1336,10 @@ public: const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); } const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); } const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); } + auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); } + auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); } + auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); } + auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); } iterator erase(const_iterator it) { @@ -1231,6 +1370,7 @@ public: iterator find(const Key &key) { + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach detach(); return iterator(d->m.find(key)); } @@ -1249,6 +1389,8 @@ public: iterator find(const Key &key, const T &value) { + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach + detach(); auto range = d->m.equal_range(key); @@ -1281,6 +1423,7 @@ public: iterator lowerBound(const Key &key) { + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach detach(); return iterator(d->m.lower_bound(key)); } @@ -1294,6 +1437,7 @@ public: iterator upperBound(const Key &key) { + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach detach(); return iterator(d->m.upper_bound(key)); } @@ -1307,6 +1451,7 @@ public: iterator insert(const Key &key, const T &value) { + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach detach(); // note that std::multimap inserts at the end of an equal_range for a key, // QMultiMap at the beginning. @@ -1316,64 +1461,47 @@ public: iterator insert(const_iterator pos, const Key &key, const T &value) { - auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0; - detach(); - auto detachedPos = std::next(d->m.cbegin(), posDistance); - return iterator(d->m.insert(detachedPos, {key, value})); + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach + typename Map::const_iterator dpos; + if (!d || d.isShared()) { + auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0; + detach(); + dpos = std::next(d->m.cbegin(), posDistance); + } else { + dpos = pos.i; + } + return iterator(d->m.insert(dpos, {key, value})); } - // CHANGE: provide insertMulti for compatibility +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use insert() instead") iterator insertMulti(const Key &key, const T &value) { return insert(key, value); } - + QT_DEPRECATED_VERSION_X_6_0("Use insert() instead") iterator insertMulti(const_iterator pos, const Key &key, const T &value) { return insert(pos, key, value); } + QT_DEPRECATED_VERSION_X_6_0("Use unite() instead") void insert(const QMultiMap<Key, T> &map) { - if (map.isEmpty()) - return; - - detach(); - - auto copy = map.d->m; -#ifdef __cpp_lib_node_extract - copy.merge(std::move(d->m)); -#else - copy.insert(std::make_move_iterator(d->m.begin()), - std::make_move_iterator(d->m.end())); -#endif - d->m = std::move(copy); + unite(map); } + QT_DEPRECATED_VERSION_X_6_0("Use unite() instead") void insert(QMultiMap<Key, T> &&map) { - if (!map.d || map.d->m.empty()) - return; - - if (map.d.isShared()) { - // fall back to a regular copy - insert(map); - return; - } - - detach(); - -#ifdef __cpp_lib_node_extract - map.d->m.merge(std::move(d->m)); -#else - map.d->m.insert(std::make_move_iterator(d->m.begin()), - std::make_move_iterator(d->m.end())); -#endif - *this = std::move(map); + unite(std::move(map)); } +#endif iterator replace(const Key &key, const T &value) { + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach + // TODO: improve. No need of copying and then overwriting. detach(); @@ -1391,14 +1519,15 @@ public: // STL compatibility inline bool empty() const { return isEmpty(); } - QPair<iterator, iterator> equal_range(const Key &akey) + std::pair<iterator, iterator> equal_range(const Key &akey) { + const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach detach(); auto result = d->m.equal_range(akey); return {iterator(result.first), iterator(result.second)}; } - QPair<const_iterator, const_iterator> equal_range(const Key &akey) const + std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const { if (!d) return {}; @@ -1408,7 +1537,42 @@ public: QMultiMap &unite(const QMultiMap &other) { - insert(other); + if (other.isEmpty()) + return *this; + + detach(); + + auto copy = other.d->m; +#ifdef __cpp_lib_node_extract + copy.merge(std::move(d->m)); +#else + copy.insert(std::make_move_iterator(d->m.begin()), + std::make_move_iterator(d->m.end())); +#endif + d->m = std::move(copy); + return *this; + } + + QMultiMap &unite(QMultiMap<Key, T> &&other) + { + if (!other.d || other.d->m.empty()) + return *this; + + if (other.d.isShared()) { + // fall back to a regular copy + unite(other); + return *this; + } + + detach(); + +#ifdef __cpp_lib_node_extract + other.d->m.merge(std::move(d->m)); +#else + other.d->m.insert(std::make_move_iterator(d->m.begin()), + std::make_move_iterator(d->m.end())); +#endif + *this = std::move(other); return *this; } }; @@ -1416,23 +1580,6 @@ public: Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap) Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap) -template <typename AKey, typename AT> -QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs) -{ - if (lhs.d == rhs.d) - return true; - if (!lhs.d) - return rhs == lhs; - Q_ASSERT(lhs.d); - return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty(); -} - -template <typename AKey, typename AT> -QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs) -{ - return !(lhs == rhs); -} - template <typename Key, typename T> QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs) { @@ -1447,6 +1594,12 @@ QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rh return lhs.unite(rhs); } +template <typename Key, typename T, typename Predicate> +qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred) +{ + return QtPrivate::associative_erase_if(map, pred); +} + QT_END_NAMESPACE #endif // QMAP_H |