summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qmap.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qmap.h')
-rw-r--r--src/corelib/tools/qmap.h493
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