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.
408 [[nodiscard]]
410 {
411 if (!d) {
412 d.reset(new MapData);
413 } else if (d.isShared()) {
414 auto hold = *this;
415 d.detach();
416 return hold;
417 }
418 return {};
419 }
420
421 // Specialized version of referenceHoldingDetach(), which will not copy key, if copying
422 [[nodiscard]]
424 {
425 if (!d) {
426 d.reset(new MapData);
427 } else if (d.isShared()) {
428 auto hold = *this;
431 d.swap(newData);
432 return hold;
433 }
434 return {};
435 }
436
437 bool isDetached() const noexcept
438 {
439 return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
440 }
441
442 bool isSharedWith(const QMap<Key, T> &other) const noexcept
443 {
444 return d == other.d; // also this makes little sense?
445 }
446
447 void clear()
448 {
449 if (!d)
450 return;
451
452 if (!d.isShared())
453 d->m.clear();
454 else
455 d.reset();
456 }
457
458 size_type remove(const Key &key)
459 {
460 if (!d)
461 return 0;
462
463 if (!d.isShared())
464 return size_type(d->m.erase(key));
465
466 MapData *newData = new MapData;
468
469 d.reset(newData);
470
471 return result;
472 }
473
474 template <typename Predicate>
476 {
477 return QtPrivate::associative_erase_if(*this, pred);
478 }
479
480 T take(const Key &key)
481 {
482 if (!d)
483 return T();
484
485 if (d.isShared()) {
486 MapData *m = new MapData;
487 // For historic reasons, we always un-share (was: detach()) when
488 // this function is called, even if `key` isn't found
489 const auto commit = qScopeGuard([&] { d.reset(m); });
490
491 auto result = m->copyIfNotEquivalentTo(d->m, key);
492 if (result.count)
493 return result.iterator->second;
494 // if we reach here, `key` wasn't found:
495 return T();
496 }
497
498#ifdef __cpp_lib_node_extract
499 if (const auto node = d->m.extract(key))
500 return std::move(node.mapped());
501#else
502 auto i = d->m.find(key);
503 if (i != d->m.end()) {
504 // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
505 T result(std::move(i->second));
506 d->m.erase(i);
507 return result;
508 }
509#endif
510 return T();
511 }
512
513 bool contains(const Key &key) const
514 {
515 if (!d)
516 return false;
517 auto i = d->m.find(key);
518 return i != d->m.end();
519 }
520
521 Key key(const T &value, const Key &defaultKey = Key()) const
522 {
523 if (!d)
524 return defaultKey;
525
526 return d->key(value, defaultKey);
527 }
528
529 T value(const Key &key, const T &defaultValue = T()) const
530 {
531 if (!d)
532 return defaultValue;
533 const auto i = d->m.find(key);
534 if (i != d->m.cend())
535 return i->second;
536 return defaultValue;
537 }
538
539 T &operator[](const Key &key)
540 {
541 const auto hold = referenceHoldingDetach();
542 auto i = d->m.find(key);
543 if (i == d->m.end())
544 i = d->m.insert({key, T()}).first;
545 return i->second;
546 }
547
548 // CHANGE: return T, not const T!
549 T operator[](const Key &key) const
550 {
551 return value(key);
552 }
553
554 QList<Key> keys() const
555 {
556 if (!d)
557 return {};
558 return d->keys();
559 }
560
561 QList<Key> keys(const T &value) const
562 {
563 if (!d)
564 return {};
565 return d->keys(value);
566 }
567
568 QList<T> values() const
569 {
570 if (!d)
571 return {};
572 return d->values();
573 }
574
575 size_type count(const Key &key) const
576 {
577 if (!d)
578 return 0;
579 return d->count(key);
580 }
581
582 size_type count() const
583 {
584 return size();
585 }
586
587 inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
588 inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return (--constEnd()).key(); }
589
590 inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
591 inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
592 inline T &last() { Q_ASSERT(!isEmpty()); return *(--end()); }
593 inline const T &last() const { Q_ASSERT(!isEmpty()); return *(--constEnd()); }
594
595 class const_iterator;
596
597 class iterator
598 {
599 friend class QMap<Key, T>;
600 friend class const_iterator;
601
602 typename Map::iterator i;
603 explicit iterator(typename Map::iterator it) : i(it) {}
604 public:
605 using iterator_category = std::bidirectional_iterator_tag;
606 using difference_type = qptrdiff;
607 using value_type = T;
608 using pointer = T *;
609 using reference = T &;
610
611 iterator() = default;
612
613 const Key &key() const { return i->first; }
614 T &value() const { return i->second; }
615 T &operator*() const { return i->second; }
616 T *operator->() const { return &i->second; }
617 friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
618 friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
619
620 iterator &operator++()
621 {
622 ++i;
623 return *this;
624 }
625 iterator operator++(int)
626 {
627 iterator r = *this;
628 ++i;
629 return r;
630 }
631 iterator &operator--()
632 {
633 --i;
634 return *this;
635 }
636 iterator operator--(int)
637 {
638 iterator r = *this;
639 --i;
640 return r;
641 }
642
643#if QT_DEPRECATED_SINCE(6, 0)
644 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
645 //! [qmap-op-it-plus-step]
646 friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
647
648 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
649 //! [qmap-op-it-minus-step]
650 friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
651
652 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
653 iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
654
655 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
656 iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
657
658 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
659 //! [qmap-op-step-plus-it]
660 friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
661
662 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
663 //! [qmap-op-step-minus-it]
664 friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
665#endif
666 };
667
668 class const_iterator
669 {
670 friend class QMap<Key, T>;
671 typename Map::const_iterator i;
672 explicit const_iterator(typename Map::const_iterator it) : i(it) {}
673
674 public:
675 using iterator_category = std::bidirectional_iterator_tag;
676 using difference_type = qptrdiff;
677 using value_type = T;
678 using pointer = const T *;
679 using reference = const T &;
680
681 const_iterator() = default;
682 Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
683
684 const Key &key() const { return i->first; }
685 const T &value() const { return i->second; }
686 const T &operator*() const { return i->second; }
687 const T *operator->() const { return &i->second; }
688 friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
689 friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
690
691 const_iterator &operator++()
692 {
693 ++i;
694 return *this;
695 }
696 const_iterator operator++(int)
697 {
698 const_iterator r = *this;
699 ++i;
700 return r;
701 }
702 const_iterator &operator--()
703 {
704 --i;
705 return *this;
706 }
707 const_iterator operator--(int)
708 {
709 const_iterator r = *this;
710 --i;
711 return r;
712 }
713
714#if QT_DEPRECATED_SINCE(6, 0)
715 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
716 //! [qmap-op-it-plus-step-const]
717 friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
718
719 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
720 //! [qmap-op-it-minus-step-const]
721 friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
722
723 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
724 const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
725
726 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
727 const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
728
729 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
730 //! [qmap-op-step-plus-it-const]
731 friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
732
733 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
734 //! [qmap-op-step-minus-it-const]
735 friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
736#endif
737 };
738
739 class key_iterator
740 {
741 const_iterator i;
742
743 public:
744 typedef typename const_iterator::iterator_category iterator_category;
745 typedef typename const_iterator::difference_type difference_type;
746 typedef Key value_type;
747 typedef const Key *pointer;
748 typedef const Key &reference;
749
750 key_iterator() = default;
751 explicit key_iterator(const_iterator o) : i(o) { }
752
753 const Key &operator*() const { return i.key(); }
754 const Key *operator->() const { return &i.key(); }
755 bool operator==(key_iterator o) const { return i == o.i; }
756 bool operator!=(key_iterator o) const { return i != o.i; }
757
758 inline key_iterator &operator++() { ++i; return *this; }
759 inline key_iterator operator++(int) { return key_iterator(i++);}
760 inline key_iterator &operator--() { --i; return *this; }
761 inline key_iterator operator--(int) { return key_iterator(i--); }
762 const_iterator base() const { return i; }
763 };
764
765 typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
766 typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
767
768 // STL style
769 iterator begin() { detach(); return iterator(d->m.begin()); }
770 const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
771 const_iterator constBegin() const { return begin(); }
772 const_iterator cbegin() const { return begin(); }
773 iterator end() { detach(); return iterator(d->m.end()); }
774 const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
775 const_iterator constEnd() const { return end(); }
776 const_iterator cend() const { return end(); }
777 key_iterator keyBegin() const { return key_iterator(begin()); }
778 key_iterator keyEnd() const { return key_iterator(end()); }
779 key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
780 key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
781 const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
782 const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
783 const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
784 const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
785 auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMap &>(*this); }
786 auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMap &>(*this); }
787 auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMap>(std::move(*this)); }
788 auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMap>(std::move(*this)); }
789
790 iterator erase(const_iterator it)
791 {
792 return erase(it, std::next(it));
793 }
794
795 iterator erase(const_iterator afirst, const_iterator alast)
796 {
797 if (!d)
798 return iterator();
799
800 if (!d.isShared())
801 return iterator(d->m.erase(afirst.i, alast.i));
802
803 auto result = d->erase(afirst.i, alast.i);
804 d.reset(result.data);
805 return iterator(result.it);
806 }
807
808 // more Qt
809 typedef iterator Iterator;
810 typedef const_iterator ConstIterator;
811
812 iterator find(const Key &key)
813 {
814 const auto hold = referenceHoldingDetach();
815 return iterator(d->m.find(key));
816 }
817
818 const_iterator find(const Key &key) const
819 {
820 if (!d)
821 return const_iterator();
822 return const_iterator(d->m.find(key));
823 }
824
825 const_iterator constFind(const Key &key) const
826 {
827 return find(key);
828 }
829
830 iterator lowerBound(const Key &key)
831 {
832 const auto hold = referenceHoldingDetach();
833 return iterator(d->m.lower_bound(key));
834 }
835
836 const_iterator lowerBound(const Key &key) const
837 {
838 if (!d)
839 return const_iterator();
840 return const_iterator(d->m.lower_bound(key));
841 }
842
843 iterator upperBound(const Key &key)
844 {
845 const auto hold = referenceHoldingDetach();
846 return iterator(d->m.upper_bound(key));
847 }
848
849 const_iterator upperBound(const Key &key) const
850 {
851 if (!d)
852 return const_iterator();
853 return const_iterator(d->m.upper_bound(key));
854 }
855
856 iterator insert(const Key &key, const T &value)
857 {
858 const auto hold = referenceHoldingDetachExcept(key);
859 return iterator(d->m.insert_or_assign(key, value).first);
860 }
861
862 iterator insert(const_iterator pos, const Key &key, const T &value)
863 {
864 if (!d) {
865 detach();
866 return iterator(d->m.emplace(key, value).first);
867 } else if (d.isShared()) {
868 auto posDistance = std::distance(d->m.cbegin(), pos.i);
869 const auto hold = referenceHoldingDetachExcept(key);
870 auto dpos = std::next(d->m.cbegin(), posDistance);
871 return iterator(d->m.insert_or_assign(dpos, key, value));
872 }
873 return iterator(d->m.insert_or_assign(pos.i, key, value));
874 }
875
876 void insert(const QMap<Key, T> &map)
877 {
878 if (map.isEmpty())
879 return;
880
881 if (isEmpty()) {
882 *this = map;
883 return;
884 }
885
886 if (d.isShared()) {
887 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newD(new MapData);
888 const auto commit = qScopeGuard([&] { newD.swap(d); });
889 newD->fillWithMergeOf(d->m, map.d->m);
890 return;
891 }
892
893#ifdef __cpp_lib_node_extract
894 // Since std::map::merge is destructive only use it when not shared
895 auto copy = map.d->m;
896 copy.merge(d->m);
897 d->m = std::move(copy);
898#else
899 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newD(new MapData);
900 const auto commit = qScopeGuard([&] { newD.swap(d); });
901 newD->fillWithMergeOf(d->m, map.d->m);
902
903#endif
904 }
905
906 void insert(QMap<Key, T> &&map)
907 {
908 if (map.isEmpty() || map.d.isShared()) {
909 // fall back to a regular copy
910 insert(map);
911 return;
912 }
913
914 // Otherwise insert into map, and do a swap on return
915 const auto commit = qScopeGuard([&] { map.swap(*this); });
916 if (isEmpty())
917 return;
918
919 if (d.isShared()) {
920 map.d->insertMap(d->m);
921 return;
922 }
923
924#ifdef __cpp_lib_node_extract
925 map.d->m.merge(std::move(d->m));
926#else
927 // same as above
928 map.d->insertMap(d->m);
929#endif
930 }
931
932 // STL compatibility
933 [[nodiscard]]
934 inline bool empty() const
935 {
936 return isEmpty();
937 }
938
939 std::pair<iterator, iterator> equal_range(const Key &akey)
940 {
941 const auto hold = referenceHoldingDetach();
942 auto result = d->m.equal_range(akey);
943 return {iterator(result.first), iterator(result.second)};
944 }
945
946 std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
947 {
948 if (!d)
949 return {};
950 auto result = d->m.equal_range(akey);
951 return {const_iterator(result.first), const_iterator(result.second)};
952 }
953
954private:
955#ifdef Q_QDOC
956 friend size_t qHash(const QMap &key, size_t seed = 0);
957#else
958# if defined(Q_CC_GHS) || defined (Q_CC_MSVC)
959 // GHS and MSVC tries to intantiate qHash() for the noexcept running into a
960 // non-SFINAE'ed hard error... Create an artificial SFINAE context as a
961 // work-around:
962 template <typename M, std::enable_if_t<std::is_same_v<M, QMap>, bool> = true>
963 friend QtPrivate::QHashMultiReturnType<typename M::key_type, typename M::mapped_type>
964# else
965 using M = QMap;
966 friend size_t
967# endif
968 qHash(const M &key, size_t seed = 0)
969 noexcept(QHashPrivate::noexceptPairHash<typename M::key_type, typename M::mapped_type>())
970 {
971 if (!key.d)
972 return seed;
973 // don't use qHashRange to avoid its compile-time overhead:
974 return std::accumulate(key.d->m.begin(), key.d->m.end(), seed,
975 QtPrivate::QHashCombine{seed});
976 }
977#endif // !Q_QDOC
978};
979
980Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
981Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map)
982
983template <typename Key, typename T, typename Predicate>
984qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
985{
986 return QtPrivate::associative_erase_if(map, pred);
987}
988
989
990//
991// QMultiMap
992//
993
994template <class Key, class T>
995class QMultiMap
996{
997 using Map = std::multimap<Key, T>;
998 using MapData = QMapData<Map>;
999 QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
1000
1001 // Note: methods that look up a single element by key use lower_bound() rather
1002 // than find(). The C++ standard permits std::multimap::find() to return any
1003 // element with the matching key; libc++ 22 changed which one it returns.
1004 // lower_bound() is where insert() places new elements, so it consistently
1005 // identifies the most-recently-inserted one.
1006
1007 auto findIteratorByKey(const Key &key) const
1008 {
1009 auto i = d->m.lower_bound(key);
1010 const auto &cmp = d->m.key_comp();
1011 if (i != d->m.end() && !cmp(key, i->first))
1012 return i;
1013 return d->m.end();
1014 }
1015 auto findIteratorByKey(const Key &key)
1016 {
1017 auto i = d->m.lower_bound(key);
1018 const auto &cmp = d->m.key_comp();
1019 if (i != d->m.end() && !cmp(key, i->first))
1020 return i;
1021 return d->m.end();
1022 }
1023
1024public:
1025 using key_type = Key;
1026 using mapped_type = T;
1027 using difference_type = qptrdiff;
1028 using size_type = qsizetype;
1029
1030 QMultiMap() = default;
1031
1032 // implicitly generated special member functions are OK!
1033
1034 QMultiMap(std::initializer_list<std::pair<Key,T>> list)
1035 {
1036 for (auto &p : list)
1037 insert(p.first, p.second);
1038 }
1039
1040 void swap(QMultiMap<Key, T> &other) noexcept
1041 {
1042 d.swap(other.d);
1043 }
1044
1045 explicit QMultiMap(const QMap<Key, T> &other)
1046 : d(other.isEmpty() ? nullptr : new MapData)
1047 {
1048 if (d) {
1049 Q_ASSERT(other.d);
1050 d->m.insert(other.d->m.begin(),
1051 other.d->m.end());
1052 }
1053 }
1054
1055 explicit QMultiMap(QMap<Key, T> &&other)
1056 : d(other.isEmpty() ? nullptr : new MapData)
1057 {
1058 if (d) {
1059 Q_ASSERT(other.d);
1060 if (other.d.isShared()) {
1061 d->m.insert(other.d->m.begin(),
1062 other.d->m.end());
1063 } else {
1064#ifdef __cpp_lib_node_extract
1065 d->m.merge(std::move(other.d->m));
1066#else
1067 d->m.insert(std::make_move_iterator(other.d->m.begin()),
1068 std::make_move_iterator(other.d->m.end()));
1069#endif
1070 }
1071 }
1072 }
1073
1074 explicit QMultiMap(const std::multimap<Key, T> &other)
1075 : d(other.empty() ? nullptr : new MapData(other))
1076 {
1077 }
1078
1079 explicit QMultiMap(std::multimap<Key, T> &&other)
1080 : d(other.empty() ? nullptr : new MapData(std::move(other)))
1081 {
1082 }
1083
1084 // CHANGE: return type
1085 Q_DECL_DEPRECATED_X("Use toStdMultiMap instead")
1086 std::multimap<Key, T> toStdMap() const
1087 {
1088 return toStdMultiMap();
1089 }
1090
1091 std::multimap<Key, T> toStdMultiMap() const &
1092 {
1093 if (d)
1094 return d->m;
1095 return {};
1096 }
1097
1098 std::multimap<Key, T> toStdMultiMap() &&
1099 {
1100 if (d) {
1101 if (d.isShared())
1102 return d->m;
1103 else
1104 return std::move(d->m);
1105 }
1106
1107 return {};
1108 }
1109
1110#ifndef Q_QDOC
1111private:
1112 template <typename AKey = Key, typename AT = T,
1113 QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>
1114 friend bool comparesEqual(const QMultiMap &lhs, const QMultiMap &rhs)
1115 {
1116 if (lhs.d == rhs.d)
1117 return true;
1118 if (!lhs.d)
1119 return rhs == lhs;
1120 Q_ASSERT(lhs.d);
1121 return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
1122 }
1123 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1124 template <typename AKey = Key, typename AT = T,
1125 QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> = true>)
1126
1127 template <typename AKey = Key, typename AT = T,
1128 QtPrivate::if_map_has_relational_operators<QMultiMap, AKey, AT> = true>
1129 friend auto compareThreeWay(const QMultiMap &lhs, const QMultiMap &rhs)
1130 {
1131 return QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.constKeyValueBegin(),
1132 lhs.constKeyValueEnd(),
1133 rhs.constKeyValueBegin(),
1134 rhs.constKeyValueEnd());
1135 }
1136 QT_DECLARE_ORDERING_HELPER_AUTO(QMultiMap, QMultiMap, /* non-constexpr */, noexcept(false),
1137 template <typename AKey = Key, typename AT = T,
1138 QtPrivate::if_map_has_relational_operators<QMultiMap, AKey, AT> = true>)
1139public:
1140#else
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 bool operator<=(const QMultiMap &lhs, const QMultiMap &rhs);
1146 friend bool operator>=(const QMultiMap &lhs, const QMultiMap &rhs);
1147 friend auto operator<=>(const QMultiMap &lhs, const QMultiMap &rhs);
1148#endif // Q_QDOC
1149
1150 size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
1151
1152 [[nodiscard]]
1153 bool isEmpty() const { return d ? d->m.empty() : true; }
1154
1155 void detach()
1156 {
1157 if (d)
1158 d.detach();
1159 else
1160 d.reset(new MapData);
1161 }
1162
1163 // A detach for holding an already shared copy, until calling function
1164 // is done using references to keys or values that might reference it.
1165 [[nodiscard]] QMultiMap referenceHoldingDetach()
1166 {
1167 if (!d) {
1168 d.reset(new MapData);
1169 } else if (d.isShared()) {
1170 auto hold = *this;
1171 d.detach();
1172 return hold;
1173 }
1174 return {};
1175 }
1176
1177 // Specialized version of referenceHoldingDetach(), which will not copy skipit, if copying
1178 [[nodiscard]] QMultiMap referenceHoldingDetachExceptFor(const typename Map::iterator &skipit)
1179 {
1180 Q_ASSERT(d.isShared());
1181 auto hold = *this;
1182 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1183 newData->copyExceptFor(d->m, skipit);
1184 d.swap(newData);
1185 return hold;
1186 }
1187
1188 bool isDetached() const noexcept
1189 {
1190 return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
1191 }
1192
1193 bool isSharedWith(const QMultiMap<Key, T> &other) const noexcept
1194 {
1195 return d == other.d; // also this makes little sense?
1196 }
1197
1198 void clear()
1199 {
1200 if (!d)
1201 return;
1202
1203 if (!d.isShared())
1204 d->m.clear();
1205 else
1206 d.reset();
1207 }
1208
1209 size_type remove(const Key &key)
1210 {
1211 if (!d)
1212 return 0;
1213
1214 if (!d.isShared())
1215 return size_type(d->m.erase(key));
1216
1217 MapData *newData = new MapData;
1218 size_type result = newData->copyIfNotEquivalentTo(d->m, key).count;
1219
1220 d.reset(newData);
1221
1222 return result;
1223 }
1224
1225 size_type remove(const Key &key, const T &value)
1226 {
1227 if (!d)
1228 return 0;
1229
1230 size_type result = 0;
1231 const auto &keyCompare = d->m.key_comp();
1232
1233 if (d.isShared()) {
1234 QtPrivate::QExplicitlySharedDataPointerV2<MapData> newData(new MapData);
1235 const auto keep = [&newData](auto it) { newData->m.insert(newData->m.cend(), *it); };
1236
1237 auto it = d->m.cbegin();
1238 const auto end = d->m.cend();
1239 for (; it != end && keyCompare(it->first, key); ++it)
1240 keep(it);
1241 // Keep matching keys if value match, otherwise skip and count
1242 for (; it != end && !keyCompare(key, it->first); ++it) {
1243 if (!(it->second == value))
1244 keep(it);
1245 else
1246 ++result;
1247 }
1248 for (; it != end; ++it)
1249 keep(it);
1250
1251 d.swap(newData);
1252 return result;
1253 }
1254
1255 // d->m.erase_if(....) would be nice, but that's C++20.
1256 // So let's do like find(keyCopy, valueCopy):
1257 auto [i, e] = d->m.equal_range(key);
1258 if (i == e)
1259 return result;
1260
1261 // value may belong to this map. As such, we need to copy it to ensure
1262 // it stays valid throughout the iteration below (which may destroy it)
1263 const T valueCopy = value;
1264 while (i != e) {
1265 if (i->second == valueCopy) {
1266 i = d->m.erase(i);
1267 ++result;
1268 } else {
1269 ++i;
1270 }
1271 }
1272
1273 return result;
1274 }
1275
1276 template <typename Predicate>
1277 size_type removeIf(Predicate pred)
1278 {
1279 return QtPrivate::associative_erase_if(*this, pred);
1280 }
1281
1282 T take(const Key &key)
1283 {
1284 if (!d)
1285 return T();
1286
1287 auto i = findIteratorByKey(key);
1288 if (d.isShared()) {
1289 if (i == d->m.end()) {
1290 // NB: take always detaches, even if the key isn't found. This is for historic reasons.
1291 detach();
1292 return T();
1293 }
1294 const auto hold = referenceHoldingDetachExceptFor(i);
1295 return i->second;
1296 }
1297
1298 if (i == d->m.end())
1299 return T();
1300
1301#ifdef __cpp_lib_node_extract
1302 return std::move(d->m.extract(i).mapped());
1303#else
1304 // ### breaks RVO on most compilers (but only on old-fashioned ones, so who cares?)
1305 T result(std::move(i->second));
1306 d->m.erase(i);
1307 return result;
1308#endif
1309 }
1310
1311 bool contains(const Key &key) const
1312 {
1313 if (!d)
1314 return false;
1315 auto i = d->m.find(key);
1316 return i != d->m.end();
1317 }
1318
1319 bool contains(const Key &key, const T &value) const
1320 {
1321 return find(key, value) != end();
1322 }
1323
1324 Key key(const T &value, const Key &defaultKey = Key()) const
1325 {
1326 if (!d)
1327 return defaultKey;
1328
1329 return d->key(value, defaultKey);
1330 }
1331
1332 T value(const Key &key, const T &defaultValue = T()) const
1333 {
1334 if (!d)
1335 return defaultValue;
1336 auto i = findIteratorByKey(key);
1337 if (i != d->m.cend())
1338 return i->second;
1339 return defaultValue;
1340 }
1341
1342 QList<Key> keys() const
1343 {
1344 if (!d)
1345 return {};
1346 return d->keys();
1347 }
1348
1349 QList<Key> keys(const T &value) const
1350 {
1351 if (!d)
1352 return {};
1353 return d->keys(value);
1354 }
1355
1356 QList<Key> uniqueKeys() const
1357 {
1358 QList<Key> result;
1359 if (!d)
1360 return result;
1361
1362 result.reserve(size());
1363
1364 std::unique_copy(keyBegin(), keyEnd(),
1365 std::back_inserter(result));
1366
1367 result.shrink_to_fit();
1368 return result;
1369 }
1370
1371 QList<T> values() const
1372 {
1373 if (!d)
1374 return {};
1375 return d->values();
1376 }
1377
1378 QList<T> values(const Key &key) const
1379 {
1380 QList<T> result;
1381 const auto range = equal_range(key);
1382 result.reserve(std::distance(range.first, range.second));
1383 std::copy(range.first, range.second, std::back_inserter(result));
1384 return result;
1385 }
1386
1387 size_type count(const Key &key) const
1388 {
1389 if (!d)
1390 return 0;
1391 return d->count(key);
1392 }
1393
1394 size_type count(const Key &key, const T &value) const
1395 {
1396 if (!d)
1397 return 0;
1398
1399 // TODO: improve; no need of scanning the equal_range twice.
1400 auto range = d->m.equal_range(key);
1401
1402 return size_type(std::count_if(range.first,
1403 range.second,
1404 MapData::valueIsEqualTo(value)));
1405 }
1406
1407 inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
1408 inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return std::next(constEnd(), -1).key(); }
1409
1410 inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
1411 inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
1412 inline T &last() { Q_ASSERT(!isEmpty()); return *std::next(end(), -1); }
1413 inline const T &last() const { Q_ASSERT(!isEmpty()); return *std::next(constEnd(), -1); }
1414
1415 class const_iterator;
1416
1417 class iterator
1418 {
1419 friend class QMultiMap<Key, T>;
1420 friend class const_iterator;
1421
1422 typename Map::iterator i;
1423 explicit iterator(typename Map::iterator it) : i(it) {}
1424 public:
1425 using iterator_category = std::bidirectional_iterator_tag;
1426 using difference_type = qptrdiff;
1427 using value_type = T;
1428 using pointer = T *;
1429 using reference = T &;
1430
1431 iterator() = default;
1432
1433 const Key &key() const { return i->first; }
1434 T &value() const { return i->second; }
1435 T &operator*() const { return i->second; }
1436 T *operator->() const { return &i->second; }
1437 friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
1438 friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
1439
1440 iterator &operator++()
1441 {
1442 ++i;
1443 return *this;
1444 }
1445 iterator operator++(int)
1446 {
1447 iterator r = *this;
1448 ++i;
1449 return r;
1450 }
1451 iterator &operator--()
1452 {
1453 --i;
1454 return *this;
1455 }
1456 iterator operator--(int)
1457 {
1458 iterator r = *this;
1459 --i;
1460 return r;
1461 }
1462
1463#if QT_DEPRECATED_SINCE(6, 0)
1464 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1465 //! [qmultimap-op-it-plus-step]
1466 friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
1467
1468 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1469 //! [qmultimap-op-it-minus-step]
1470 friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
1471
1472 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1473 iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1474
1475 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1476 iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1477
1478 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1479 //! [qmultimap-op-step-plus-it]
1480 friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
1481
1482 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1483 //! [qmultimap-op-step-minus-it]
1484 friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
1485#endif
1486 };
1487
1488 class const_iterator
1489 {
1490 friend class QMultiMap<Key, T>;
1491 typename Map::const_iterator i;
1492 explicit const_iterator(typename Map::const_iterator it) : i(it) {}
1493
1494 public:
1495 using iterator_category = std::bidirectional_iterator_tag;
1496 using difference_type = qptrdiff;
1497 using value_type = T;
1498 using pointer = const T *;
1499 using reference = const T &;
1500
1501 const_iterator() = default;
1502 Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
1503
1504 const Key &key() const { return i->first; }
1505 const T &value() const { return i->second; }
1506 const T &operator*() const { return i->second; }
1507 const T *operator->() const { return &i->second; }
1508 friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
1509 friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
1510
1511 const_iterator &operator++()
1512 {
1513 ++i;
1514 return *this;
1515 }
1516 const_iterator operator++(int)
1517 {
1518 const_iterator r = *this;
1519 ++i;
1520 return r;
1521 }
1522 const_iterator &operator--()
1523 {
1524 --i;
1525 return *this;
1526 }
1527 const_iterator operator--(int)
1528 {
1529 const_iterator r = *this;
1530 --i;
1531 return r;
1532 }
1533
1534#if QT_DEPRECATED_SINCE(6, 0)
1535 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1536 //! [qmultimap-op-it-plus-step-const]
1537 friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
1538
1539 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1540 //! [qmultimap-op-it-minus-step-const]
1541 friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
1542
1543 QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
1544 const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
1545
1546 QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
1547 const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
1548
1549 QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
1550 //! [qmultimap-op-step-plus-it-const]
1551 friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
1552
1553 QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
1554 //! [qmultimap-op-step-minus-it-const]
1555 friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
1556#endif
1557 };
1558
1559 class key_iterator
1560 {
1561 const_iterator i;
1562
1563 public:
1564 typedef typename const_iterator::iterator_category iterator_category;
1565 typedef typename const_iterator::difference_type difference_type;
1566 typedef Key value_type;
1567 typedef const Key *pointer;
1568 typedef const Key &reference;
1569
1570 key_iterator() = default;
1571 explicit key_iterator(const_iterator o) : i(o) { }
1572
1573 const Key &operator*() const { return i.key(); }
1574 const Key *operator->() const { return &i.key(); }
1575 bool operator==(key_iterator o) const { return i == o.i; }
1576 bool operator!=(key_iterator o) const { return i != o.i; }
1577
1578 inline key_iterator &operator++() { ++i; return *this; }
1579 inline key_iterator operator++(int) { return key_iterator(i++);}
1580 inline key_iterator &operator--() { --i; return *this; }
1581 inline key_iterator operator--(int) { return key_iterator(i--); }
1582 const_iterator base() const { return i; }
1583 };
1584
1585 typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
1586 typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
1587
1588 // STL style
1589 iterator begin() { detach(); return iterator(d->m.begin()); }
1590 const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
1591 const_iterator constBegin() const { return begin(); }
1592 const_iterator cbegin() const { return begin(); }
1593 iterator end() { detach(); return iterator(d->m.end()); }
1594 const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
1595 const_iterator constEnd() const { return end(); }
1596 const_iterator cend() const { return end(); }
1597 key_iterator keyBegin() const { return key_iterator(begin()); }
1598 key_iterator keyEnd() const { return key_iterator(end()); }
1599 key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
1600 key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
1601 const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
1602 const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
1603 const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
1604 const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
1605 auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QMultiMap &>(*this); }
1606 auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QMultiMap &>(*this); }
1607 auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1608 auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange<QMultiMap>(std::move(*this)); }
1609
1610 iterator erase(const_iterator it)
1611 {
1612 return erase(it, std::next(it));
1613 }
1614
1615 iterator erase(const_iterator afirst, const_iterator alast)
1616 {
1617 if (!d)
1618 return iterator();
1619
1620 if (!d.isShared())
1621 return iterator(d->m.erase(afirst.i, alast.i));
1622
1623 auto result = d->erase(afirst.i, alast.i);
1624 d.reset(result.data);
1625 return iterator(result.it);
1626 }
1627
1628 // more Qt
1629 typedef iterator Iterator;
1630 typedef const_iterator ConstIterator;
1631
1632 size_type count() const
1633 {
1634 return size();
1635 }
1636
1637 iterator find(const Key &key)
1638 {
1639 const auto hold = referenceHoldingDetach();
1640 return iterator(findIteratorByKey(key));
1641 }
1642
1643 const_iterator find(const Key &key) const
1644 {
1645 if (!d)
1646 return const_iterator();
1647 return const_iterator(findIteratorByKey(key));
1648 }
1649
1650 const_iterator constFind(const Key &key) const
1651 {
1652 return find(key);
1653 }
1654
1655 iterator find(const Key &key, const T &value)
1656 {
1657 const auto hold = referenceHoldingDetach();
1658
1659 auto range = d->m.equal_range(key);
1660 auto i = std::find_if(range.first, range.second,
1661 MapData::valueIsEqualTo(value));
1662
1663 if (i != range.second)
1664 return iterator(i);
1665 return iterator(d->m.end());
1666 }
1667
1668 const_iterator find(const Key &key, const T &value) const
1669 {
1670 if (!d)
1671 return const_iterator();
1672
1673 auto range = d->m.equal_range(key);
1674 auto i = std::find_if(range.first, range.second,
1675 MapData::valueIsEqualTo(value));
1676
1677 if (i != range.second)
1678 return const_iterator(i);
1679 return const_iterator(d->m.end());
1680 }
1681
1682 const_iterator constFind(const Key &key, const T &value) const
1683 {
1684 return find(key, value);
1685 }
1686
1687 iterator lowerBound(const Key &key)
1688 {
1689 const auto hold = referenceHoldingDetach();
1690 return iterator(d->m.lower_bound(key));
1691 }
1692
1693 const_iterator lowerBound(const Key &key) const
1694 {
1695 if (!d)
1696 return const_iterator();
1697 return const_iterator(d->m.lower_bound(key));
1698 }
1699
1700 iterator upperBound(const Key &key)
1701 {
1702 const auto hold = referenceHoldingDetach();
1703 return iterator(d->m.upper_bound(key));
1704 }
1705
1706 const_iterator upperBound(const Key &key) const
1707 {
1708 if (!d)
1709 return const_iterator();
1710 return const_iterator(d->m.upper_bound(key));
1711 }
1712
1713 iterator insert(const Key &key, const T &value)
1714 {
1715 const auto hold = referenceHoldingDetach();
1716 // note that std::multimap inserts at the end of an equal_range for a key,
1717 // QMultiMap at the beginning.
1718 auto i = d->m.lower_bound(key);
1719 return iterator(d->m.insert(i, {key, value}));
1720 }
1721
1722 iterator insert(const_iterator pos, const Key &key, const T &value)
1723 {
1724 if (!d) {
1725 d.reset(new MapData);
1726 return iterator(d->m.insert({ key, value }));
1727 } else if (d.isShared()) {
1728 auto posDistance = std::distance(d->m.cbegin(), pos.i);
1729 auto hold = referenceHoldingDetach();
1730 auto dpos = std::next(d->m.cbegin(), posDistance);
1731 return iterator(d->m.insert(dpos, {key, value}));
1732 }
1733
1734 return iterator(d->m.insert(pos.i, {key, value}));
1735 }
1736
1737#if QT_DEPRECATED_SINCE(6, 0)
1738 QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1739 iterator insertMulti(const Key &key, const T &value)
1740 {
1741 return insert(key, value);
1742 }
1743 QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
1744 iterator insertMulti(const_iterator pos, const Key &key, const T &value)
1745 {
1746 return insert(pos, key, value);
1747 }
1748
1749 QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1750 void insert(const QMultiMap<Key, T> &map)
1751 {
1752 unite(map);
1753 }
1754
1755 QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
1756 void insert(QMultiMap<Key, T> &&map)
1757 {
1758 unite(std::move(map));
1759 }
1760#endif
1761
1762 iterator replace(const Key &key, const T &value)
1763 {
1764 if (!d) {
1765 d.reset(new MapData);
1766 return iterator(d->m.insert({ key, value }));
1767 }
1768 auto i = findIteratorByKey(key);
1769 if (d.isShared()) {
1770 const auto hold = referenceHoldingDetachExceptFor(i);
1771 return iterator(d->m.insert({ key, value }));
1772 }
1773
1774 // Similarly, improve here (e.g. lower_bound and hinted insert);
1775 // there's no insert_or_assign on multimaps
1776 if (i != d->m.end())
1777 i->second = value;
1778 else
1779 i = d->m.insert({key, value});
1780
1781 return iterator(i);
1782 }
1783
1784 // STL compatibility
1785 [[nodiscard]]
1786 inline bool empty() const { return isEmpty(); }
1787
1788 std::pair<iterator, iterator> equal_range(const Key &akey)
1789 {
1790 const auto hold = referenceHoldingDetach();
1791 auto result = d->m.equal_range(akey);
1792 return {iterator(result.first), iterator(result.second)};
1793 }
1794
1795 std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
1796 {
1797 if (!d)
1798 return {};
1799 auto result = d->m.equal_range(akey);
1800 return {const_iterator(result.first), const_iterator(result.second)};
1801 }
1802
1803 QMultiMap &unite(const QMultiMap &other)
1804 {
1805 if (other.isEmpty())
1806 return *this;
1807
1808 detach();
1809
1810 auto copy = other.d->m;
1811#ifdef __cpp_lib_node_extract
1812 copy.merge(std::move(d->m));
1813#else
1814 copy.insert(std::make_move_iterator(d->m.begin()),
1815 std::make_move_iterator(d->m.end()));
1816#endif
1817 d->m = std::move(copy);
1818 return *this;
1819 }
1820
1821 QMultiMap &unite(QMultiMap<Key, T> &&other)
1822 {
1823 if (!other.d || other.d->m.empty())
1824 return *this;
1825
1826 if (other.d.isShared()) {
1827 // fall back to a regular copy
1828 unite(other);
1829 return *this;
1830 }
1831
1832 detach();
1833
1834#ifdef __cpp_lib_node_extract
1835 other.d->m.merge(std::move(d->m));
1836#else
1837 other.d->m.insert(std::make_move_iterator(d->m.begin()),
1838 std::make_move_iterator(d->m.end()));
1839#endif
1840 *this = std::move(other);
1841 return *this;
1842 }
1843};
1844
1845Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap)
1846Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap)
1847
1848template <typename Key, typename T>
1849QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1850{
1851 auto result = lhs;
1852 result += rhs;
1853 return result;
1854}
1855
1856template <typename Key, typename T>
1857QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
1858{
1859 return lhs.unite(rhs);
1860}
1861
1862template <typename Key, typename T, typename Predicate>
1863qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
1864{
1865 return QtPrivate::associative_erase_if(map, pred);
1866}
1867
1868QT_END_NAMESPACE
1869
1870#endif // QMAP_H
Definition qlist.h:82
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:968
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:2782
QMultiMap< Key, T > operator+=(QMultiMap< Key, T > &lhs, const QMultiMap< Key, T > &rhs)
Definition qmap.h:1857
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)