Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmap.h
Go to the documentation of this file.
1// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
2// Copyright (C) 2021 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#ifndef QMAP_H
7#define QMAP_H
8
9#include <QtCore/qcompare.h>
10#include <QtCore/qhashfunctions.h>
11#include <QtCore/qiterator.h>
12#include <QtCore/qlist.h>
13#include <QtCore/qrefcount.h>
14#include <QtCore/qpair.h>
15#include <QtCore/qscopeguard.h>
16#include <QtCore/qshareddata.h>
17#include <QtCore/qshareddata_impl.h>
18#include <QtCore/qttypetraits.h>
19
20#include <functional>
21#include <initializer_list>
22#include <map>
23#include <algorithm>
24
25QT_BEGIN_NAMESPACE
26
27// common code shared between QMap and QMultimap
28template <typename AMap>
29class QMapData : public QSharedData
30{
31public:
32 using Map = AMap;
33 using Key = typename Map::key_type;
34 using T = typename Map::mapped_type;
35 using value_type = typename Map::value_type;
36 using size_type = typename Map::size_type;
37 using iterator = typename Map::iterator;
38 using const_iterator = typename Map::const_iterator;
39
40 static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
41 static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
42
43 Map m;
44
45 QMapData() = default;
46 explicit QMapData(const Map &other)
47 : m(other)
48 {}
49
50 explicit QMapData(Map &&other)
51 : m(std::move(other))
52 {}
53
54 // copies from source all the values not matching key.
55 // returns how many were NOT copied (removed), and first removed iterator
56 auto copyIfNotEquivalentTo(const Map &source, const Key &key)
57 {
58 Q_ASSERT(m.empty());
59
60 size_type result = 0;
61 auto foundIt = source.end();
62
63 const auto markFound = [&](auto it) {
64 if (result == 0)
65 foundIt = it;
66 ++result;
67 };
68 const auto keep = [this](auto it) { m.insert(m.cend(), *it); };
69
70 auto it = source.cbegin();
71 const auto end = source.cend();
72 const auto &cmp = m.key_comp();
73 // Keep all before:
74 for (; it != end && cmp(it->first, key); ++it)
75 keep(it);
76 // Count and skip matches:
77 for (; it != end && !cmp(key, it->first); ++it)
78 markFound(it);
79 // Keep all after:
80 for (; it != end; ++it)
81 keep(it);
82
83 struct resultType { size_type count; decltype(source.begin()) iterator; };
84 return resultType{result, foundIt};
85 }
86
87 void copyExceptFor(const Map &source, const iterator &skipit)
88 {
89 Q_ASSERT(m.empty());
90
91 auto it = source.cend();
92 const auto end = source.cbegin();
93 auto hint = m.end();
94 if (it == end)
95 return;
96 do {
97 --it;
98 if (it == skipit)
99 continue;
100 hint = m.emplace_hint(hint, it->first, it->second);
101 } while (it != end);
102 }
103
104 // Merges the two sources into this one, giving preference to source2
105 void fillWithMergeOf(const Map &source1, const Map &source2)
106 {
107 Q_ASSERT(m.empty());
108
109 auto insertionHint = m.end();
110 auto src1It = source1.crbegin();
111 const auto src1End = source1.crend();
112 auto src2It = source2.crbegin();
113 const auto src2End = source2.crend();
114 const auto &keyCompare = m.key_comp();
115 while (src1It != src1End && src2It != src2End) {
116 if (keyCompare(src2It->first, src1It->first)) {
117 insertionHint = m.emplace_hint(insertionHint, src1It->first, src1It->second);
118 ++src1It;
119 } else if (keyCompare(src1It->first, src2It->first)) {
120 insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second);
121 ++src2It;
122 } else {
123 // Equivalence, insert source2, forget source1
124 insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second);
125 ++src1It;
126 ++src2It;
127 }
128 }
129 for (; src1It != src1End; ++src1It)
130 insertionHint = m.emplace_hint(insertionHint, src1It->first, src1It->second);
131 for (; src2It != src2End; ++src2It)
132 insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second);
133 }
134
135 // Merge source into this one without changing source as std::map::merge would
136 void insertMap(const Map &source)
137 {
138 Q_ASSERT(!m.empty());
139 // copy in reverse order, trying to make effective use of insertionHint.
140 auto insertionHint = m.end();
141 auto it = source.crbegin();
142 const auto end = source.crend();
143 for (; it != end; ++it)
144 insertionHint = m.emplace_hint(insertionHint, it->first, it->second);
145 }
146
147 // used in key(T), count(Key, T), find(key, T), etc; returns a
148 // comparator object suitable for algorithms with std::(multi)map
149 // iterators.
150 static auto valueIsEqualTo(const T &value)
151 {
152 return [&value](const auto &v) { return v.second == value; };
153 }
154
155 Key key(const T &value, const Key &defaultKey) const
156 {
157 auto i = std::find_if(m.cbegin(),
158 m.cend(),
159 valueIsEqualTo(value));
160 if (i != m.cend())
161 return i->first;
162
163 return defaultKey;
164 }
165
166 QList<Key> keys() const
167 {
168 QList<Key> result;
169 result.reserve(m.size());
170
171 const auto extractKey = [](const auto &v) { return v.first; };
172
173 std::transform(m.cbegin(),
174 m.cend(),
175 std::back_inserter(result),
176 extractKey);
177 return result;
178 }
179
180 QList<Key> keys(const T &value) const
181 {
182 QList<Key> result;
183 result.reserve(m.size());
184 // no std::transform_if...
185 for (const auto &v : m) {
186 if (v.second == value)
187 result.append(v.first);
188 }
189 result.shrink_to_fit();
190 return result;
191 }
192
193 QList<T> values() const
194 {
195 QList<T> result;
196 result.reserve(m.size());
197
198 const auto extractValue = [](const auto &v) { return v.second; };
199
200 std::transform(m.cbegin(),
201 m.cend(),
202 std::back_inserter(result),
203 extractValue);
204 return result;
205 }
206
207 size_type count(const Key &key) const
208 {
209 return m.count(key);
210 }
211
212 // Used in erase. Allocates a new QMapData and copies, from this->m,
213 // the elements not in the [first, last) range. The return contains
214 // the new QMapData and an iterator in its map pointing at the first
215 // element after the erase.
216 struct EraseResult {
217 QMapData *data;
218 iterator it;
219 };
220
221 EraseResult erase(const_iterator first, const_iterator last) const
222 {
223 EraseResult result;
224 result.data = new QMapData;
225 result.it = result.data->m.end();
226 const auto newDataEnd = result.it;
227
228 auto i = m.begin();
229 const auto e = m.end();
230
231 // copy over all the elements before first
232 while (i != first) {
233 result.it = result.data->m.insert(newDataEnd, *i);
234 ++i;
235 }
236
237 // skip until last
238 while (i != last)
239 ++i;
240
241 // copy from last to the end
242 while (i != e) {
243 result.data->m.insert(newDataEnd, *i);
244 ++i;
245 }
246
247 if (result.it != newDataEnd)
248 ++result.it;
249
250 return result;
251 }
252};
253
254// common type traits
255namespace QtPrivate {
256
257template <typename Container, typename ...Ts>
260
261// The is_base_of<Container, T> check is required for recursive containers.
262// Without it MSVC produces errors like:
263//
264// error C2968:
265// 'if_map_has_relational_operators<QMap<NoCmpParamRecursiveMapK, Empty>,
266// NoCmpParamRecursiveMapK, Empty>':
267// recursive alias declaration
268//
269// The solution is similar to QTypeTraits::*_container checks.
270template <typename Container, typename T>
273
274template <typename Container, typename ...Ts>
277
278template <typename Container, typename ...Ts>
284 >,
285 bool>;
286
287} // namespace QtPrivate
288
289//
290// QMap
291//
292
293template <class Key, class T>
294class QMap
295{
296 using Map = std::map<Key, T>;
297 using MapData = QMapData<Map>;
298 QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
299
300 friend class QMultiMap<Key, T>;
301
302public:
303 using key_type = Key;
304 using mapped_type = T;
307
308 QMap() = default;
309
310 // implicitly generated special member functions are OK!
311
312 void swap(QMap<Key, T> &other) noexcept
313 {
314 d.swap(other.d);
315 }
316
317 QMap(std::initializer_list<std::pair<Key, T>> list)
318 {
319 for (auto &p : list)
320 insert(p.first, p.second);
321 }
322
323 explicit QMap(const std::map<Key, T> &other)
324 : d(other.empty() ? nullptr : new MapData(other))
325 {
326 }
327
328 explicit QMap(std::map<Key, T> &&other)
329 : d(other.empty() ? nullptr : new MapData(std::move(other)))
330 {
331 }
332
333 std::map<Key, T> toStdMap() const &
334 {
335 if (d)
336 return d->m;
337 return {};
338 }
339
341 {
342 if (d) {
343 if (d.isShared())
344 return d->m;
345 else
346 return std::move(d->m);
347 }
348
349 return {};
350 }
351
352#ifndef Q_QDOC
353private:
354 template <typename AKey = Key, typename AT = T,
355 QTypeTraits::compare_eq_result_container<QMap, AKey, AT> = true>
356 friend bool comparesEqual(const QMap &lhs, const QMap &rhs)
357 {
358 if (lhs.d == rhs.d)
359 return true;
360 if (!lhs.d)
361 return rhs == lhs;
362 Q_ASSERT(lhs.d);
363 return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
364 }
365 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMap, QMap, /* non-constexpr */, noexcept(false),
366 template <typename AKey = Key, typename AT = T,
367 QTypeTraits::compare_eq_result_container<QMap, AKey, AT> = true>)
368
369 template <typename AKey = Key, typename AT = T,
371 friend auto compareThreeWay(const QMap &lhs, const QMap &rhs)
372 {
377 }
378 QT_DECLARE_ORDERING_HELPER_AUTO(QMap, QMap, /* non-constexpr */, noexcept(false),
379 template <typename AKey = Key, typename AT = T,
381
382public:
383#else
384 friend bool operator==(const QMap &lhs, const QMap &rhs);
385 friend bool operator!=(const QMap &lhs, const QMap &rhs);
386 friend bool operator<(const QMap &lhs, const QMap &rhs);
387 friend bool operator>(const QMap &lhs, const QMap &rhs);
388 friend bool operator<=(const QMap &lhs, const QMap &rhs);
389 friend bool operator>=(const QMap &lhs, const QMap &rhs);
390 friend auto operator<=>(const QMap &lhs, const QMap &rhs);
391#endif // Q_QDOC
392
393 size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
394
395 [[nodiscard]]
396 bool isEmpty() const { return d ? d->m.empty() : true; }
397
398 void detach()
399 {
400 if (d)
401 d.detach();
402 else
403 d.reset(new MapData);
404 }
405
406 // A detach for holding an already shared copy, until calling function
407 // is done using references to keys or values that might reference it.
409 {
410 if (!d) {
411 d.reset(new MapData);
412 } else if (d.isShared()) {
413 auto hold = *this;
414 d.detach();
415 return hold;
416 }
417 return {};
418 }
419
420 // Specialized version of referenceHoldingDetach(), which will not copy key, if copying
422 {
423 if (!d) {
424 d.reset(new MapData);
425 } else if (d.isShared()) {
426 auto hold = *this;
429 d.swap(newData);
430 return hold;
431 }
432 return {};
433 }
434
435 bool isDetached() const noexcept
436 {
437 return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
438 }
439
440 bool isSharedWith(const QMap<Key, T> &other) const noexcept
441 {
442 return d == other.d; // also this makes little sense?
443 }
444
445 void clear()
446 {
447 if (!d)
448 return;
449
450 if (!d.isShared())
451 d->m.clear();
452 else
453 d.reset();
454 }
455
456 size_type remove(const Key &key)
457 {
458 if (!d)
459 return 0;
460
461 if (!d.isShared())
462 return size_type(d->m.erase(key));
463
464 MapData *newData = new MapData;
466
467 d.reset(newData);
468
469 return result;
470 }
471
472 template <typename Predicate>
474 {
475 return QtPrivate::associative_erase_if(*this, pred);
476 }
477
478 T take(const Key &key)
479 {
480 if (!d)
481 return T();
482
483 if (d.isShared()) {
484 MapData *m = new MapData;
485 // For historic reasons, we always un-share (was: detach()) when
486 // this function is called, even if `key` isn't found
487 const auto commit = qScopeGuard([&] { d.reset(m); });
488
489 auto result = m->copyIfNotEquivalentTo(d->m, key);
490 if (result.count)
491 return result.iterator->second;
492 // if we reach here, `key` wasn't found:
493 return T();
494 }
495
496#ifdef __cpp_lib_node_extract
497 if (const auto node = d->m.extract(key))
498 return std::move(node.mapped());
499#else
500 auto i = d->m.find(key);
501 if (i != d->m.end()) {
502 // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
503 T result(std::move(i->second));
504 d->m.erase(i);
505 return result;
506 }
507#endif
508 return T();
509 }
510
511 bool contains(const Key &key) const
512 {
513 if (!d)
514 return false;
515 auto i = d->m.find(key);
516 return i != d->m.end();
517 }
518
519 Key key(const T &value, const Key &defaultKey = Key()) const
520 {
521 if (!d)
522 return defaultKey;
523
524 return d->key(value, defaultKey);
525 }
526
527 T value(const Key &key, const T &defaultValue = T()) const
528 {
529 if (!d)
530 return defaultValue;
531 const auto i = d->m.find(key);
532 if (i != d->m.cend())
533 return i->second;
534 return defaultValue;
535 }
536
537 T &operator[](const Key &key)
538 {
539 const auto hold = referenceHoldingDetach();
540 auto i = d->m.find(key);
541 if (i == d->m.end())
542 i = d->m.insert({key, T()}).first;
543 return i->second;
544 }
545
546 // CHANGE: return T, not const T!
547 T operator[](const Key &key) const
548 {
549 return value(key);
550 }
551
552 QList<Key> keys() const
553 {
554 if (!d)
555 return {};
556 return d->keys();
557 }
558
559 QList<Key> keys(const T &value) const
560 {
561 if (!d)
562 return {};
563 return d->keys(value);
564 }
565
566 QList<T> values() const
567 {
568 if (!d)
569 return {};
570 return d->values();
571 }
572
573 size_type count(const Key &key) const
574 {
575 if (!d)
576 return 0;
577 return d->count(key);
578 }
579
580 size_type count() const
581 {
582 return size();
583 }
584
585 inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
586 inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return (--constEnd()).key(); }
587
588 inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
589 inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
590 inline T &last() { Q_ASSERT(!isEmpty()); return *(--end()); }
591 inline const T &last() const { Q_ASSERT(!isEmpty()); return *(--constEnd()); }
592
593 class const_iterator;
594
595 class iterator
596 {
597 friend class QMap<Key, T>;
598 friend class const_iterator;
599
600 typename Map::iterator i;
601 explicit iterator(typename Map::iterator it) : i(it) {}
602 public:
603 using iterator_category = std::bidirectional_iterator_tag;
604 using difference_type = qptrdiff;
605 using value_type = T;
606 using pointer = T *;
607 using reference = T &;
608
609 iterator() = default;
610
611 const Key &key() const { return i->first; }
612 T &value() const { return i->second; }
613 T &operator*() const { return i->second; }
614 T *operator->() const { return &i->second; }
615 friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
616 friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
617
618 iterator &operator++()
619 {
620 ++i;
621 return *this;
622 }
623 iterator operator++(int)
624 {
625 iterator r = *this;
626 ++i;
627 return r;
628 }
629 iterator &operator--()
630 {
631 --i;
632 return *this;
633 }
634 iterator operator--(int)
635 {
636 iterator r = *this;
637 --i;
638 return r;
639 }
640
641#if QT_DEPRECATED_SINCE(6, 0)
642 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
643 //! [qmap-op-it-plus-step]
644 friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
645
646 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
647 //! [qmap-op-it-minus-step]
648 friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
649
650 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
651 iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
652
653 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
654 iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
655
656 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
657 //! [qmap-op-step-plus-it]
658 friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
659
660 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
661 //! [qmap-op-step-minus-it]
662 friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
663#endif
664 };
665
666 class const_iterator
667 {
668 friend class QMap<Key, T>;
669 typename Map::const_iterator i;
670 explicit const_iterator(typename Map::const_iterator it) : i(it) {}
671
672 public:
673 using iterator_category = std::bidirectional_iterator_tag;
674 using difference_type = qptrdiff;
675 using value_type = T;
676 using pointer = const T *;
677 using reference = const T &;
678
679 const_iterator() = default;
680 Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
681
682 const Key &key() const { return i->first; }
683 const T &value() const { return i->second; }
684 const T &operator*() const { return i->second; }
685 const T *operator->() const { return &i->second; }
686 friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
687 friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
688
689 const_iterator &operator++()
690 {
691 ++i;
692 return *this;
693 }
694 const_iterator operator++(int)
695 {
696 const_iterator r = *this;
697 ++i;
698 return r;
699 }
700 const_iterator &operator--()
701 {
702 --i;
703 return *this;
704 }
705 const_iterator operator--(int)
706 {
707 const_iterator r = *this;
708 --i;
709 return r;
710 }
711
712#if QT_DEPRECATED_SINCE(6, 0)
713 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
714 //! [qmap-op-it-plus-step-const]
715 friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
716
717 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
718 //! [qmap-op-it-minus-step-const]
719 friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
720
721 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
722 const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
723
724 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
725 const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
726
727 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
728 //! [qmap-op-step-plus-it-const]
729 friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
730
731 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
732 //! [qmap-op-step-minus-it-const]
733 friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
734#endif
735 };
736
737 class key_iterator
738 {
739 const_iterator i;
740
741 public:
742 typedef typename const_iterator::iterator_category iterator_category;
743 typedef typename const_iterator::difference_type difference_type;
744 typedef Key value_type;
745 typedef const Key *pointer;
746 typedef const Key &reference;
747
748 key_iterator() = default;
749 explicit key_iterator(const_iterator o) : i(o) { }
750
751 const Key &operator*() const { return i.key(); }
752 const Key *operator->() const { return &i.key(); }
753 bool operator==(key_iterator o) const { return i == o.i; }
754 bool operator!=(key_iterator o) const { return i != o.i; }
755
756 inline key_iterator &operator++() { ++i; return *this; }
757 inline key_iterator operator++(int) { return key_iterator(i++);}
758 inline key_iterator &operator--() { --i; return *this; }
759 inline key_iterator operator--(int) { return key_iterator(i--); }
760 const_iterator base() const { return i; }
761 };
762
763 typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
764 typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
765
766 // STL style
767 iterator begin() { detach(); return iterator(d->m.begin()); }
768 const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
769 const_iterator constBegin() const { return begin(); }
770 const_iterator cbegin() const { return begin(); }
771 iterator end() { detach(); return iterator(d->m.end()); }
772 const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
773 const_iterator constEnd() const { return end(); }
774 const_iterator cend() const { return end(); }
775 key_iterator keyBegin() const { return key_iterator(begin()); }
776 key_iterator keyEnd() const { return key_iterator(end()); }
777 key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
778 key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
779 const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
780 const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
781 const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
782 const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
783 auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMap &>(*this); }
784 auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMap &>(*this); }
785 auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMap>(std::move(*this)); }
786 auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMap>(std::move(*this)); }
787
788 iterator erase(const_iterator it)
789 {
790 return erase(it, std::next(it));
791 }
792
793 iterator erase(const_iterator afirst, const_iterator alast)
794 {
795 if (!d)
796 return iterator();
797
798 if (!d.isShared())
799 return iterator(d->m.erase(afirst.i, alast.i));
800
801 auto result = d->erase(afirst.i, alast.i);
802 d.reset(result.data);
803 return iterator(result.it);
804 }
805
806 // more Qt
807 typedef iterator Iterator;
808 typedef const_iterator ConstIterator;
809
810 iterator find(const Key &key)
811 {
812 const auto hold = referenceHoldingDetach();
813 return iterator(d->m.find(key));
814 }
815
816 const_iterator find(const Key &key) const
817 {
818 if (!d)
819 return const_iterator();
820 return const_iterator(d->m.find(key));
821 }
822
823 const_iterator constFind(const Key &key) const
824 {
825 return find(key);
826 }
827
828 iterator lowerBound(const Key &key)
829 {
830 const auto hold = referenceHoldingDetach();
831 return iterator(d->m.lower_bound(key));
832 }
833
834 const_iterator lowerBound(const Key &key) const
835 {
836 if (!d)
837 return const_iterator();
838 return const_iterator(d->m.lower_bound(key));
839 }
840
841 iterator upperBound(const Key &key)
842 {
843 const auto hold = referenceHoldingDetach();
844 return iterator(d->m.upper_bound(key));
845 }
846
847 const_iterator upperBound(const Key &key) const
848 {
849 if (!d)
850 return const_iterator();
851 return const_iterator(d->m.upper_bound(key));
852 }
853
854 iterator insert(const Key &key, const T &value)
855 {
856 const auto hold = referenceHoldingDetachExcept(key);
857 return iterator(d->m.insert_or_assign(key, value).first);
858 }
859
860 iterator insert(const_iterator pos, const Key &key, const T &value)
861 {
862 if (!d) {
863 detach();
864 return iterator(d->m.emplace(key, value).first);
865 } else if (d.isShared()) {
866 auto posDistance = std::distance(d->m.cbegin(), pos.i);
867 const auto hold = referenceHoldingDetachExcept(key);
868 auto dpos = std::next(d->m.cbegin(), posDistance);
869 return iterator(d->m.insert_or_assign(dpos, key, value));
870 }
871 return iterator(d->m.insert_or_assign(pos.i, key, value));
872 }
873
874 void insert(const QMap<Key, T> &map)
875 {
876 if (map.isEmpty())
877 return;
878
879 if (isEmpty()) {
880 *this = map;
881 return;
882 }
883
884 if (d.isShared()) {
885 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newD(new MapData);
886 const auto commit = qScopeGuard([&] { newD.swap(d); });
887 newD->fillWithMergeOf(d->m, map.d->m);
888 return;
889 }
890
891#ifdef __cpp_lib_node_extract
892 // Since std::map::merge is destructive only use it when not shared
893 auto copy = map.d->m;
894 copy.merge(d->m);
895 d->m = std::move(copy);
896#else
897 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newD(new MapData);
898 const auto commit = qScopeGuard([&] { newD.swap(d); });
899 newD->fillWithMergeOf(d->m, map.d->m);
900
901#endif
902 }
903
904 void insert(QMap<Key, T> &&map)
905 {
906 if (map.isEmpty() || map.d.isShared()) {
907 // fall back to a regular copy
908 insert(map);
909 return;
910 }
911
912 // Otherwise insert into map, and do a swap on return
913 const auto commit = qScopeGuard([&] { map.swap(*this); });
914 if (isEmpty())
915 return;
916
917 if (d.isShared()) {
918 map.d->insertMap(d->m);
919 return;
920 }
921
922#ifdef __cpp_lib_node_extract
923 map.d->m.merge(std::move(d->m));
924#else
925 // same as above
926 map.d->insertMap(d->m);
927#endif
928 }
929
930 // STL compatibility
931 [[nodiscard]]
932 inline bool empty() const
933 {
934 return isEmpty();
935 }
936
937 std::pair<iterator, iterator> equal_range(const Key &akey)
938 {
939 const auto hold = referenceHoldingDetach();
940 auto result = d->m.equal_range(akey);
941 return {iterator(result.first), iterator(result.second)};
942 }
943
944 std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
945 {
946 if (!d)
947 return {};
948 auto result = d->m.equal_range(akey);
949 return {const_iterator(result.first), const_iterator(result.second)};
950 }
951
952private:
953#ifdef Q_QDOC
954 friend size_t qHash(const QMap &key, size_t seed = 0);
955#else
956# if defined(Q_CC_GHS) || defined (Q_CC_MSVC)
957 // GHS and MSVC tries to intantiate qHash() for the noexcept running into a
958 // non-SFINAE'ed hard error... Create an artificial SFINAE context as a
959 // work-around:
960 template <typename M, std::enable_if_t<std::is_same_v<M, QMap>, bool> = true>
961 friend QtPrivate::QHashMultiReturnType<typename M::key_type, typename M::mapped_type>
962# else
963 using M = QMap;
964 friend size_t
965# endif
966 qHash(const M &key, size_t seed = 0)
967 noexcept(QHashPrivate::noexceptPairHash<typename M::key_type, typename M::mapped_type>())
968 {
969 if (!key.d)
970 return seed;
971 // don't use qHashRange to avoid its compile-time overhead:
972 return std::accumulate(key.d->m.begin(), key.d->m.end(), seed,
973 QtPrivate::QHashCombine{seed});
974 }
975#endif // !Q_QDOC
976};
977
978Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
979Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map)
980
981template <typename Key, typename T, typename Predicate>
982qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
983{
984 return QtPrivate::associative_erase_if(map, pred);
985}
986
987
988//
989// QMultiMap
990//
991
992template <class Key, class T>
993class QMultiMap
994{
995 using Map = std::multimap<Key, T>;
996 using MapData = QMapData<Map>;
997 QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
998
999 // Note: methods that look up a single element by key use lower_bound() rather
1000 // than find(). The C++ standard permits std::multimap::find() to return any
1001 // element with the matching key; libc++ 22 changed which one it returns.
1002 // lower_bound() is where insert() places new elements, so it consistently
1003 // identifies the most-recently-inserted one.
1004
1005 auto findIteratorByKey(const Key &key) const
1006 {
1007 auto i = d->m.lower_bound(key);
1008 const auto &cmp = d->m.key_comp();
1009 if (i != d->m.end() && !cmp(key, i->first))
1010 return i;
1011 return d->m.end();
1012 }
1013 auto findIteratorByKey(const Key &key)
1014 {
1015 auto i = d->m.lower_bound(key);
1016 const auto &cmp = d->m.key_comp();
1017 if (i != d->m.end() && !cmp(key, i->first))
1018 return i;
1019 return d->m.end();
1020 }
1021
1022public:
1023 using key_type = Key;
1024 using mapped_type = T;
1025 using difference_type = qptrdiff;
1026 using size_type = qsizetype;
1027
1028 QMultiMap() = default;
1029
1030 // implicitly generated special member functions are OK!
1031
1032 QMultiMap(std::initializer_list<std::pair<Key,T>> list)
1033 {
1034 for (auto &p : list)
1035 insert(p.first, p.second);
1036 }
1037
1038 void swap(QMultiMap<Key, T> &other) noexcept
1039 {
1040 d.swap(other.d);
1041 }
1042
1043 explicit QMultiMap(const QMap<Key, T> &other)
1044 : d(other.isEmpty() ? nullptr : new MapData)
1045 {
1046 if (d) {
1047 Q_ASSERT(other.d);
1048 d->m.insert(other.d->m.begin(),
1049 other.d->m.end());
1050 }
1051 }
1052
1053 explicit QMultiMap(QMap<Key, T> &&other)
1054 : d(other.isEmpty() ? nullptr : new MapData)
1055 {
1056 if (d) {
1057 Q_ASSERT(other.d);
1058 if (other.d.isShared()) {
1059 d->m.insert(other.d->m.begin(),
1060 other.d->m.end());
1061 } else {
1062#ifdef __cpp_lib_node_extract
1063 d->m.merge(std::move(other.d->m));
1064#else
1065 d->m.insert(std::make_move_iterator(other.d->m.begin()),
1066 std::make_move_iterator(other.d->m.end()));
1067#endif
1068 }
1069 }
1070 }
1071
1072 explicit QMultiMap(const std::multimap<Key, T> &other)
1073 : d(other.empty() ? nullptr : new MapData(other))
1074 {
1075 }
1076
1077 explicit QMultiMap(std::multimap<Key, T> &&other)
1078 : d(other.empty() ? nullptr : new MapData(std::move(other)))
1079 {
1080 }
1081
1082 // CHANGE: return type
1083 Q_DECL_DEPRECATED_X("Use toStdMultiMap instead")
1084 std::multimap<Key, T> toStdMap() const
1085 {
1086 return toStdMultiMap();
1087 }
1088
1089 std::multimap<Key, T> toStdMultiMap() const &
1090 {
1091 if (d)
1092 return d->m;
1093 return {};
1094 }
1095
1096 std::multimap<Key, T> toStdMultiMap() &&
1097 {
1098 if (d) {
1099 if (d.isShared())
1100 return d->m;
1101 else
1102 return std::move(d->m);
1103 }
1104
1105 return {};
1106 }
1107
1108#ifndef Q_QDOC
1109private:
1110 template <typename AKey = Key, typename AT = T,
1111 QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>
1112 friend bool comparesEqual(const QMultiMap &lhs, const QMultiMap &rhs)
1113 {
1114 if (lhs.d == rhs.d)
1115 return true;
1116 if (!lhs.d)
1117 return rhs == lhs;
1118 Q_ASSERT(lhs.d);
1119 return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
1120 }
1121 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1122 template <typename AKey = Key, typename AT = T,
1123 QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>)
1124
1125 template <typename AKey = Key, typename AT = T,
1126 QtPrivate::if_map_has_relational_operators<QMultiMap, AKey, AT> = true>
1127 friend auto compareThreeWay(const QMultiMap &lhs, const QMultiMap &rhs)
1128 {
1129 return QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.constKeyValueBegin(),
1130 lhs.constKeyValueEnd(),
1131 rhs.constKeyValueBegin(),
1132 rhs.constKeyValueEnd());
1133 }
1134 QT_DECLARE_ORDERING_HELPER_AUTO(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1135 template <typename AKey = Key, typename AT = T,
1136 QtPrivate::if_map_has_relational_operators<QMultiMap, AKey, AT> = true>)
1137public:
1138#else
1139 friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs);
1140 friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs);
1141 friend bool operator<(const QMultiMap &lhs, const QMultiMap &rhs);
1142 friend bool operator>(const QMultiMap &lhs, const QMultiMap &rhs);
1143 friend bool operator<=(const QMultiMap &lhs, const QMultiMap &rhs);
1144 friend bool operator>=(const QMultiMap &lhs, const QMultiMap &rhs);
1145 friend auto operator<=>(const QMultiMap &lhs, const QMultiMap &rhs);
1146#endif // Q_QDOC
1147
1148 size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
1149
1150 [[nodiscard]]
1151 bool isEmpty() const { return d ? d->m.empty() : true; }
1152
1153 void detach()
1154 {
1155 if (d)
1156 d.detach();
1157 else
1158 d.reset(new MapData);
1159 }
1160
1161 // A detach for holding an already shared copy, until calling function
1162 // is done using references to keys or values that might reference it.
1163 [[nodiscard]] QMultiMap referenceHoldingDetach()
1164 {
1165 if (!d) {
1166 d.reset(new MapData);
1167 } else if (d.isShared()) {
1168 auto hold = *this;
1169 d.detach();
1170 return hold;
1171 }
1172 return {};
1173 }
1174
1175 // Specialized version of referenceHoldingDetach(), which will not copy skipit, if copying
1176 [[nodiscard]] QMultiMap referenceHoldingDetachExceptFor(const typename Map::iterator &skipit)
1177 {
1178 Q_ASSERT(d.isShared());
1179 auto hold = *this;
1180 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1181 newData->copyExceptFor(d->m, skipit);
1182 d.swap(newData);
1183 return hold;
1184 }
1185
1186 bool isDetached() const noexcept
1187 {
1188 return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
1189 }
1190
1191 bool isSharedWith(const QMultiMap<Key, T> &other) const noexcept
1192 {
1193 return d == other.d; // also this makes little sense?
1194 }
1195
1196 void clear()
1197 {
1198 if (!d)
1199 return;
1200
1201 if (!d.isShared())
1202 d->m.clear();
1203 else
1204 d.reset();
1205 }
1206
1207 size_type remove(const Key &key)
1208 {
1209 if (!d)
1210 return 0;
1211
1212 if (!d.isShared())
1213 return size_type(d->m.erase(key));
1214
1215 MapData *newData = new MapData;
1216 size_type result = newData->copyIfNotEquivalentTo(d->m, key).count;
1217
1218 d.reset(newData);
1219
1220 return result;
1221 }
1222
1223 size_type remove(const Key &key, const T &value)
1224 {
1225 if (!d)
1226 return 0;
1227
1228 size_type result = 0;
1229 const auto &keyCompare = d->m.key_comp();
1230
1231 if (d.isShared()) {
1232 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1233 const auto keep = [&newData](auto it) { newData->m.insert(newData->m.cend(), *it); };
1234
1235 auto it = d->m.cbegin();
1236 const auto end = d->m.cend();
1237 for (; it != end && keyCompare(it->first, key); ++it)
1238 keep(it);
1239 // Keep matching keys if value match, otherwise skip and count
1240 for (; it != end && !keyCompare(key, it->first); ++it) {
1241 if (!(it->second == value))
1242 keep(it);
1243 else
1244 ++result;
1245 }
1246 for (; it != end; ++it)
1247 keep(it);
1248
1249 d.swap(newData);
1250 return result;
1251 }
1252
1253 // d->m.erase_if(....) would be nice, but that's C++20.
1254 // So let's do like find(keyCopy, valueCopy):
1255 auto [i, e] = d->m.equal_range(key);
1256 if (i == e)
1257 return result;
1258
1259 // value may belong to this map. As such, we need to copy it to ensure
1260 // it stays valid throughout the iteration below (which may destroy it)
1261 const T valueCopy = value;
1262 while (i != e) {
1263 if (i->second == valueCopy) {
1264 i = d->m.erase(i);
1265 ++result;
1266 } else {
1267 ++i;
1268 }
1269 }
1270
1271 return result;
1272 }
1273
1274 template <typename Predicate>
1275 size_type removeIf(Predicate pred)
1276 {
1277 return QtPrivate::associative_erase_if(*this, pred);
1278 }
1279
1280 T take(const Key &key)
1281 {
1282 if (!d)
1283 return T();
1284
1285 auto i = findIteratorByKey(key);
1286 if (d.isShared()) {
1287 if (i == d->m.end()) {
1288 // NB: take always detaches, even if the key isn't found. This is for historic reasons.
1289 detach();
1290 return T();
1291 }
1292 const auto hold = referenceHoldingDetachExceptFor(i);
1293 return i->second;
1294 }
1295
1296 if (i == d->m.end())
1297 return T();
1298
1299#ifdef __cpp_lib_node_extract
1300 return d->m.extract(i).mapped();
1301#else
1302 // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
1303 T result(std::move(i->second));
1304 d->m.erase(i);
1305 return result;
1306#endif
1307 }
1308
1309 bool contains(const Key &key) const
1310 {
1311 if (!d)
1312 return false;
1313 auto i = d->m.find(key);
1314 return i != d->m.end();
1315 }
1316
1317 bool contains(const Key &key, const T &value) const
1318 {
1319 return find(key, value) != end();
1320 }
1321
1322 Key key(const T &value, const Key &defaultKey = Key()) const
1323 {
1324 if (!d)
1325 return defaultKey;
1326
1327 return d->key(value, defaultKey);
1328 }
1329
1330 T value(const Key &key, const T &defaultValue = T()) const
1331 {
1332 if (!d)
1333 return defaultValue;
1334 auto i = findIteratorByKey(key);
1335 if (i != d->m.cend())
1336 return i->second;
1337 return defaultValue;
1338 }
1339
1340 QList<Key> keys() const
1341 {
1342 if (!d)
1343 return {};
1344 return d->keys();
1345 }
1346
1347 QList<Key> keys(const T &value) const
1348 {
1349 if (!d)
1350 return {};
1351 return d->keys(value);
1352 }
1353
1354 QList<Key> uniqueKeys() const
1355 {
1356 QList<Key> result;
1357 if (!d)
1358 return result;
1359
1360 result.reserve(size());
1361
1362 std::unique_copy(keyBegin(), keyEnd(),
1363 std::back_inserter(result));
1364
1365 result.shrink_to_fit();
1366 return result;
1367 }
1368
1369 QList<T> values() const
1370 {
1371 if (!d)
1372 return {};
1373 return d->values();
1374 }
1375
1376 QList<T> values(const Key &key) const
1377 {
1378 QList<T> result;
1379 const auto range = equal_range(key);
1380 result.reserve(std::distance(range.first, range.second));
1381 std::copy(range.first, range.second, std::back_inserter(result));
1382 return result;
1383 }
1384
1385 size_type count(const Key &key) const
1386 {
1387 if (!d)
1388 return 0;
1389 return d->count(key);
1390 }
1391
1392 size_type count(const Key &key, const T &value) const
1393 {
1394 if (!d)
1395 return 0;
1396
1397 // TODO: improve; no need of scanning the equal_range twice.
1398 auto range = d->m.equal_range(key);
1399
1400 return size_type(std::count_if(range.first,
1401 range.second,
1402 MapData::valueIsEqualTo(value)));
1403 }
1404
1405 inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
1406 inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return std::next(constEnd(), -1).key(); }
1407
1408 inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
1409 inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
1410 inline T &last() { Q_ASSERT(!isEmpty()); return *std::next(end(), -1); }
1411 inline const T &last() const { Q_ASSERT(!isEmpty()); return *std::next(constEnd(), -1); }
1412
1413 class const_iterator;
1414
1415 class iterator
1416 {
1417 friend class QMultiMap<Key, T>;
1418 friend class const_iterator;
1419
1420 typename Map::iterator i;
1421 explicit iterator(typename Map::iterator it) : i(it) {}
1422 public:
1423 using iterator_category = std::bidirectional_iterator_tag;
1424 using difference_type = qptrdiff;
1425 using value_type = T;
1426 using pointer = T *;
1427 using reference = T &;
1428
1429 iterator() = default;
1430
1431 const Key &key() const { return i->first; }
1432 T &value() const { return i->second; }
1433 T &operator*() const { return i->second; }
1434 T *operator->() const { return &i->second; }
1435 friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
1436 friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
1437
1438 iterator &operator++()
1439 {
1440 ++i;
1441 return *this;
1442 }
1443 iterator operator++(int)
1444 {
1445 iterator r = *this;
1446 ++i;
1447 return r;
1448 }
1449 iterator &operator--()
1450 {
1451 --i;
1452 return *this;
1453 }
1454 iterator operator--(int)
1455 {
1456 iterator r = *this;
1457 --i;
1458 return r;
1459 }
1460
1461#if QT_DEPRECATED_SINCE(6, 0)
1462 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1463 //! [qmultimap-op-it-plus-step]
1464 friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
1465
1466 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1467 //! [qmultimap-op-it-minus-step]
1468 friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
1469
1470 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1471 iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1472
1473 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1474 iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1475
1476 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1477 //! [qmultimap-op-step-plus-it]
1478 friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
1479
1480 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1481 //! [qmultimap-op-step-minus-it]
1482 friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
1483#endif
1484 };
1485
1486 class const_iterator
1487 {
1488 friend class QMultiMap<Key, T>;
1489 typename Map::const_iterator i;
1490 explicit const_iterator(typename Map::const_iterator it) : i(it) {}
1491
1492 public:
1493 using iterator_category = std::bidirectional_iterator_tag;
1494 using difference_type = qptrdiff;
1495 using value_type = T;
1496 using pointer = const T *;
1497 using reference = const T &;
1498
1499 const_iterator() = default;
1500 Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
1501
1502 const Key &key() const { return i->first; }
1503 const T &value() const { return i->second; }
1504 const T &operator*() const { return i->second; }
1505 const T *operator->() const { return &i->second; }
1506 friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
1507 friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
1508
1509 const_iterator &operator++()
1510 {
1511 ++i;
1512 return *this;
1513 }
1514 const_iterator operator++(int)
1515 {
1516 const_iterator r = *this;
1517 ++i;
1518 return r;
1519 }
1520 const_iterator &operator--()
1521 {
1522 --i;
1523 return *this;
1524 }
1525 const_iterator operator--(int)
1526 {
1527 const_iterator r = *this;
1528 --i;
1529 return r;
1530 }
1531
1532#if QT_DEPRECATED_SINCE(6, 0)
1533 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1534 //! [qmultimap-op-it-plus-step-const]
1535 friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
1536
1537 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1538 //! [qmultimap-op-it-minus-step-const]
1539 friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
1540
1541 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1542 const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1543
1544 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1545 const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1546
1547 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1548 //! [qmultimap-op-step-plus-it-const]
1549 friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
1550
1551 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1552 //! [qmultimap-op-step-minus-it-const]
1553 friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
1554#endif
1555 };
1556
1557 class key_iterator
1558 {
1559 const_iterator i;
1560
1561 public:
1562 typedef typename const_iterator::iterator_category iterator_category;
1563 typedef typename const_iterator::difference_type difference_type;
1564 typedef Key value_type;
1565 typedef const Key *pointer;
1566 typedef const Key &reference;
1567
1568 key_iterator() = default;
1569 explicit key_iterator(const_iterator o) : i(o) { }
1570
1571 const Key &operator*() const { return i.key(); }
1572 const Key *operator->() const { return &i.key(); }
1573 bool operator==(key_iterator o) const { return i == o.i; }
1574 bool operator!=(key_iterator o) const { return i != o.i; }
1575
1576 inline key_iterator &operator++() { ++i; return *this; }
1577 inline key_iterator operator++(int) { return key_iterator(i++);}
1578 inline key_iterator &operator--() { --i; return *this; }
1579 inline key_iterator operator--(int) { return key_iterator(i--); }
1580 const_iterator base() const { return i; }
1581 };
1582
1583 typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1584 typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1585
1586 // STL style
1587 iterator begin() { detach(); return iterator(d->m.begin()); }
1588 const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
1589 const_iterator constBegin() const { return begin(); }
1590 const_iterator cbegin() const { return begin(); }
1591 iterator end() { detach(); return iterator(d->m.end()); }
1592 const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
1593 const_iterator constEnd() const { return end(); }
1594 const_iterator cend() const { return end(); }
1595 key_iterator keyBegin() const { return key_iterator(begin()); }
1596 key_iterator keyEnd() const { return key_iterator(end()); }
1597 key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
1598 key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
1599 const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
1600 const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
1601 const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
1602 const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
1603 auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMultiMap &>(*this); }
1604 auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMultiMap &>(*this); }
1605 auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1606 auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1607
1608 iterator erase(const_iterator it)
1609 {
1610 return erase(it, std::next(it));
1611 }
1612
1613 iterator erase(const_iterator afirst, const_iterator alast)
1614 {
1615 if (!d)
1616 return iterator();
1617
1618 if (!d.isShared())
1619 return iterator(d->m.erase(afirst.i, alast.i));
1620
1621 auto result = d->erase(afirst.i, alast.i);
1622 d.reset(result.data);
1623 return iterator(result.it);
1624 }
1625
1626 // more Qt
1627 typedef iterator Iterator;
1628 typedef const_iterator ConstIterator;
1629
1630 size_type count() const
1631 {
1632 return size();
1633 }
1634
1635 iterator find(const Key &key)
1636 {
1637 const auto hold = referenceHoldingDetach();
1638 return iterator(findIteratorByKey(key));
1639 }
1640
1641 const_iterator find(const Key &key) const
1642 {
1643 if (!d)
1644 return const_iterator();
1645 return const_iterator(findIteratorByKey(key));
1646 }
1647
1648 const_iterator constFind(const Key &key) const
1649 {
1650 return find(key);
1651 }
1652
1653 iterator find(const Key &key, const T &value)
1654 {
1655 const auto hold = referenceHoldingDetach();
1656
1657 auto range = d->m.equal_range(key);
1658 auto i = std::find_if(range.first, range.second,
1659 MapData::valueIsEqualTo(value));
1660
1661 if (i != range.second)
1662 return iterator(i);
1663 return iterator(d->m.end());
1664 }
1665
1666 const_iterator find(const Key &key, const T &value) const
1667 {
1668 if (!d)
1669 return const_iterator();
1670
1671 auto range = d->m.equal_range(key);
1672 auto i = std::find_if(range.first, range.second,
1673 MapData::valueIsEqualTo(value));
1674
1675 if (i != range.second)
1676 return const_iterator(i);
1677 return const_iterator(d->m.end());
1678 }
1679
1680 const_iterator constFind(const Key &key, const T &value) const
1681 {
1682 return find(key, value);
1683 }
1684
1685 iterator lowerBound(const Key &key)
1686 {
1687 const auto hold = referenceHoldingDetach();
1688 return iterator(d->m.lower_bound(key));
1689 }
1690
1691 const_iterator lowerBound(const Key &key) const
1692 {
1693 if (!d)
1694 return const_iterator();
1695 return const_iterator(d->m.lower_bound(key));
1696 }
1697
1698 iterator upperBound(const Key &key)
1699 {
1700 const auto hold = referenceHoldingDetach();
1701 return iterator(d->m.upper_bound(key));
1702 }
1703
1704 const_iterator upperBound(const Key &key) const
1705 {
1706 if (!d)
1707 return const_iterator();
1708 return const_iterator(d->m.upper_bound(key));
1709 }
1710
1711 iterator insert(const Key &key, const T &value)
1712 {
1713 const auto hold = referenceHoldingDetach();
1714 // note that std::multimap inserts at the end of an equal_range for a key,
1715 // QMultiMap at the beginning.
1716 auto i = d->m.lower_bound(key);
1717 return iterator(d->m.insert(i, {key, value}));
1718 }
1719
1720 iterator insert(const_iterator pos, const Key &key, const T &value)
1721 {
1722 if (!d) {
1723 d.reset(new MapData);
1724 return iterator(d->m.insert({ key, value }));
1725 } else if (d.isShared()) {
1726 auto posDistance = std::distance(d->m.cbegin(), pos.i);
1727 auto hold = referenceHoldingDetach();
1728 auto dpos = std::next(d->m.cbegin(), posDistance);
1729 return iterator(d->m.insert(dpos, {key, value}));
1730 }
1731
1732 return iterator(d->m.insert(pos.i, {key, value}));
1733 }
1734
1735#if QT_DEPRECATED_SINCE(6, 0)
1736 QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1737 iterator insertMulti(const Key &key, const T &value)
1738 {
1739 return insert(key, value);
1740 }
1741 QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1742 iterator insertMulti(const_iterator pos, const Key &key, const T &value)
1743 {
1744 return insert(pos, key, value);
1745 }
1746
1747 QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1748 void insert(const QMultiMap<Key, T> &map)
1749 {
1750 unite(map);
1751 }
1752
1753 QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1754 void insert(QMultiMap<Key, T> &&map)
1755 {
1756 unite(std::move(map));
1757 }
1758#endif
1759
1760 iterator replace(const Key &key, const T &value)
1761 {
1762 if (!d) {
1763 d.reset(new MapData);
1764 return iterator(d->m.insert({ key, value }));
1765 }
1766 auto i = findIteratorByKey(key);
1767 if (d.isShared()) {
1768 const auto hold = referenceHoldingDetachExceptFor(i);
1769 return iterator(d->m.insert({ key, value }));
1770 }
1771
1772 // Similarly, improve here (e.g. lower_bound and hinted insert);
1773 // there's no insert_or_assign on multimaps
1774 if (i != d->m.end())
1775 i->second = value;
1776 else
1777 i = d->m.insert({key, value});
1778
1779 return iterator(i);
1780 }
1781
1782 // STL compatibility
1783 [[nodiscard]]
1784 inline bool empty() const { return isEmpty(); }
1785
1786 std::pair<iterator, iterator> equal_range(const Key &akey)
1787 {
1788 const auto hold = referenceHoldingDetach();
1789 auto result = d->m.equal_range(akey);
1790 return {iterator(result.first), iterator(result.second)};
1791 }
1792
1793 std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
1794 {
1795 if (!d)
1796 return {};
1797 auto result = d->m.equal_range(akey);
1798 return {const_iterator(result.first), const_iterator(result.second)};
1799 }
1800
1801 QMultiMap &unite(const QMultiMap &other)
1802 {
1803 if (other.isEmpty())
1804 return *this;
1805
1806 detach();
1807
1808 auto copy = other.d->m;
1809#ifdef __cpp_lib_node_extract
1810 copy.merge(std::move(d->m));
1811#else
1812 copy.insert(std::make_move_iterator(d->m.begin()),
1813 std::make_move_iterator(d->m.end()));
1814#endif
1815 d->m = std::move(copy);
1816 return *this;
1817 }
1818
1819 QMultiMap &unite(QMultiMap<Key, T> &&other)
1820 {
1821 if (!other.d || other.d->m.empty())
1822 return *this;
1823
1824 if (other.d.isShared()) {
1825 // fall back to a regular copy
1826 unite(other);
1827 return *this;
1828 }
1829
1830 detach();
1831
1832#ifdef __cpp_lib_node_extract
1833 other.d->m.merge(std::move(d->m));
1834#else
1835 other.d->m.insert(std::make_move_iterator(d->m.begin()),
1836 std::make_move_iterator(d->m.end()));
1837#endif
1838 *this = std::move(other);
1839 return *this;
1840 }
1841};
1842
1843Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap)
1844Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap)
1845
1846template <typename Key, typename T>
1847QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1848{
1849 auto result = lhs;
1850 result += rhs;
1851 return result;
1852}
1853
1854template <typename Key, typename T>
1855QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1856{
1857 return lhs.unite(rhs);
1858}
1859
1860template <typename Key, typename T, typename Predicate>
1861qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
1862{
1863 return QtPrivate::associative_erase_if(map, pred);
1864}
1865
1866QT_END_NAMESPACE
1867
1868#endif // QMAP_H
Definition qlist.h:81
Definition qmap.h:295
std::map< Key, T > toStdMap() const &
Definition qmap.h:333
QMap()=default
friend size_t qHash(const M &key, size_t seed=0) noexcept(QHashPrivate::noexceptPairHash< typename M::key_type, typename M::mapped_type >())
Definition qmap.h:966
T mapped_type
Definition qmap.h:304
QMap(std::map< Key, T > &&other)
Definition qmap.h:328
Key key_type
Definition qmap.h:303
std::map< Key, T > toStdMap() &&
Definition qmap.h:340
QMap(const std::map< Key, T > &other)
Definition qmap.h:323
friend bool comparesEqual(const QMap &lhs, const QMap &rhs)
Definition qmap.h:356
QMap(std::initializer_list< std::pair< Key, T > > list)
Definition qmap.h:317
void swap(QMap< Key, T > &other) noexcept
Definition qmap.h:312
void sync() override
~QWinSettingsPrivate() override
void clear() override
bool isWritable() const override
void set(const QString &uKey, const QVariant &value) override
void remove(const QString &uKey) override
QStringList children(const QString &uKey, ChildSpec spec) const override
std::optional< QVariant > get(const QString &uKey) const override
std::optional< QVariant > readKey(HKEY parentHandle, const QString &rSubKey) const
void flush() override
QWinSettingsPrivate(QString rKey, REGSAM access=0)
QString fileName() const override
HKEY handle() const
bool readOnly() const
HKEY parentHandle() const
RegistryKey(HKEY parent_handle=0, const QString &key=QString(), bool read_only=true, REGSAM access=0)
QString key() const
Combined button and popup list for selecting options.
qsizetype erase_if(QMultiHash< Key, T > &hash, Predicate pred)
Definition qhash.h:2783
QMultiMap< Key, T > operator+=(QMultiMap< Key, T > &lhs, const QMultiMap< Key, T > &rhs)
Definition qmap.h:1855
static void deleteChildGroups(HKEY parentHandle, REGSAM access=0)
static QString escapedKey(QString uKey)
QList< RegistryKey > RegistryKeyList
static void mergeKeySets(NameSet *dest, const NameSet &src)
static QString unescapedKey(QString rKey)
static void allKeys(HKEY parentHandle, const QString &rSubKey, NameSet *result, REGSAM access=0)
static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access=0)
static QString keyPath(const QString &rKey)
static QString keyName(const QString &rKey)
#define KEY_WOW64_32KEY
QMap< QString, QString > NameSet
static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildSpec spec)
static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access=0)
#define KEY_WOW64_64KEY
static const REGSAM registryPermissions
static HKEY createOrOpenKey(HKEY parentHandle, const QString &rSubKey, bool *readOnly, REGSAM access=0)