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
999public:
1000 using key_type = Key;
1001 using mapped_type = T;
1002 using difference_type = qptrdiff;
1003 using size_type = qsizetype;
1004
1005 QMultiMap() = default;
1006
1007 // implicitly generated special member functions are OK!
1008
1009 QMultiMap(std::initializer_list<std::pair<Key,T>> list)
1010 {
1011 for (auto &p : list)
1012 insert(p.first, p.second);
1013 }
1014
1015 void swap(QMultiMap<Key, T> &other) noexcept
1016 {
1017 d.swap(other.d);
1018 }
1019
1020 explicit QMultiMap(const QMap<Key, T> &other)
1021 : d(other.isEmpty() ? nullptr : new MapData)
1022 {
1023 if (d) {
1024 Q_ASSERT(other.d);
1025 d->m.insert(other.d->m.begin(),
1026 other.d->m.end());
1027 }
1028 }
1029
1030 explicit QMultiMap(QMap<Key, T> &&other)
1031 : d(other.isEmpty() ? nullptr : new MapData)
1032 {
1033 if (d) {
1034 Q_ASSERT(other.d);
1035 if (other.d.isShared()) {
1036 d->m.insert(other.d->m.begin(),
1037 other.d->m.end());
1038 } else {
1039#ifdef __cpp_lib_node_extract
1040 d->m.merge(std::move(other.d->m));
1041#else
1042 d->m.insert(std::make_move_iterator(other.d->m.begin()),
1043 std::make_move_iterator(other.d->m.end()));
1044#endif
1045 }
1046 }
1047 }
1048
1049 explicit QMultiMap(const std::multimap<Key, T> &other)
1050 : d(other.empty() ? nullptr : new MapData(other))
1051 {
1052 }
1053
1054 explicit QMultiMap(std::multimap<Key, T> &&other)
1055 : d(other.empty() ? nullptr : new MapData(std::move(other)))
1056 {
1057 }
1058
1059 // CHANGE: return type
1060 Q_DECL_DEPRECATED_X("Use toStdMultiMap instead")
1061 std::multimap<Key, T> toStdMap() const
1062 {
1063 return toStdMultiMap();
1064 }
1065
1066 std::multimap<Key, T> toStdMultiMap() const &
1067 {
1068 if (d)
1069 return d->m;
1070 return {};
1071 }
1072
1073 std::multimap<Key, T> toStdMultiMap() &&
1074 {
1075 if (d) {
1076 if (d.isShared())
1077 return d->m;
1078 else
1079 return std::move(d->m);
1080 }
1081
1082 return {};
1083 }
1084
1085#ifndef Q_QDOC
1086private:
1087 template <typename AKey = Key, typename AT = T,
1088 QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>
1089 friend bool comparesEqual(const QMultiMap &lhs, const QMultiMap &rhs)
1090 {
1091 if (lhs.d == rhs.d)
1092 return true;
1093 if (!lhs.d)
1094 return rhs == lhs;
1095 Q_ASSERT(lhs.d);
1096 return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
1097 }
1098 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1099 template <typename AKey = Key, typename AT = T,
1100 QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>)
1101
1102 template <typename AKey = Key, typename AT = T,
1103 QtPrivate::if_map_has_relational_operators<QMultiMap, AKey, AT> = true>
1104 friend auto compareThreeWay(const QMultiMap &lhs, const QMultiMap &rhs)
1105 {
1106 return QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.constKeyValueBegin(),
1107 lhs.constKeyValueEnd(),
1108 rhs.constKeyValueBegin(),
1109 rhs.constKeyValueEnd());
1110 }
1111 QT_DECLARE_ORDERING_HELPER_AUTO(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1112 template <typename AKey = Key, typename AT = T,
1113 QtPrivate::if_map_has_relational_operators<QMultiMap, AKey, AT> = true>)
1114public:
1115#else
1116 friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs);
1117 friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs);
1118 friend bool operator<(const QMultiMap &lhs, const QMultiMap &rhs);
1119 friend bool operator>(const QMultiMap &lhs, const QMultiMap &rhs);
1120 friend bool operator<=(const QMultiMap &lhs, const QMultiMap &rhs);
1121 friend bool operator>=(const QMultiMap &lhs, const QMultiMap &rhs);
1122 friend auto operator<=>(const QMultiMap &lhs, const QMultiMap &rhs);
1123#endif // Q_QDOC
1124
1125 size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
1126
1127 [[nodiscard]]
1128 bool isEmpty() const { return d ? d->m.empty() : true; }
1129
1130 void detach()
1131 {
1132 if (d)
1133 d.detach();
1134 else
1135 d.reset(new MapData);
1136 }
1137
1138 // A detach for holding an already shared copy, until calling function
1139 // is done using references to keys or values that might reference it.
1140 [[nodiscard]] QMultiMap referenceHoldingDetach()
1141 {
1142 if (!d) {
1143 d.reset(new MapData);
1144 } else if (d.isShared()) {
1145 auto hold = *this;
1146 d.detach();
1147 return hold;
1148 }
1149 return {};
1150 }
1151
1152 // Specialized version of referenceHoldingDetach(), which will not copy skipit, if copying
1153 [[nodiscard]] QMultiMap referenceHoldingDetachExceptFor(const typename Map::iterator &skipit)
1154 {
1155 Q_ASSERT(d.isShared());
1156 auto hold = *this;
1157 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1158 newData->copyExceptFor(d->m, skipit);
1159 d.swap(newData);
1160 return hold;
1161 }
1162
1163 bool isDetached() const noexcept
1164 {
1165 return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
1166 }
1167
1168 bool isSharedWith(const QMultiMap<Key, T> &other) const noexcept
1169 {
1170 return d == other.d; // also this makes little sense?
1171 }
1172
1173 void clear()
1174 {
1175 if (!d)
1176 return;
1177
1178 if (!d.isShared())
1179 d->m.clear();
1180 else
1181 d.reset();
1182 }
1183
1184 size_type remove(const Key &key)
1185 {
1186 if (!d)
1187 return 0;
1188
1189 if (!d.isShared())
1190 return size_type(d->m.erase(key));
1191
1192 MapData *newData = new MapData;
1193 size_type result = newData->copyIfNotEquivalentTo(d->m, key).count;
1194
1195 d.reset(newData);
1196
1197 return result;
1198 }
1199
1200 size_type remove(const Key &key, const T &value)
1201 {
1202 if (!d)
1203 return 0;
1204
1205 size_type result = 0;
1206 const auto &keyCompare = d->m.key_comp();
1207
1208 if (d.isShared()) {
1209 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1210 const auto keep = [&newData](auto it) { newData->m.insert(newData->m.cend(), *it); };
1211
1212 auto it = d->m.cbegin();
1213 const auto end = d->m.cend();
1214 for (; it != end && keyCompare(it->first, key); ++it)
1215 keep(it);
1216 // Keep matching keys if value match, otherwise skip and count
1217 for (; it != end && !keyCompare(key, it->first); ++it) {
1218 if (!(it->second == value))
1219 keep(it);
1220 else
1221 ++result;
1222 }
1223 for (; it != end; ++it)
1224 keep(it);
1225
1226 d.swap(newData);
1227 return result;
1228 }
1229
1230 // d->m.erase_if(....) would be nice, but that's C++20.
1231 // So let's do like find(keyCopy, valueCopy):
1232 auto [i, e] = d->m.equal_range(key);
1233 if (i == e)
1234 return result;
1235
1236 // value may belong to this map. As such, we need to copy it to ensure
1237 // it stays valid throughout the iteration below (which may destroy it)
1238 const T valueCopy = value;
1239 while (i != e) {
1240 if (i->second == valueCopy) {
1241 i = d->m.erase(i);
1242 ++result;
1243 } else {
1244 ++i;
1245 }
1246 }
1247
1248 return result;
1249 }
1250
1251 template <typename Predicate>
1252 size_type removeIf(Predicate pred)
1253 {
1254 return QtPrivate::associative_erase_if(*this, pred);
1255 }
1256
1257 T take(const Key &key)
1258 {
1259 if (!d)
1260 return T();
1261
1262 if (d.isShared()) {
1263 auto i = d->m.find(key);
1264 const auto hold = referenceHoldingDetachExceptFor(i);
1265 return i->second;
1266 }
1267
1268#ifdef __cpp_lib_node_extract
1269 if (const auto node = d->m.extract(key))
1270 return std::move(node.mapped());
1271#else
1272 auto i = d->m.find(key);
1273 if (i != d->m.end()) {
1274 // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
1275 T result(std::move(i->second));
1276 d->m.erase(i);
1277 return result;
1278 }
1279#endif
1280 return T();
1281 }
1282
1283 bool contains(const Key &key) const
1284 {
1285 if (!d)
1286 return false;
1287 auto i = d->m.find(key);
1288 return i != d->m.end();
1289 }
1290
1291 bool contains(const Key &key, const T &value) const
1292 {
1293 return find(key, value) != end();
1294 }
1295
1296 Key key(const T &value, const Key &defaultKey = Key()) const
1297 {
1298 if (!d)
1299 return defaultKey;
1300
1301 return d->key(value, defaultKey);
1302 }
1303
1304 T value(const Key &key, const T &defaultValue = T()) const
1305 {
1306 if (!d)
1307 return defaultValue;
1308 const auto i = d->m.find(key);
1309 if (i != d->m.cend())
1310 return i->second;
1311 return defaultValue;
1312 }
1313
1314 QList<Key> keys() const
1315 {
1316 if (!d)
1317 return {};
1318 return d->keys();
1319 }
1320
1321 QList<Key> keys(const T &value) const
1322 {
1323 if (!d)
1324 return {};
1325 return d->keys(value);
1326 }
1327
1328 QList<Key> uniqueKeys() const
1329 {
1330 QList<Key> result;
1331 if (!d)
1332 return result;
1333
1334 result.reserve(size());
1335
1336 std::unique_copy(keyBegin(), keyEnd(),
1337 std::back_inserter(result));
1338
1339 result.shrink_to_fit();
1340 return result;
1341 }
1342
1343 QList<T> values() const
1344 {
1345 if (!d)
1346 return {};
1347 return d->values();
1348 }
1349
1350 QList<T> values(const Key &key) const
1351 {
1352 QList<T> result;
1353 const auto range = equal_range(key);
1354 result.reserve(std::distance(range.first, range.second));
1355 std::copy(range.first, range.second, std::back_inserter(result));
1356 return result;
1357 }
1358
1359 size_type count(const Key &key) const
1360 {
1361 if (!d)
1362 return 0;
1363 return d->count(key);
1364 }
1365
1366 size_type count(const Key &key, const T &value) const
1367 {
1368 if (!d)
1369 return 0;
1370
1371 // TODO: improve; no need of scanning the equal_range twice.
1372 auto range = d->m.equal_range(key);
1373
1374 return size_type(std::count_if(range.first,
1375 range.second,
1376 MapData::valueIsEqualTo(value)));
1377 }
1378
1379 inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
1380 inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return std::next(constEnd(), -1).key(); }
1381
1382 inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
1383 inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
1384 inline T &last() { Q_ASSERT(!isEmpty()); return *std::next(end(), -1); }
1385 inline const T &last() const { Q_ASSERT(!isEmpty()); return *std::next(constEnd(), -1); }
1386
1387 class const_iterator;
1388
1389 class iterator
1390 {
1391 friend class QMultiMap<Key, T>;
1392 friend class const_iterator;
1393
1394 typename Map::iterator i;
1395 explicit iterator(typename Map::iterator it) : i(it) {}
1396 public:
1397 using iterator_category = std::bidirectional_iterator_tag;
1398 using difference_type = qptrdiff;
1399 using value_type = T;
1400 using pointer = T *;
1401 using reference = T &;
1402
1403 iterator() = default;
1404
1405 const Key &key() const { return i->first; }
1406 T &value() const { return i->second; }
1407 T &operator*() const { return i->second; }
1408 T *operator->() const { return &i->second; }
1409 friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
1410 friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
1411
1412 iterator &operator++()
1413 {
1414 ++i;
1415 return *this;
1416 }
1417 iterator operator++(int)
1418 {
1419 iterator r = *this;
1420 ++i;
1421 return r;
1422 }
1423 iterator &operator--()
1424 {
1425 --i;
1426 return *this;
1427 }
1428 iterator operator--(int)
1429 {
1430 iterator r = *this;
1431 --i;
1432 return r;
1433 }
1434
1435#if QT_DEPRECATED_SINCE(6, 0)
1436 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1437 //! [qmultimap-op-it-plus-step]
1438 friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
1439
1440 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1441 //! [qmultimap-op-it-minus-step]
1442 friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
1443
1444 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1445 iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1446
1447 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1448 iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1449
1450 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1451 //! [qmultimap-op-step-plus-it]
1452 friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
1453
1454 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1455 //! [qmultimap-op-step-minus-it]
1456 friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
1457#endif
1458 };
1459
1460 class const_iterator
1461 {
1462 friend class QMultiMap<Key, T>;
1463 typename Map::const_iterator i;
1464 explicit const_iterator(typename Map::const_iterator it) : i(it) {}
1465
1466 public:
1467 using iterator_category = std::bidirectional_iterator_tag;
1468 using difference_type = qptrdiff;
1469 using value_type = T;
1470 using pointer = const T *;
1471 using reference = const T &;
1472
1473 const_iterator() = default;
1474 Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
1475
1476 const Key &key() const { return i->first; }
1477 const T &value() const { return i->second; }
1478 const T &operator*() const { return i->second; }
1479 const T *operator->() const { return &i->second; }
1480 friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
1481 friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
1482
1483 const_iterator &operator++()
1484 {
1485 ++i;
1486 return *this;
1487 }
1488 const_iterator operator++(int)
1489 {
1490 const_iterator r = *this;
1491 ++i;
1492 return r;
1493 }
1494 const_iterator &operator--()
1495 {
1496 --i;
1497 return *this;
1498 }
1499 const_iterator operator--(int)
1500 {
1501 const_iterator r = *this;
1502 --i;
1503 return r;
1504 }
1505
1506#if QT_DEPRECATED_SINCE(6, 0)
1507 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1508 //! [qmultimap-op-it-plus-step-const]
1509 friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
1510
1511 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1512 //! [qmultimap-op-it-minus-step-const]
1513 friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
1514
1515 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1516 const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1517
1518 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1519 const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1520
1521 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1522 //! [qmultimap-op-step-plus-it-const]
1523 friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
1524
1525 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1526 //! [qmultimap-op-step-minus-it-const]
1527 friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
1528#endif
1529 };
1530
1531 class key_iterator
1532 {
1533 const_iterator i;
1534
1535 public:
1536 typedef typename const_iterator::iterator_category iterator_category;
1537 typedef typename const_iterator::difference_type difference_type;
1538 typedef Key value_type;
1539 typedef const Key *pointer;
1540 typedef const Key &reference;
1541
1542 key_iterator() = default;
1543 explicit key_iterator(const_iterator o) : i(o) { }
1544
1545 const Key &operator*() const { return i.key(); }
1546 const Key *operator->() const { return &i.key(); }
1547 bool operator==(key_iterator o) const { return i == o.i; }
1548 bool operator!=(key_iterator o) const { return i != o.i; }
1549
1550 inline key_iterator &operator++() { ++i; return *this; }
1551 inline key_iterator operator++(int) { return key_iterator(i++);}
1552 inline key_iterator &operator--() { --i; return *this; }
1553 inline key_iterator operator--(int) { return key_iterator(i--); }
1554 const_iterator base() const { return i; }
1555 };
1556
1557 typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1558 typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1559
1560 // STL style
1561 iterator begin() { detach(); return iterator(d->m.begin()); }
1562 const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
1563 const_iterator constBegin() const { return begin(); }
1564 const_iterator cbegin() const { return begin(); }
1565 iterator end() { detach(); return iterator(d->m.end()); }
1566 const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
1567 const_iterator constEnd() const { return end(); }
1568 const_iterator cend() const { return end(); }
1569 key_iterator keyBegin() const { return key_iterator(begin()); }
1570 key_iterator keyEnd() const { return key_iterator(end()); }
1571 key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
1572 key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
1573 const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
1574 const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
1575 const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
1576 const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
1577 auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMultiMap &>(*this); }
1578 auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMultiMap &>(*this); }
1579 auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1580 auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1581
1582 iterator erase(const_iterator it)
1583 {
1584 return erase(it, std::next(it));
1585 }
1586
1587 iterator erase(const_iterator afirst, const_iterator alast)
1588 {
1589 if (!d)
1590 return iterator();
1591
1592 if (!d.isShared())
1593 return iterator(d->m.erase(afirst.i, alast.i));
1594
1595 auto result = d->erase(afirst.i, alast.i);
1596 d.reset(result.data);
1597 return iterator(result.it);
1598 }
1599
1600 // more Qt
1601 typedef iterator Iterator;
1602 typedef const_iterator ConstIterator;
1603
1604 size_type count() const
1605 {
1606 return size();
1607 }
1608
1609 iterator find(const Key &key)
1610 {
1611 const auto hold = referenceHoldingDetach();
1612 return iterator(d->m.find(key));
1613 }
1614
1615 const_iterator find(const Key &key) const
1616 {
1617 if (!d)
1618 return const_iterator();
1619 return const_iterator(d->m.find(key));
1620 }
1621
1622 const_iterator constFind(const Key &key) const
1623 {
1624 return find(key);
1625 }
1626
1627 iterator find(const Key &key, const T &value)
1628 {
1629 const auto hold = referenceHoldingDetach();
1630
1631 auto range = d->m.equal_range(key);
1632 auto i = std::find_if(range.first, range.second,
1633 MapData::valueIsEqualTo(value));
1634
1635 if (i != range.second)
1636 return iterator(i);
1637 return iterator(d->m.end());
1638 }
1639
1640 const_iterator find(const Key &key, const T &value) const
1641 {
1642 if (!d)
1643 return const_iterator();
1644
1645 auto range = d->m.equal_range(key);
1646 auto i = std::find_if(range.first, range.second,
1647 MapData::valueIsEqualTo(value));
1648
1649 if (i != range.second)
1650 return const_iterator(i);
1651 return const_iterator(d->m.end());
1652 }
1653
1654 const_iterator constFind(const Key &key, const T &value) const
1655 {
1656 return find(key, value);
1657 }
1658
1659 iterator lowerBound(const Key &key)
1660 {
1661 const auto hold = referenceHoldingDetach();
1662 return iterator(d->m.lower_bound(key));
1663 }
1664
1665 const_iterator lowerBound(const Key &key) const
1666 {
1667 if (!d)
1668 return const_iterator();
1669 return const_iterator(d->m.lower_bound(key));
1670 }
1671
1672 iterator upperBound(const Key &key)
1673 {
1674 const auto hold = referenceHoldingDetach();
1675 return iterator(d->m.upper_bound(key));
1676 }
1677
1678 const_iterator upperBound(const Key &key) const
1679 {
1680 if (!d)
1681 return const_iterator();
1682 return const_iterator(d->m.upper_bound(key));
1683 }
1684
1685 iterator insert(const Key &key, const T &value)
1686 {
1687 const auto hold = referenceHoldingDetach();
1688 // note that std::multimap inserts at the end of an equal_range for a key,
1689 // QMultiMap at the beginning.
1690 auto i = d->m.lower_bound(key);
1691 return iterator(d->m.insert(i, {key, value}));
1692 }
1693
1694 iterator insert(const_iterator pos, const Key &key, const T &value)
1695 {
1696 if (!d) {
1697 d.reset(new MapData);
1698 return iterator(d->m.insert({ key, value }));
1699 } else if (d.isShared()) {
1700 auto posDistance = std::distance(d->m.cbegin(), pos.i);
1701 auto hold = referenceHoldingDetach();
1702 auto dpos = std::next(d->m.cbegin(), posDistance);
1703 return iterator(d->m.insert(dpos, {key, value}));
1704 }
1705
1706 return iterator(d->m.insert(pos.i, {key, value}));
1707 }
1708
1709#if QT_DEPRECATED_SINCE(6, 0)
1710 QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1711 iterator insertMulti(const Key &key, const T &value)
1712 {
1713 return insert(key, value);
1714 }
1715 QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1716 iterator insertMulti(const_iterator pos, const Key &key, const T &value)
1717 {
1718 return insert(pos, key, value);
1719 }
1720
1721 QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1722 void insert(const QMultiMap<Key, T> &map)
1723 {
1724 unite(map);
1725 }
1726
1727 QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1728 void insert(QMultiMap<Key, T> &&map)
1729 {
1730 unite(std::move(map));
1731 }
1732#endif
1733
1734 iterator replace(const Key &key, const T &value)
1735 {
1736 if (!d) {
1737 d.reset(new MapData);
1738 return iterator(d->m.insert({ key, value }));
1739 }
1740 auto i = d->m.find(key);
1741 if (d.isShared()) {
1742 const auto hold = referenceHoldingDetachExceptFor(i);
1743 return iterator(d->m.insert({ key, value }));
1744 }
1745
1746 // Similarly, improve here (e.g. lower_bound and hinted insert);
1747 // there's no insert_or_assign on multimaps
1748 if (i != d->m.end())
1749 i->second = value;
1750 else
1751 i = d->m.insert({key, value});
1752
1753 return iterator(i);
1754 }
1755
1756 // STL compatibility
1757 [[nodiscard]]
1758 inline bool empty() const { return isEmpty(); }
1759
1760 std::pair<iterator, iterator> equal_range(const Key &akey)
1761 {
1762 const auto hold = referenceHoldingDetach();
1763 auto result = d->m.equal_range(akey);
1764 return {iterator(result.first), iterator(result.second)};
1765 }
1766
1767 std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
1768 {
1769 if (!d)
1770 return {};
1771 auto result = d->m.equal_range(akey);
1772 return {const_iterator(result.first), const_iterator(result.second)};
1773 }
1774
1775 QMultiMap &unite(const QMultiMap &other)
1776 {
1777 if (other.isEmpty())
1778 return *this;
1779
1780 detach();
1781
1782 auto copy = other.d->m;
1783#ifdef __cpp_lib_node_extract
1784 copy.merge(std::move(d->m));
1785#else
1786 copy.insert(std::make_move_iterator(d->m.begin()),
1787 std::make_move_iterator(d->m.end()));
1788#endif
1789 d->m = std::move(copy);
1790 return *this;
1791 }
1792
1793 QMultiMap &unite(QMultiMap<Key, T> &&other)
1794 {
1795 if (!other.d || other.d->m.empty())
1796 return *this;
1797
1798 if (other.d.isShared()) {
1799 // fall back to a regular copy
1800 unite(other);
1801 return *this;
1802 }
1803
1804 detach();
1805
1806#ifdef __cpp_lib_node_extract
1807 other.d->m.merge(std::move(d->m));
1808#else
1809 other.d->m.insert(std::make_move_iterator(d->m.begin()),
1810 std::make_move_iterator(d->m.end()));
1811#endif
1812 *this = std::move(other);
1813 return *this;
1814 }
1815};
1816
1817Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap)
1818Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap)
1819
1820template <typename Key, typename T>
1821QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1822{
1823 auto result = lhs;
1824 result += rhs;
1825 return result;
1826}
1827
1828template <typename Key, typename T>
1829QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1830{
1831 return lhs.unite(rhs);
1832}
1833
1834template <typename Key, typename T, typename Predicate>
1835qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
1836{
1837 return QtPrivate::associative_erase_if(map, pred);
1838}
1839
1840QT_END_NAMESPACE
1841
1842#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:1829
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)