9#include <QtCore/qalgorithms.h>
10#include <QtCore/qcontainertools_impl.h>
11#include <QtCore/qhashfunctions.h>
12#include <QtCore/qiterator.h>
13#include <QtCore/qlist.h>
14#include <QtCore/qrefcount.h>
15#include <QtCore/qscopeguard.h>
16#include <QtCore/qttypetraits.h>
18#include <initializer_list>
20#include <QtCore/q20type_traits.h>
28 explicit QHashDummyValue() =
default;
29 friend constexpr bool operator==(QHashDummyValue, QHashDummyValue)
noexcept {
return true; }
30#ifndef __cpp_impl_three_way_comparison
31 friend constexpr bool operator!=(QHashDummyValue, QHashDummyValue)
noexcept {
return false; }
33 friend constexpr size_t qHash(QHashDummyValue)
noexcept =
delete;
34 friend constexpr size_t qHash(QHashDummyValue, size_t)
noexcept =
delete;
39template <
typename T,
typename =
void>
47template <
typename T,
typename =
void>
55template <
typename T,
typename =
void>
66 if constexpr (HasQHashOverload<T>) {
67 return qHash(t, seed);
68 }
else if constexpr (HasStdHashSpecializationWithSeed<T>) {
69 return std::hash<T>()(t, seed);
70 }
else if constexpr (HasStdHashSpecializationWithoutSeed<T>) {
72 return std::hash<T>()(t);
74 static_assert(QtPrivate::type_dependent_false<T>(),
"The key type must have a qHash overload or a std::hash specialization");
79template <
typename Key,
typename T>
87 template<
typename ...Args>
89 {
new (n)
Node{
std::move(k), T(
std::forward<Args>(args)...) }; }
90 template<
typename ...Args>
92 {
new (n)
Node{ Key(k), T(
std::forward<Args>(args)...) }; }
93 template<
typename ...Args>
96 value = T(
std::forward<Args>(args)...);
105template <
typename Key>
106struct Node<Key, QHashDummyValue> {
111 template<
typename ...Args>
113 {
new (n)
Node{
std::move(k) }; }
114 template<
typename ...Args>
116 {
new (n)
Node{ k }; }
117 template<
typename ...Args>
135 qsizetype nEntries = 0;
157template <
typename Key,
typename T>
167 template<
typename ...Args>
170 template<
typename ...Args>
195 Chain *chain =
new Chain{ c->value,
nullptr };
208 qsizetype size = n
->value->free();
212 template<
typename ...Args>
215 Chain *e =
new Chain{ T(
std::forward<Args>(args)...),
nullptr };
218 template<
typename ...Args>
221 value->value = T(
std::forward<Args>(args)...);
225template<
typename Node>
236 static_assert ((NEntries & LocalBucketMask) == 0,
"NEntries must be a power of two.");
247template<
typename Node>
256 struct {
alignas(
Node)
unsigned char data[
sizeof(Node)]; } storage;
258 unsigned char &
nextFree() {
return *
reinterpret_cast<
unsigned char *>(&storage); }
259 Node &
node() {
return *
reinterpret_cast<Node *>(&storage); }
268 memset(offsets, SpanConstants::UnusedEntry,
sizeof(offsets));
277 if constexpr (!
std::is_trivially_destructible<Node>::value) {
278 for (
auto o : offsets) {
279 if (o != SpanConstants::UnusedEntry)
280 entries[o].node().~Node();
289 Q_ASSERT(i < SpanConstants::NEntries);
290 Q_ASSERT(offsets[i] == SpanConstants::UnusedEntry);
301 Q_ASSERT(bucket < SpanConstants::NEntries);
302 Q_ASSERT(offsets[bucket] != SpanConstants::UnusedEntry);
304 unsigned char entry = offsets[bucket];
305 offsets[bucket] = SpanConstants::UnusedEntry;
317 return (offsets[i] != SpanConstants::UnusedEntry);
319 Node &
at(size_t i)
noexcept
321 Q_ASSERT(i < SpanConstants::NEntries);
322 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
324 return entries[offsets[i]].node();
326 const Node &
at(size_t i)
const noexcept
328 Q_ASSERT(i < SpanConstants::NEntries);
329 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
331 return entries[offsets[i]].node();
347 Q_ASSERT(offsets[from] != SpanConstants::UnusedEntry);
348 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
349 offsets[to] = offsets[from];
350 offsets[from] = SpanConstants::UnusedEntry;
354 Q_ASSERT(to < SpanConstants::NEntries);
355 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
356 Q_ASSERT(fromIndex < SpanConstants::NEntries);
357 Q_ASSERT(fromSpan.offsets[fromIndex] != SpanConstants::UnusedEntry);
361 offsets[to] = nextFree;
365 size_t fromOffset = fromSpan.offsets[fromIndex];
366 fromSpan.offsets[fromIndex] = SpanConstants::UnusedEntry;
369 if constexpr (isRelocatable_v<Node>) {
370 memcpy(&toEntry, &fromEntry,
sizeof(
Entry));
372 new (&toEntry.node()) Node(
std::move(fromEntry.node()));
373 fromEntry.node().~Node();
375 fromEntry.nextFree() = fromSpan
.nextFree;
376 fromSpan
.nextFree =
static_cast<
unsigned char>(fromOffset);
381 Q_ASSERT(
allocated < SpanConstants::NEntries);
396 static_assert(SpanConstants::NEntries % 8 == 0);
398 alloc = SpanConstants::NEntries / 8 * 3;
399 else if (
allocated == SpanConstants::NEntries / 8 * 3)
400 alloc = SpanConstants::NEntries / 8 * 5;
402 alloc =
allocated + SpanConstants::NEntries/8;
406 if constexpr (isRelocatable_v<Node>) {
411 new (&newEntries[i].node()) Node(
std::move(
entries[i].node()));
415 for (size_t i =
allocated; i < alloc; ++i) {
416 newEntries[i].nextFree() = uchar(i + 1);
428 constexpr int SizeDigits = std::numeric_limits<size_t>::digits;
432 if (requestedCapacity <= 64)
433 return SpanConstants::NEntries;
441 int count = qCountLeadingZeroBits(requestedCapacity);
443 return (std::numeric_limits<size_t>::max)();
444 return size_t(1) << (SizeDigits - count + 1);
448 return hash & (nBuckets - 1);
452template <
typename Node>
455template <
typename Node>
471 return (std::numeric_limits<ptrdiff_t>::max)() /
sizeof(Span);
482 :
span(d
->spans + (bucket >> SpanConstants::SpanShift)),
491 return ((span - d->spans) << SpanConstants::SpanShift) | index;
500 advance_impl(d,
nullptr);
504 return !
span->hasNode(index);
508 return span->offset(index);
512 return span->atOffset(offset);
516 return &
span->at(index);
520 return span->insert(index);
526 return lhs.span == rhs.span && lhs.index == rhs.index;
530 void advance_impl(
const Data *d,
Span *whenAtEnd)
noexcept
534 if (Q_UNLIKELY(index == SpanConstants::NEntries)) {
537 if (
span - d
->spans == ptrdiff_t(d->numBuckets >> SpanConstants::SpanShift))
550 constexpr qptrdiff MaxSpanCount = (std::numeric_limits<qptrdiff>::max)() /
sizeof(Span);
551 constexpr size_t MaxBucketCount = MaxSpanCount << SpanConstants::SpanShift;
553 if (numBuckets > MaxBucketCount) {
558 size_t nSpans = numBuckets >> SpanConstants::SpanShift;
559 return R{
new Span[nSpans], nSpans };
564 numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
565 spans = allocateSpans(numBuckets).spans;
566 seed = QHashSeed::globalSeed();
571 template <
bool Resized>
575 for (size_t s = 0; s < nSpans; ++s) {
577 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
578 if (!span.hasNode(index))
580 const Node &n = span.at(index);
581 auto it = Resized ? findBucket(n.key) :
Bucket {
spans + s, index };
582 Q_ASSERT(it.isUnused());
583 Node *newNode = it.insert();
584 new (newNode) Node(n);
591 auto r = allocateSpans(numBuckets);
593 reallocationHelper<
false>(other, r.nSpans);
597 numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
598 spans = allocateSpans(numBuckets).spans;
599 size_t otherNSpans = other.numBuckets >> SpanConstants::SpanShift;
600 reallocationHelper<
true>(other, otherNSpans);
615 return new Data(size);
632 return iterator{
this, other.bucket};
652 size_t newBucketCount = GrowthPolicy::bucketsForCapacity(sizeHint);
655 size_t oldBucketCount = numBuckets;
656 spans = allocateSpans(newBucketCount).spans;
657 numBuckets = newBucketCount;
658 size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
660 for (size_t s = 0; s < oldNSpans; ++s) {
661 Span &span = oldSpans[s];
662 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
663 if (!span.hasNode(index))
665 Node &n = span.at(index);
666 auto it = findBucket(n.key);
667 Q_ASSERT(it.isUnused());
668 Node *newNode = it.insert();
669 new (newNode) Node(
std::move(n));
679 if (bucket == numBuckets)
686 return float(size)/numBuckets;
690 return size >= (numBuckets >> 1);
696 return findBucketWithHash(key, hash);
701 static_assert(std::is_same_v<std::remove_cv_t<Key>, K> ||
702 QHashHeterogeneousSearch<std::remove_cv_t<Key>, K>::value);
703 Q_ASSERT(numBuckets > 0);
704 Bucket bucket(
this, GrowthPolicy::bucketForHash(numBuckets, hash));
708 size_t offset = bucket.offset();
709 if (offset == SpanConstants::UnusedEntry) {
712 Node &n = bucket.nodeAtOffset(offset);
713 if (qHashEquals(n.key, key))
716 bucket.advanceWrapped(
this);
720 template <
typename K> Node *
findNode(
const K &key)
const noexcept
722 auto bucket = findBucket(key);
723 if (bucket.isUnused())
725 return bucket.node();
738 if (numBuckets > 0) {
739 it = findBucketWithHash(key, hash);
741 return { it.toIterator(
this),
true };
745 it = findBucketWithHash(key, hash);
747 Q_ASSERT(it.span !=
nullptr);
748 Q_ASSERT(it.isUnused());
751 return { it.toIterator(
this),
false };
756 Q_ASSERT(bucket.span->hasNode(bucket.index));
757 bucket.span->erase(bucket.index);
763 next.advanceWrapped(
this);
764 size_t offset = next.offset();
765 if (offset == SpanConstants::UnusedEntry)
767 size_t hash =
QHashPrivate::calculateHash(next.nodeAtOffset(offset).key, seed);
768 Bucket newBucket(
this, GrowthPolicy::bucketForHash(numBuckets, hash));
770 if (newBucket == next) {
773 }
else if (newBucket == bucket) {
775 if (next.span == bucket.span) {
776 bucket.span->moveLocal(next.index, bucket.index);
779 bucket.span->moveFromSpan(*next.span, next.index, bucket.index);
784 newBucket.advanceWrapped(
this);
795template <
typename Node>
802 size_t span()
const noexcept {
return bucket >> SpanConstants::SpanShift; }
803 size_t index()
const noexcept {
return bucket & SpanConstants::LocalBucketMask; }
804 inline bool isUnused()
const noexcept {
return !d->spans[span()].hasNode(index()); }
806 inline Node *
node()
const noexcept
809 return &d->spans[span()].at(index());
811 bool atEnd()
const noexcept {
return !
d; }
817 if (bucket == d->numBuckets) {
828 {
return d == other.d && bucket == other.bucket; }
830 {
return !(*
this == other); }
842template <
typename Key,
typename T>
847 friend class QSet<
Key>;
848 friend class QMultiHash<
Key,
T>;
864 : d(
new Data(list.size()))
866 for (
typename std::initializer_list<
std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
877 static_assert(
std::is_nothrow_destructible_v<Key>,
"Types with throwing destructors are not supported in Qt containers.");
878 static_assert(
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
880 if (d && !d->ref.deref())
890 if (d && !d->ref.deref())
898 : d(
std::exchange(other.d,
nullptr))
920 for (;
f !=
l; ++
f) {
922 using V =
decltype(
e);
933 static bool compareIterators(
const const_iterator &lhs,
const const_iterator &rhs)
935 return lhs.i.node()->valuesEqual(rhs.i.node());
938 template <
typename AKey = Key,
typename AT = T,
939 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> =
true>
944 if (lhs.size() != rhs.size())
949 if (i == lhs
.end() || !compareIterators(i, it))
955 QT_DECLARE_EQUALITY_OPERATORS_HELPER(
QHash,
QHash, ,
noexcept,
956 template <
typename AKey = Key,
typename AT = T,
957 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> =
true>)
967 inline bool isEmpty()
const noexcept {
return !
d ||
d->
size == 0; }
1063 while (
i !=
end()) {
1090 template <
typename K>
1132 while (
i !=
end()) {
1181 friend class iterator;
1186 friend class iterator;
1187 friend class QHash<Key, T>;
1188 friend class QSet<
Key>;
1190 explicit inline const_iterator(piter it) : i(it) { }
1202 inline const Key &
key()
const noexcept {
return i.node()->key; }
1203 inline const T &
value()
const noexcept {
return i.node()->value; }
1204 inline const T &
operator*()
const noexcept {
return i.node()->value; }
1205 inline const T *
operator->()
const noexcept {
return &i.node()->value; }
1237 const Key &
operator*()
const noexcept {
return i.key(); }
1238 const Key *
operator->()
const noexcept {
return &i.key(); }
1251 inline iterator begin() {
if (!d)
return iterator(); detach();
return iterator(d->begin()); }
1268 auto asKeyValueRange()
const & {
return QtPrivate::QKeyValueRange<
const QHash &>(*
this); }
1270 auto asKeyValueRange()
const && {
return QtPrivate::QKeyValueRange<QHash>(std::move(*
this)); }
1301 iterator i = iterator{d->detachedIterator(it.i)};
1302 typename Data::Bucket bucket(i.i);
1305 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
1312 return equal_range_impl(*
this, key);
1316 return equal_range_impl(*
this, key);
1319 template <
typename Hash,
typename K>
static auto equal_range_impl(Hash &self,
const K &key)
1321 auto first = self.find(key);
1322 auto second = first;
1323 if (second !=
decltype(first){})
1325 return std::make_pair(first, second);
1328 template <
typename K> iterator findImpl(
const K &key)
1332 auto it = d->findBucket(key);
1333 size_t bucket = it.toBucketIndex(d);
1335 it =
typename Data::Bucket(d, bucket);
1338 return iterator(it.toIterator(d));
1340 template <
typename K>
const_iterator constFindImpl(
const K &key)
const noexcept
1344 auto it = d->findBucket(key);
1356 return findImpl(key);
1360 return constFindImpl(key);
1369 return emplace(key, value);
1374 return emplace(key,
std::move(value));
1379 return emplace(
std::move(key), value);
1384 return emplace(
std::move(key),
std::move(value));
1389 if (d == hash.d || !hash.d)
1399 emplace(it.key(), it.value());
1402 template <
typename ...Args>
1406 return emplace(
std::move(copy),
std::forward<Args>(args)...);
1409 template <
typename ...Args>
1413 if (d->shouldGrow())
1414 return emplace_helper(
std::move(key), T(
std::forward<Args>(args)...));
1415 return emplace_helper(
std::move(key),
std::forward<Args>(args)...);
1418 const auto copy = *
this;
1420 return emplace_helper(
std::move(key),
std::forward<Args>(args)...);
1423 template <
typename... Args>
1426 return tryEmplace_impl(key,
std::forward<Args>(args)...);
1428 template <
typename... Args>
1431 return tryEmplace_impl(
std::move(key),
std::forward<Args>(args)...);
1436 return tryEmplace_impl(key, value);
1439 template <
typename... Args>
1442 return tryEmplace_impl(key,
std::forward<Args>(args)...);
1444 template <
typename... Args>
1447 return tryEmplace_impl(
std::move(key),
std::forward<Args>(args)...);
1449 template <
typename... Args>
1454 template <
typename... Args>
1461 template <
typename K,
typename... Args>
1468 size_t hash =
QHashPrivate::calculateHash(key, d->seed);
1469 typename Data::Bucket bucket = d->findBucketWithHash(key, hash);
1470 const bool shouldInsert = bucket.isUnused();
1474 if (!isDetached() || (shouldInsert && d->shouldGrow())) {
1475 detachGuard = *
this;
1476 const bool resized = shouldInsert && d->shouldGrow();
1477 const size_t bucketIndex = bucket.toBucketIndex(d);
1480 d = resized ? Data::detached(d, d->size + 1) : Data::detached(d);
1481 bucket = resized ? d->findBucketWithHash(key, hash) :
typename Data::Bucket(d, bucketIndex);
1484 Node *n = bucket.insert();
1485 using ConstructProxy =
typename QHashPrivate::HeterogenousConstructProxy<Key, K>;
1486 Node::createInPlace(n, ConstructProxy(
std::forward<K>(key)),
1487 std::forward<Args>(args)...);
1490 return {iterator(bucket.toIterator(d)), shouldInsert};
1493 template <
typename Value>
1496 return insertOrAssign_impl(key,
std::forward<Value>(value));
1498 template <
typename Value>
1501 return insertOrAssign_impl(
std::move(key),
std::forward<Value>(value));
1503 template <
typename Value>
1506 return insertOrAssign_impl(key,
std::forward<Value>(value));
1508 template <
typename Value>
1511 return insertOrAssign_impl(
std::move(key),
std::forward<Value>(value));
1513 template <
typename Value>
1518 template <
typename Value>
1525 template <
typename K,
typename Value>
1528 auto r = tryEmplace(
std::forward<K>(key),
std::forward<Value>(value));
1530 *r.iterator =
std::forward<Value>(value);
1536 float load_factor()
const noexcept {
return d ? d->loadFactor() : 0; }
1542 inline bool empty()
const noexcept {
return isEmpty(); }
1545 template <
typename ...Args>
1546 iterator emplace_helper(Key &&key, Args &&... args)
1548 auto result = d->findOrInsert(key);
1549 if (!result.initialized)
1550 Node::createInPlace(result.it.node(),
std::move(key),
std::forward<Args>(args)...);
1552 result.it.node()->emplaceValue(
std::forward<Args>(args)...);
1553 return iterator(result.it);
1556 template <
typename K>
1559 template <
typename K>
1563 template <
typename K, if_heterogeneously_searchable<K> =
true>
1566 return removeImpl(key);
1568 template <
typename K, if_heterogeneously_searchable<K> =
true>
1571 return takeImpl(key);
1573 template <
typename K, if_heterogeneously_searchable<K> =
true>
1576 return d ? d->findNode(key) !=
nullptr :
false;
1578 template <
typename K, if_heterogeneously_searchable<K> =
true>
1581 return contains(key) ? 1 : 0;
1583 template <
typename K, if_heterogeneously_searchable<K> =
true>
1586 if (
auto *v = valueImpl(key))
1591 template <
typename K, if_heterogeneously_searchable<K> =
true>
1592 T
value(
const K &key,
const T &defaultValue)
const noexcept
1594 if (
auto *v = valueImpl(key))
1597 return defaultValue;
1599 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1602 return *tryEmplace(key).iterator;
1604 template <
typename K, if_heterogeneously_searchable<K> =
true>
1609 template <
typename K, if_heterogeneously_searchable<K> =
true>
1613 return equal_range_impl(*
this, key);
1615 template <
typename K, if_heterogeneously_searchable<K> =
true>
1619 return equal_range_impl(*
this, key);
1621 template <
typename K, if_heterogeneously_searchable<K> =
true>
1624 return findImpl(key);
1626 template <
typename K, if_heterogeneously_searchable<K> =
true>
1629 return constFindImpl(key);
1631 template <
typename K, if_heterogeneously_searchable<K> =
true>
1636 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1639 return tryEmplace_impl(
std::forward<K>(key),
std::forward<Args>(args)...);
1641 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1644 return tryEmplace_impl(
std::forward<K>(key), value);
1646 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1649 return tryEmplace_impl(
std::forward<K>(key),
std::forward<Args>(args)...);
1651 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1656 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1659 return insertOrAssign_impl(
std::forward<K>(key),
std::forward<Value>(value));
1661 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1664 return insertOrAssign_impl(
std::forward<K>(key),
std::forward<Value>(value));
1666 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1674template <
typename Key,
typename T>
1677 using Node = QHashPrivate::MultiNode<Key, T>;
1678 using Data = QHashPrivate::Data<Node>;
1679 using Chain = QHashPrivate::MultiNodeChain<T>;
1682 qsizetype m_size = 0;
1685 using key_type = Key;
1686 using mapped_type = T;
1687 using value_type = T;
1688 using size_type = qsizetype;
1689 using difference_type = qsizetype;
1690 using reference = T &;
1691 using const_reference =
const T &;
1693 QMultiHash()
noexcept =
default;
1694 inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
1695 : d(
new Data(list.size()))
1697 for (
typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
1698 insert(it->first, it->second);
1701 template <
typename InputIterator>
1702 QMultiHash(InputIterator f, InputIterator l);
1704 template <
typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> =
true>
1705 QMultiHash(InputIterator f, InputIterator l)
1707 QtPrivate::reserveIfForwardIterator(
this, f, l);
1709 insert(f.key(), f.value());
1712 template <
typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> =
true>
1713 QMultiHash(InputIterator f, InputIterator l)
1715 QtPrivate::reserveIfForwardIterator(
this, f, l);
1716 for (; f != l; ++f) {
1718 using V =
decltype(e);
1719 insert(std::forward<V>(e).first, std::forward<V>(e).second);
1723 QMultiHash(
const QMultiHash &other)
noexcept
1724 : d(other.d), m_size(other.m_size)
1731 static_assert(std::is_nothrow_destructible_v<Key>,
"Types with throwing destructors are not supported in Qt containers.");
1732 static_assert(std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
1734 if (d && !d->ref.deref())
1738 QMultiHash &operator=(
const QMultiHash &other)
noexcept(std::is_nothrow_destructible<Node>::value)
1744 if (d && !d->ref.deref())
1747 m_size = other.m_size;
1751 QMultiHash(QMultiHash &&other)
noexcept
1752 : d(std::exchange(other.d,
nullptr)),
1753 m_size(std::exchange(other.m_size, 0))
1756 QMultiHash &operator=(QMultiHash &&other)
noexcept(std::is_nothrow_destructible<Node>::value)
1758 QMultiHash moved(std::move(other));
1763 explicit QMultiHash(
const QHash<Key, T> &other)
1764 : QMultiHash(other.begin(), other.end())
1767 explicit QMultiHash(QHash<Key, T> &&other)
1769 unite(std::move(other));
1772 void swap(QMultiHash &other)
noexcept
1774 qt_ptr_swap(d, other.d);
1775 std::swap(m_size, other.m_size);
1780 template <
typename AKey = Key,
typename AT = T,
1781 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> =
true>
1782 friend bool comparesEqual(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept
1786 if (lhs.m_size != rhs.m_size)
1788 if (lhs.m_size == 0)
1793 if (lhs.d->size != rhs.d->size)
1795 for (
auto it = rhs.d->begin(); it != rhs.d->end(); ++it) {
1796 auto *n = lhs.d->findNode(it.node()->key);
1799 Chain *e = it.node()->value;
1801 Chain *oe = n->value;
1803 if (oe->value == e->value)
1815 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiHash, QMultiHash, ,
noexcept,
1816 template <
typename AKey = Key,
typename AT = T,
1817 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> =
true>)
1820 friend bool operator==(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept;
1821 friend bool operator!=(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept;
1824 inline qsizetype size()
const noexcept {
return m_size; }
1827 inline bool isEmpty()
const noexcept {
return !m_size; }
1829 inline qsizetype capacity()
const noexcept {
return d ? qsizetype(d->numBuckets >> 1) : 0; }
1830 void reserve(qsizetype size)
1833 if (size && (
this->capacity() >= size))
1838 d = Data::detached(d, size_t(size));
1840 inline void squeeze() { reserve(0); }
1842 inline void detach() {
if (!d || d->ref.isShared()) d = Data::detached(d); }
1843 inline bool isDetached()
const noexcept {
return d && !d->ref.isShared(); }
1844 bool isSharedWith(
const QMultiHash &other)
const noexcept {
return d == other.d; }
1846 void clear()
noexcept(std::is_nothrow_destructible<Node>::value)
1848 if (d && !d->ref.deref())
1854 qsizetype remove(
const Key &key)
1856 return removeImpl(key);
1859 template <
typename K> qsizetype removeImpl(
const K &key)
1863 auto it = d->findBucket(key);
1864 size_t bucket = it.toBucketIndex(d);
1866 it =
typename Data::Bucket(d, bucket);
1870 qsizetype n = Node::freeChain(it.node());
1872 Q_ASSERT(m_size >= 0);
1878 template <
typename Predicate>
1879 qsizetype removeIf(Predicate pred)
1881 return QtPrivate::associative_erase_if(*
this, pred);
1884 T take(
const Key &key)
1886 return takeImpl(key);
1889 template <
typename K> T takeImpl(
const K &key)
1893 auto it = d->findBucket(key);
1894 size_t bucket = it.toBucketIndex(d);
1896 it =
typename Data::Bucket(d, bucket);
1900 Chain *e = it.node()->value;
1902 T t = std::move(e->value);
1904 it.node()->value = e->next;
1911 Q_ASSERT(m_size >= 0);
1916 bool contains(
const Key &key)
const noexcept
1920 return d->findNode(key) !=
nullptr;
1924 const Key *keyImpl(
const T &value)
const noexcept
1927 auto i = d->begin();
1928 while (i != d->end()) {
1929 Chain *e = i.node()->value;
1930 if (e->contains(value))
1931 return &i.node()->key;
1939 Key key(
const T &value)
const noexcept
1941 if (
auto *k = keyImpl(value))
1946 Key key(
const T &value,
const Key &defaultKey)
const noexcept
1948 if (
auto *k = keyImpl(value))
1955 template <
typename K>
1956 T *valueImpl(
const K &key)
const noexcept
1959 Node *n = d->findNode(key);
1962 return &n->value->value;
1968 T value(
const Key &key)
const noexcept
1970 if (
auto *v = valueImpl(key))
1975 T value(
const Key &key,
const T &defaultValue)
const noexcept
1977 if (
auto *v = valueImpl(key))
1980 return defaultValue;
1983 T &operator[](
const Key &key)
1985 return operatorIndexImpl(key);
1988 template <
typename K> T &operatorIndexImpl(
const K &key)
1990 const auto copy = isDetached() ? QMultiHash() : *
this;
1992 auto result = d->findOrInsert(key);
1993 Q_ASSERT(!result.it.atEnd());
1994 if (!result.initialized) {
1995 Node::createInPlace(result.it.node(), Key(key), T());
1998 return result.it.node()->value->value;
2002 const T operator[](
const Key &key)
const noexcept
2007 QList<Key> uniqueKeys()
const
2011 auto i = d->begin();
2012 while (i != d->end()) {
2013 res.append(i.node()->key);
2020 QList<Key> keys()
const {
return QList<Key>(keyBegin(), keyEnd()); }
2021 QList<Key> keys(
const T &value)
const
2024 const_iterator i = begin();
2025 while (i != end()) {
2026 if (i.value() == value)
2027 res.append(i.key());
2033 QList<T> values()
const {
return QList<T>(begin(), end()); }
2034 QList<T> values(
const Key &key)
const
2036 return valuesImpl(key);
2039 template <
typename K> QList<T> valuesImpl(
const K &key)
const
2043 Node *n = d->findNode(key);
2045 Chain *e = n->value;
2047 values.append(e->value);
2056 class const_iterator;
2060 using piter =
typename QHashPrivate::iterator<Node>;
2061 friend class const_iterator;
2062 friend class QMultiHash<Key, T>;
2064 Chain **e =
nullptr;
2065 explicit inline iterator(piter it, Chain **entry =
nullptr)
noexcept : i(it), e(entry)
2067 if (!it.atEnd() && !e) {
2068 e = &it.node()->value;
2074 typedef std::forward_iterator_tag iterator_category;
2075 typedef qptrdiff difference_type;
2076 typedef T value_type;
2078 typedef T &reference;
2080 constexpr iterator()
noexcept =
default;
2082 inline const Key &key()
const noexcept {
return i.node()->key; }
2083 inline T &value()
const noexcept {
return (*e)->value; }
2084 inline T &operator*()
const noexcept {
return (*e)->value; }
2085 inline T *operator->()
const noexcept {
return &(*e)->value; }
2086 inline bool operator==(
const iterator &o)
const noexcept {
return e == o.e; }
2087 inline bool operator!=(
const iterator &o)
const noexcept {
return e != o.e; }
2089 inline iterator &operator++()
noexcept {
2095 e = i.atEnd() ?
nullptr : &i.node()->value;
2099 inline iterator operator++(
int)
noexcept {
2105 inline bool operator==(
const const_iterator &o)
const noexcept {
return e == o.e; }
2106 inline bool operator!=(
const const_iterator &o)
const noexcept {
return e != o.e; }
2108 friend class iterator;
2110 class const_iterator
2112 using piter =
typename QHashPrivate::iterator<Node>;
2113 friend class iterator;
2114 friend class QMultiHash<Key, T>;
2116 Chain **e =
nullptr;
2117 explicit inline const_iterator(piter it, Chain **entry =
nullptr)
noexcept : i(it), e(entry)
2119 if (!it.atEnd() && !e) {
2120 e = &it.node()->value;
2126 typedef std::forward_iterator_tag iterator_category;
2127 typedef qptrdiff difference_type;
2128 typedef T value_type;
2129 typedef const T *pointer;
2130 typedef const T &reference;
2132 constexpr const_iterator()
noexcept =
default;
2133 inline const_iterator(
const iterator &o)
noexcept : i(o.i), e(o.e) { }
2135 inline const Key &key()
const noexcept {
return i.node()->key; }
2136 inline T &value()
const noexcept {
return (*e)->value; }
2137 inline T &operator*()
const noexcept {
return (*e)->value; }
2138 inline T *operator->()
const noexcept {
return &(*e)->value; }
2139 inline bool operator==(
const const_iterator &o)
const noexcept {
return e == o.e; }
2140 inline bool operator!=(
const const_iterator &o)
const noexcept {
return e != o.e; }
2142 inline const_iterator &operator++()
noexcept {
2148 e = i.atEnd() ?
nullptr : &i.node()->value;
2152 inline const_iterator operator++(
int)
noexcept
2154 const_iterator r = *
this;
2159 friend class const_iterator;
2166 typedef typename const_iterator::iterator_category iterator_category;
2167 typedef qptrdiff difference_type;
2168 typedef Key value_type;
2169 typedef const Key *pointer;
2170 typedef const Key &reference;
2172 key_iterator()
noexcept =
default;
2173 explicit key_iterator(const_iterator o)
noexcept : i(o) { }
2175 const Key &operator*()
const noexcept {
return i.key(); }
2176 const Key *operator->()
const noexcept {
return &i.key(); }
2177 bool operator==(key_iterator o)
const noexcept {
return i == o.i; }
2178 bool operator!=(key_iterator o)
const noexcept {
return i != o.i; }
2180 inline key_iterator &operator++()
noexcept { ++i;
return *
this; }
2181 inline key_iterator operator++(
int)
noexcept {
return key_iterator(i++);}
2182 const_iterator base()
const noexcept {
return i; }
2185 typedef QKeyValueIterator<
const Key&,
const T&, const_iterator> const_key_value_iterator;
2186 typedef QKeyValueIterator<
const Key&, T&, iterator> key_value_iterator;
2189 inline iterator begin() {
if (!d)
return iterator(); detach();
return iterator(d->begin()); }
2190 inline const_iterator begin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2191 inline const_iterator cbegin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2192 inline const_iterator constBegin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2193 inline iterator end()
noexcept {
return iterator(); }
2194 inline const_iterator end()
const noexcept {
return const_iterator(); }
2195 inline const_iterator cend()
const noexcept {
return const_iterator(); }
2196 inline const_iterator constEnd()
const noexcept {
return const_iterator(); }
2197 inline key_iterator keyBegin()
const noexcept {
return key_iterator(begin()); }
2198 inline key_iterator keyEnd()
const noexcept {
return key_iterator(end()); }
2199 inline key_value_iterator keyValueBegin()
noexcept {
return key_value_iterator(begin()); }
2200 inline key_value_iterator keyValueEnd()
noexcept {
return key_value_iterator(end()); }
2201 inline const_key_value_iterator keyValueBegin()
const noexcept {
return const_key_value_iterator(begin()); }
2202 inline const_key_value_iterator constKeyValueBegin()
const noexcept {
return const_key_value_iterator(begin()); }
2203 inline const_key_value_iterator keyValueEnd()
const noexcept {
return const_key_value_iterator(end()); }
2204 inline const_key_value_iterator constKeyValueEnd()
const noexcept {
return const_key_value_iterator(end()); }
2205 auto asKeyValueRange() & {
return QtPrivate::QKeyValueRange<QMultiHash &>(*
this); }
2206 auto asKeyValueRange()
const & {
return QtPrivate::QKeyValueRange<
const QMultiHash &>(*
this); }
2207 auto asKeyValueRange() && {
return QtPrivate::QKeyValueRange<QMultiHash>(std::move(*
this)); }
2208 auto asKeyValueRange()
const && {
return QtPrivate::QKeyValueRange<QMultiHash>(std::move(*
this)); }
2210 iterator detach(const_iterator it)
2214 if (d->ref.isShared()) {
2217 Chain *entry = i.node()->value;
2218 while (entry != *it.e) {
2220 entry = entry->next;
2225 i = d->detachedIterator(i);
2226 e = &i.node()->value;
2233 return iterator(i, e);
2236 iterator erase(const_iterator it)
2239 iterator iter = detach(it);
2242 Chain *next = e->next;
2246 if (i.e == &i.i.node()->value) {
2248 typename Data::Bucket bucket(i.i);
2250 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
2251 i = iterator(++iter.i);
2253 i = iterator(bucket.toIterator(d));
2255 i = iterator(++iter.i);
2259 Q_ASSERT(m_size >= 0);
2264 typedef iterator Iterator;
2265 typedef const_iterator ConstIterator;
2266 inline qsizetype count()
const noexcept {
return size(); }
2269 template <
typename K> iterator findImpl(
const K &key)
2273 auto it = d->findBucket(key);
2274 size_t bucket = it.toBucketIndex(d);
2276 it =
typename Data::Bucket(d, bucket);
2280 return iterator(it.toIterator(d));
2282 template <
typename K> const_iterator constFindImpl(
const K &key)
const noexcept
2286 auto it = d->findBucket(key);
2289 return const_iterator(it.toIterator(d));
2292 iterator find(
const Key &key)
2294 return findImpl(key);
2296 const_iterator constFind(
const Key &key)
const noexcept
2298 return constFindImpl(key);
2300 const_iterator find(
const Key &key)
const noexcept
2302 return constFindImpl(key);
2305 iterator insert(
const Key &key,
const T &value)
2307 return emplace(key, value);
2310 iterator insert(
const Key &key, T &&value)
2312 return emplace(key, std::move(value));
2315 iterator insert(Key &&key,
const T &value)
2317 return emplace(std::move(key), value);
2320 iterator insert(Key &&key, T &&value)
2322 return emplace(std::move(key), std::move(value));
2325 template <
typename ...Args>
2326 iterator emplace(
const Key &key, Args &&... args)
2328 return emplace(Key(key), std::forward<Args>(args)...);
2331 template <
typename ...Args>
2332 iterator emplace(Key &&key, Args &&... args)
2335 if (d->shouldGrow())
2336 return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
2337 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2340 const auto copy = *
this;
2342 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2346 float load_factor()
const noexcept {
return d ? d->loadFactor() : 0; }
2347 static float max_load_factor()
noexcept {
return 0.5; }
2348 size_t bucket_count()
const noexcept {
return d ? d->numBuckets : 0; }
2349 static size_t max_bucket_count()
noexcept {
return Data::maxNumBuckets(); }
2352 inline bool empty()
const noexcept {
return isEmpty(); }
2354 inline iterator replace(
const Key &key,
const T &value)
2356 return emplaceReplace(key, value);
2359 template <
typename ...Args>
2360 iterator emplaceReplace(
const Key &key, Args &&... args)
2362 return emplaceReplace(Key(key), std::forward<Args>(args)...);
2365 template <
typename ...Args>
2366 iterator emplaceReplace(Key &&key, Args &&... args)
2369 if (d->shouldGrow())
2370 return emplaceReplace_helper(std::move(key), T(std::forward<Args>(args)...));
2371 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2374 const auto copy = *
this;
2376 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2379 inline QMultiHash &operator+=(
const QMultiHash &other)
2380 {
this->unite(other);
return *
this; }
2381 inline QMultiHash operator+(
const QMultiHash &other)
const
2382 { QMultiHash result = *
this; result += other;
return result; }
2384 bool contains(
const Key &key,
const T &value)
const noexcept
2386 return containsImpl(key, value);
2389 template <
typename K>
bool containsImpl(
const K &key,
const T &value)
const noexcept
2393 auto n = d->findNode(key);
2396 return n->value->contains(value);
2400 qsizetype remove(
const Key &key,
const T &value)
2402 return removeImpl(key, value);
2405 template <
typename K> qsizetype removeImpl(
const K &key,
const T &value)
2409 auto it = d->findBucket(key);
2410 size_t bucket = it.toBucketIndex(d);
2412 it =
typename Data::Bucket(d, bucket);
2417 Chain **e = &it.node()->value;
2420 if (entry->value == value) {
2428 if (!it.node()->value)
2431 Q_ASSERT(m_size >= 0);
2436 qsizetype count(
const Key &key)
const noexcept
2438 return countImpl(key);
2441 template <
typename K> qsizetype countImpl(
const K &key)
const noexcept
2445 auto it = d->findBucket(key);
2449 Chain *e = it.node()->value;
2459 qsizetype count(
const Key &key,
const T &value)
const noexcept
2461 return countImpl(key, value);
2464 template <
typename K> qsizetype countImpl(
const K &key,
const T &value)
const noexcept
2468 auto it = d->findBucket(key);
2472 Chain *e = it.node()->value;
2474 if (e->value == value)
2482 template <
typename K> iterator findImpl(
const K &key,
const T &value)
2486 const auto copy = isDetached() ? QMultiHash() : *
this;
2488 auto it = constFind(key, value);
2489 return iterator(it.i, it.e);
2491 template <
typename K> const_iterator constFindImpl(
const K &key,
const T &value)
const noexcept
2493 const_iterator i(constFind(key));
2494 const_iterator end(constEnd());
2495 while (i != end && i.key() == key) {
2496 if (i.value() == value)
2504 iterator find(
const Key &key,
const T &value)
2506 return findImpl(key, value);
2509 const_iterator constFind(
const Key &key,
const T &value)
const noexcept
2511 return constFindImpl(key, value);
2513 const_iterator find(
const Key &key,
const T &value)
const noexcept
2515 return constFind(key, value);
2518 QMultiHash &unite(
const QMultiHash &other)
2522 }
else if (other.isEmpty()) {
2525 QMultiHash copy(other);
2527 for (
auto cit = copy.cbegin(); cit != copy.cend(); ++cit)
2528 insert(cit.key(), *cit);
2533 QMultiHash &unite(
const QHash<Key, T> &other)
2535 for (
auto cit = other.cbegin(); cit != other.cend(); ++cit)
2536 insert(cit.key(), *cit);
2540 QMultiHash &unite(QHash<Key, T> &&other)
2542 if (!other.isDetached()) {
2546 auto it = other.d->begin();
2547 for (
const auto end = other.d->end(); it != end; ++it)
2548 emplace(std::move(it.node()->key), it.node()->takeValue());
2553 std::pair<iterator, iterator> equal_range(
const Key &key)
2555 return equal_range_impl(key);
2558 template <
typename K> std::pair<iterator, iterator> equal_range_impl(
const K &key)
2560 const auto copy = isDetached() ? QMultiHash() : *
this;
2562 auto pair = std::as_const(*
this).equal_range(key);
2563 return {iterator(pair.first.i), iterator(pair.second.i)};
2567 std::pair<const_iterator, const_iterator> equal_range(
const Key &key)
const noexcept
2569 return equal_range_impl(key);
2572 template <
typename K> std::pair<const_iterator, const_iterator> equal_range_impl(
const K &key)
const noexcept
2575 return {end(), end()};
2577 auto bucket = d->findBucket(key);
2578 if (bucket.isUnused())
2579 return {end(), end()};
2580 auto it = bucket.toIterator(d);
2583 return {const_iterator(it), const_iterator(end)};
2586 void detach_helper()
2592 Data *dd =
new Data(*d);
2593 if (!d->ref.deref())
2598 template<
typename... Args>
2599 iterator emplace_helper(Key &&key, Args &&...args)
2601 auto result = d->findOrInsert(key);
2602 if (!result.initialized)
2603 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2605 result.it.node()->insertMulti(std::forward<Args>(args)...);
2607 return iterator(result.it);
2610 template<
typename... Args>
2611 iterator emplaceReplace_helper(Key &&key, Args &&...args)
2613 auto result = d->findOrInsert(key);
2614 if (!result.initialized) {
2615 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2618 result.it.node()->emplaceValue(std::forward<Args>(args)...);
2620 return iterator(result.it);
2623 template <
typename K>
2624 using if_heterogeneously_searchable = QHashPrivate::if_heterogeneously_searchable_with<Key, K>;
2626 template <
typename K>
2627 using if_key_constructible_from = std::enable_if_t<std::is_constructible_v<Key, K>,
bool>;
2630 template <
typename K, if_heterogeneously_searchable<K> =
true>
2631 qsizetype remove(
const K &key)
2633 return removeImpl(key);
2635 template <
typename K, if_heterogeneously_searchable<K> =
true>
2636 T take(
const K &key)
2638 return takeImpl(key);
2640 template <
typename K, if_heterogeneously_searchable<K> =
true>
2641 bool contains(
const K &key)
const noexcept
2645 return d->findNode(key) !=
nullptr;
2647 template <
typename K, if_heterogeneously_searchable<K> =
true>
2648 T value(
const K &key)
const noexcept
2650 if (
auto *v = valueImpl(key))
2655 template <
typename K, if_heterogeneously_searchable<K> =
true>
2656 T value(
const K &key,
const T &defaultValue)
const noexcept
2658 if (
auto *v = valueImpl(key))
2661 return defaultValue;
2663 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
2664 T &operator[](
const K &key)
2666 return operatorIndexImpl(key);
2668 template <
typename K, if_heterogeneously_searchable<K> =
true>
2669 const T operator[](
const K &key)
const noexcept
2673 template <
typename K, if_heterogeneously_searchable<K> =
true>
2674 QList<T> values(
const K &key)
2676 return valuesImpl(key);
2678 template <
typename K, if_heterogeneously_searchable<K> =
true>
2679 iterator find(
const K &key)
2681 return findImpl(key);
2683 template <
typename K, if_heterogeneously_searchable<K> =
true>
2684 const_iterator constFind(
const K &key)
const noexcept
2686 return constFindImpl(key);
2688 template <
typename K, if_heterogeneously_searchable<K> =
true>
2689 const_iterator find(
const K &key)
const noexcept
2691 return constFindImpl(key);
2693 template <
typename K, if_heterogeneously_searchable<K> =
true>
2694 bool contains(
const K &key,
const T &value)
const noexcept
2696 return containsImpl(key, value);
2698 template <
typename K, if_heterogeneously_searchable<K> =
true>
2699 qsizetype remove(
const K &key,
const T &value)
2701 return removeImpl(key, value);
2703 template <
typename K, if_heterogeneously_searchable<K> =
true>
2704 qsizetype count(
const K &key)
const noexcept
2706 return countImpl(key);
2708 template <
typename K, if_heterogeneously_searchable<K> =
true>
2709 qsizetype count(
const K &key,
const T &value)
const noexcept
2711 return countImpl(key, value);
2713 template <
typename K, if_heterogeneously_searchable<K> =
true>
2714 iterator find(
const K &key,
const T &value)
2716 return findImpl(key, value);
2718 template <
typename K, if_heterogeneously_searchable<K> =
true>
2719 const_iterator constFind(
const K &key,
const T &value)
const noexcept
2721 return constFindImpl(key, value);
2723 template <
typename K, if_heterogeneously_searchable<K> =
true>
2724 const_iterator find(
const K &key,
const T &value)
const noexcept
2726 return constFind(key, value);
2728 template <
typename K, if_heterogeneously_searchable<K> =
true>
2729 std::pair<iterator, iterator>
2730 equal_range(
const K &key)
2732 return equal_range_impl(key);
2734 template <
typename K, if_heterogeneously_searchable<K> =
true>
2735 std::pair<const_iterator, const_iterator>
2736 equal_range(
const K &key)
const noexcept
2738 return equal_range_impl(key);
2742Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2743Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2744Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2745Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2747template <
class Key,
class T>
2748size_t qHash(
const QHash<Key, T> &key, size_t seed = 0)
2749 noexcept(
noexcept(qHash(std::declval<Key&>())) &&
noexcept(qHash(std::declval<T&>())))
2751 const QtPrivate::QHashCombine combine(seed);
2753 for (
auto it = key.begin(), end = key.end(); it != end; ++it) {
2754 size_t h = combine(seed, it.key());
2756 hash += combine(h, it.value());
2761template <
class Key,
class T>
2765 const QtPrivate::QHashCombine combine(seed);
2767 for (
auto it = key.begin(), end = key.end(); it != end; ++it) {
2768 size_t h = combine(seed, it.key());
2770 hash += combine(h, it.value());
2775template <
typename Key,
typename T,
typename Predicate>
2778 return QtPrivate::associative_erase_if(hash, pred);
2781template <
typename Key,
typename T,
typename Predicate>
2784 return QtPrivate::associative_erase_if(hash, pred);
The QAbstractFileEngineIterator class provides an iterator interface for custom file engines.
virtual ~QAbstractFileEnginePrivate()
QAbstractFileEnginePrivate(QAbstractFileEngine *q)
QFile::FileError fileError
QAbstractFileEngine *const q_ptr
\inmodule QtCore \reentrant
QDirPrivate(const QDirPrivate ©)
void clearCache(MetaDataClearing mode)
void initFileLists(const QDir &dir) const
QString resolveAbsoluteEntry() const
bool operator()(const QDirSortItem &, const QDirSortItem &) const
QDirSortItemComparator(QDir::SortFlags flags, QCollator *coll=nullptr)
int compareStrings(const QString &a, const QString &b, Qt::CaseSensitivity cs) const
const_iterator & operator++() noexcept
The prefix ++ operator ({++i}) advances the iterator to the next item in the hash and returns an iter...
const_iterator(const iterator &o) noexcept
Constructs a copy of other.
constexpr const_iterator() noexcept=default
Constructs an uninitialized iterator.
const_iterator operator++(int) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::forward_iterator_tag iterator_category
const T * operator->() const noexcept
Returns a pointer to the current item's value.
bool operator==(const const_iterator &o) const noexcept
Returns true if other points to the same item as this iterator; otherwise returns false.
const T & value() const noexcept
Returns the current item's value.
const Key & key() const noexcept
Returns the current item's key.
bool operator!=(const const_iterator &o) const noexcept
Returns true if other points to a different item than this iterator; otherwise returns false.
const T & operator*() const noexcept
Returns the current item's value.
key_iterator & operator++() noexcept
The prefix ++ operator ({++i}) advances the iterator to the next item in the hash and returns an iter...
key_iterator() noexcept=default
bool operator!=(key_iterator o) const noexcept
Returns true if other points to a different item than this iterator; otherwise returns false.
key_iterator operator++(int) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
const Key & operator*() const noexcept
Returns the current item's key.
const Key * operator->() const noexcept
Returns a pointer to the current item's key.
key_iterator(const_iterator o) noexcept
bool operator==(key_iterator o) const noexcept
Returns true if other points to the same item as this iterator; otherwise returns false.
const_iterator::iterator_category iterator_category
const_iterator base() const noexcept
Returns the underlying const_iterator this key_iterator is based on.
key_value_iterator try_emplace(const_iterator, K &&key, Args &&...args)
T & operator[](const K &key)
key_iterator keyEnd() const noexcept
const T operator[](const K &key) const noexcept
std::pair< const_iterator, const_iterator > equal_range(const Key &key) const noexcept
TryEmplaceResult insertOrAssign(const Key &key, Value &&value)
float load_factor() const noexcept
Returns the current load factor of the QHash's internal hash table.
const_iterator constFind(const Key &key) const noexcept
iterator insert(const Key &key, T &&value)
std::pair< key_value_iterator, bool > insert_or_assign(Key &&key, Value &&value)
~QHash()
Destroys the hash.
QHash & operator=(const QHash &other) noexcept
Assigns other to this hash and returns a reference to this hash.
iterator erase(const_iterator it)
std::pair< key_value_iterator, bool > try_emplace(K &&key, Args &&...args)
iterator emplace(const Key &key, Args &&... args)
key_value_iterator keyValueBegin()
const_iterator constFind(const K &key) const noexcept
T value(const K &key, const T &defaultValue) const noexcept
QHash(const QHash &other) noexcept
Constructs a copy of other.
auto asKeyValueRange() const &&
TryEmplaceResult tryEmplace(K &&key, Args &&...args)
TryEmplaceResult tryInsert(const Key &key, const T &value)
iterator emplace(Key &&key, Args &&... args)
Inserts a new element into the container.
friend bool comparesEqual(const QHash &lhs, const QHash &rhs) noexcept
TryEmplaceResult tryEmplace(const Key &key, Args &&...args)
\variable QHash::TryEmplaceResult::iterator
const_key_value_iterator constKeyValueEnd() const noexcept
bool empty() const noexcept
This function is provided for STL compatibility.
std::pair< key_value_iterator, bool > insert_or_assign(K &&key, Value &&value)
const_iterator cbegin() const noexcept
std::pair< key_value_iterator, bool > try_emplace(const Key &key, Args &&...args)
key_value_iterator insert_or_assign(const_iterator, K &&key, Value &&value)
iterator insert(Key &&key, T &&value)
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
void insert(const QHash &hash)
const_iterator find(const Key &key) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::pair< key_value_iterator, bool > try_emplace(Key &&key, Args &&...args)
static float max_load_factor() noexcept
QKeyValueIterator< const Key &, const T &, const_iterator > const_key_value_iterator
\inmodule QtCore
const_key_value_iterator keyValueBegin() const noexcept
TryEmplaceResult insertOrAssign(K &&key, Value &&value)
key_value_iterator keyValueEnd()
const_iterator end() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Key key_type
Typedef for Key.
iterator find(const K &key)
const_key_value_iterator constKeyValueBegin() const noexcept
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
qsizetype count(const K &key) const
iterator insert(Key &&key, const T &value)
std::pair< iterator, iterator > equal_range(const K &key)
key_iterator keyBegin() const noexcept
iterator Iterator
Qt-style synonym for QHash::iterator.
key_value_iterator insert_or_assign(const_iterator, const Key &key, Value &&value)
bool contains(const K &key) const
TryEmplaceResult tryInsert(K &&key, const T &value)
std::pair< const_iterator, const_iterator > equal_range(const K &key) const noexcept
size_t bucket_count() const noexcept
const_iterator ConstIterator
Qt-style synonym for QHash::const_iterator.
key_value_iterator try_emplace(const_iterator, Key &&key, Args &&...args)
auto asKeyValueRange() &&
auto asKeyValueRange() const &
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
qsizetype count() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
QHash(std::initializer_list< std::pair< Key, T > > list)
T value(const K &key) const noexcept
const_iterator find(const K &key) const noexcept
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
QHash(QHash &&other) noexcept
Move-constructs a QHash instance, making it point at the same object that other was pointing to.
std::pair< key_value_iterator, bool > insert_or_assign(const Key &key, Value &&value)
std::pair< iterator, iterator > equal_range(const Key &key)
const_iterator cend() const noexcept
key_value_iterator insert_or_assign(const_iterator, Key &&key, Value &&value)
static size_t max_bucket_count() noexcept
bool remove(const K &key)
QKeyValueIterator< const Key &, T &, iterator > key_value_iterator
\inmodule QtCore
TryEmplaceResult insertOrAssign(Key &&key, Value &&value)
QHash() noexcept=default
Constructs an empty hash.
const T & const_reference
TryEmplaceResult tryEmplace(Key &&key, Args &&...args)
key_value_iterator try_emplace(const_iterator, const Key &key, Args &&...args)
T mapped_type
Typedef for T.
const_key_value_iterator keyValueEnd() const noexcept
const_iterator begin() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
constexpr size_t bucketForHash(size_t nBuckets, size_t hash) noexcept
constexpr size_t bucketsForCapacity(size_t requestedCapacity) noexcept
constexpr bool HasStdHashSpecializationWithoutSeed
constexpr bool isRelocatable_v
size_t calculateHash(const T &t, size_t seed=0)
constexpr bool HasQHashOverload
std::conditional_t< std::is_same_v< HashKey, q20::remove_cvref_t< KeyArgument > >, KeyArgument, HashKey > HeterogenousConstructProxy
constexpr bool HasStdHashSpecializationWithSeed
Combined button and popup list for selecting options.
std::unique_ptr< QAbstractFileEngine > qt_custom_file_engine_handler_create(const QString &path)
static void appendIfMatchesNonDirListingFlags(const QDirListing::DirEntry &dirEntry, QDir::Filters filters, QFileInfoList &l)
static qsizetype rootLength(QStringView name, QDirPrivate::PathNormalizations flags)
static bool qt_cleanPath(QString *path)
QDebug operator<<(QDebug debug, QDir::Filters filters)
QDebug operator<<(QDebug debug, const QDir &dir)
static QDebug operator<<(QDebug debug, QDir::SortFlags sorting)
bool qt_isPathNormalized(const QString &path, QDirPrivate::PathNormalizations flags) noexcept
bool comparesEqual(const QDir &lhs, const QDir &rhs)
static bool treatAsAbsolute(const QString &path)
static bool checkPermissions(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
static qsizetype findStartOfNonNormalizedPath(const QChar *in, qsizetype i, qsizetype n, QDirPrivate::PathNormalizations flags) noexcept
static bool checkDotOrDotDot(const QDirListing::DirEntry &dirEntry, QDir::Filters filters)
Q_AUTOTEST_EXPORT bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
bool qt_isPathNormalized(const QString &path, QDirPrivate::PathNormalizations flags) noexcept
qsizetype erase_if(QMultiHash< Key, T > &hash, Predicate pred)
size_t qHash(const QMultiHash< Key, T > &key, size_t seed=0) noexcept(noexcept(qHash(std::declval< Key & >())) &&noexcept(qHash(std::declval< T & >())))
qsizetype erase_if(QHash< Key, T > &hash, Predicate pred)
QDirSortItem(const QFileInfo &fi, QDir::SortFlags sort)
friend bool operator==(Bucket lhs, Bucket rhs) noexcept
size_t offset() const noexcept
bool isUnused() const noexcept
Bucket(const Data *d, size_t bucket) noexcept
Bucket(Span *s, size_t i) noexcept
void advance(const Data *d) noexcept
Node & nodeAtOffset(size_t offset)
iterator toIterator(const Data *d) const noexcept
friend bool operator!=(Bucket lhs, Bucket rhs) noexcept
void advanceWrapped(const Data *d) noexcept
Bucket(iterator it) noexcept
size_t toBucketIndex(const Data *d) const noexcept
Bucket findBucketWithHash(const K &key, size_t hash) const noexcept
iterator begin() const noexcept
QHashPrivate::Span< Node > Span
size_t nextBucket(size_t bucket) const noexcept
typename Node::ValueType T
InsertionResult findOrInsert(const K &key) noexcept
Node * findNode(const K &key) const noexcept
QHashPrivate::iterator< Node > iterator
static Data * detached(Data *d)
iterator detachedIterator(iterator other) const noexcept
constexpr iterator end() const noexcept
bool shouldGrow() const noexcept
typename Node::KeyType Key
void rehash(size_t sizeHint=0)
Q_ALWAYS_INLINE void reallocationHelper(const Data &other, size_t nSpans)
void erase(Bucket bucket) noexcept(std::is_nothrow_destructible< Node >::value)
static Data * detached(Data *d, size_t size)
float loadFactor() const noexcept
static auto allocateSpans(size_t numBuckets)
Data(const Data &other, size_t reserved)
static constexpr size_t maxNumBuckets() noexcept
Bucket findBucket(const K &key) const noexcept
qsizetype free() noexcept(std::is_nothrow_destructible_v< T >)
bool contains(const T &val) const noexcept
static qsizetype freeChain(MultiNode *n) noexcept(std::is_nothrow_destructible_v< T >)
MultiNode(MultiNode &&other)
void insertMulti(Args &&... args)
MultiNode(const MultiNode &other)
static void createInPlace(MultiNode *n, const Key &k, Args &&... args)
MultiNode(const Key &k, Chain *c)
static void createInPlace(MultiNode *n, Key &&k, Args &&... args)
MultiNode(Key &&k, Chain *c) noexcept(std::is_nothrow_move_assignable_v< Key >)
MultiNodeChain< T > Chain
void emplaceValue(Args &&... args)
static void createInPlace(Node *n, const Key &k, Args &&...)
QHashDummyValue ValueType
void emplaceValue(Args &&...)
bool valuesEqual(const Node *) const
ValueType takeValue() noexcept
static void createInPlace(Node *n, Key &&k, Args &&...)
void emplaceValue(Args &&... args)
bool valuesEqual(const Node *other) const
T && takeValue() noexcept
static void createInPlace(Node *n, const Key &k, Args &&... args)
static void createInPlace(Node *n, Key &&k, Args &&... args)
static constexpr size_t SpanShift
static constexpr size_t LocalBucketMask
static constexpr size_t UnusedEntry
static constexpr size_t NEntries
unsigned char & nextFree()
unsigned char data[sizeof(Node)]
const Node & at(size_t i) const noexcept
void moveLocal(size_t from, size_t to) noexcept
void freeData() noexcept(std::is_nothrow_destructible< Node >::value)
void erase(size_t bucket) noexcept(std::is_nothrow_destructible< Node >::value)
unsigned char offsets[SpanConstants::NEntries]
Node & atOffset(size_t o) noexcept
size_t offset(size_t i) const noexcept
bool hasNode(size_t i) const noexcept
void moveFromSpan(Span &fromSpan, size_t fromIndex, size_t to) noexcept(std::is_nothrow_move_constructible_v< Node >)
const Node & atOffset(size_t o) const noexcept
Node & at(size_t i) noexcept
Node * node() const noexcept
size_t span() const noexcept
iterator operator++() noexcept
size_t index() const noexcept
QHashPrivate::Span< Node > Span
bool isUnused() const noexcept
bool operator!=(iterator other) const noexcept
bool atEnd() const noexcept
bool operator==(iterator other) const noexcept
TryEmplaceResult(QHash::iterator it, bool b)
TryEmplaceResult()=default