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