diff options
Diffstat (limited to 'src/corelib/tools/qmap.h')
-rw-r--r-- | src/corelib/tools/qmap.h | 257 |
1 files changed, 196 insertions, 61 deletions
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index b64989eadd..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> @@ -238,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) @@ -276,8 +241,9 @@ public: return {}; } +#ifndef Q_QDOC template <typename AKey = Key, typename AT = T> friend - QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMap &lhs, const QMap &rhs) + QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator==(const QMap &lhs, const QMap &rhs) { if (lhs.d == rhs.d) return true; @@ -288,11 +254,15 @@ public: } template <typename AKey = Key, typename AT = T> friend - QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap &lhs, const QMap &rhs) + 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); } @@ -354,6 +324,7 @@ public: 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(); @@ -395,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()) @@ -496,6 +468,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] + 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 @@ -543,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 @@ -591,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) { @@ -616,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)); } @@ -634,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)); } @@ -647,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)); } @@ -660,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); @@ -668,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) @@ -729,20 +763,46 @@ 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) @@ -754,6 +814,7 @@ qsizetype erase_if(QMap<Key, T> &map, Predicate pred) return QtPrivate::associative_erase_if(map, pred); } + // // QMultiMap // @@ -783,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) @@ -851,8 +912,9 @@ public: return {}; } +#ifndef Q_QDOC template <typename AKey = Key, typename AT = T> friend - QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMultiMap &lhs, const QMultiMap &rhs) + QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator==(const QMultiMap &lhs, const QMultiMap &rhs) { if (lhs.d == rhs.d) return true; @@ -863,11 +925,15 @@ public: } template <typename AKey = Key, typename AT = T> friend - QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMultiMap &lhs, const QMultiMap &rhs) + 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); } @@ -923,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(); @@ -961,6 +1027,8 @@ public: 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(); @@ -1125,6 +1193,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] + 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 @@ -1172,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 @@ -1220,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) { @@ -1250,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)); } @@ -1268,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); @@ -1300,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)); } @@ -1313,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)); } @@ -1326,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. @@ -1335,10 +1461,16 @@ 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})); } #if QT_DEPRECATED_SINCE(6, 0) @@ -1368,6 +1500,8 @@ public: 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(); @@ -1385,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 {}; |