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/qttypetraits.h>
17#include <initializer_list>
19#include <QtCore/q20type_traits.h>
27 explicit QHashDummyValue() =
default;
28 friend constexpr bool operator==(QHashDummyValue, QHashDummyValue)
noexcept {
return true; }
29#ifndef __cpp_impl_three_way_comparison
30 friend constexpr bool operator!=(QHashDummyValue, QHashDummyValue)
noexcept {
return false; }
32 friend constexpr size_t qHash(QHashDummyValue)
noexcept =
delete;
33 friend constexpr size_t qHash(QHashDummyValue, size_t)
noexcept =
delete;
38template <
typename T,
typename =
void>
46template <
typename T,
typename =
void>
54template <
typename T,
typename =
void>
65 if constexpr (HasQHashOverload<T>) {
66 return qHash(t, seed);
67 }
else if constexpr (HasStdHashSpecializationWithSeed<T>) {
68 return std::hash<T>()(t, seed);
69 }
else if constexpr (HasStdHashSpecializationWithoutSeed<T>) {
71 return std::hash<T>()(t);
73 static_assert(QtPrivate::type_dependent_false<T>(),
"The key type must have a qHash overload or a std::hash specialization");
78template <
typename Key,
typename T>
86 template<
typename ...Args>
88 {
new (n)
Node{
std::move(k), T(
std::forward<Args>(args)...) }; }
89 template<
typename ...Args>
91 {
new (n)
Node{ Key(k), T(
std::forward<Args>(args)...) }; }
92 template<
typename ...Args>
95 value = T(
std::forward<Args>(args)...);
104template <
typename Key>
105struct Node<Key, QHashDummyValue> {
110 template<
typename ...Args>
112 {
new (n)
Node{
std::move(k) }; }
113 template<
typename ...Args>
115 {
new (n)
Node{ k }; }
116 template<
typename ...Args>
134 qsizetype nEntries = 0;
156template <
typename Key,
typename T>
166 template<
typename ...Args>
169 template<
typename ...Args>
194 Chain *chain =
new Chain{ c->value,
nullptr };
207 qsizetype size = n
->value->free();
211 template<
typename ...Args>
214 Chain *e =
new Chain{ T(
std::forward<Args>(args)...),
nullptr };
217 template<
typename ...Args>
220 value->value = T(
std::forward<Args>(args)...);
224template<
typename Node>
235 static_assert ((NEntries & LocalBucketMask) == 0,
"NEntries must be a power of two.");
246template<
typename Node>
255 struct {
alignas(
Node)
unsigned char data[
sizeof(Node)]; } storage;
257 unsigned char &
nextFree() {
return *
reinterpret_cast<
unsigned char *>(&storage); }
258 Node &
node() {
return *
reinterpret_cast<Node *>(&storage); }
267 memset(offsets, SpanConstants::UnusedEntry,
sizeof(offsets));
276 if constexpr (!
std::is_trivially_destructible<Node>::value) {
277 for (
auto o : offsets) {
278 if (o != SpanConstants::UnusedEntry)
279 entries[o].node().~Node();
288 Q_ASSERT(i < SpanConstants::NEntries);
289 Q_ASSERT(offsets[i] == SpanConstants::UnusedEntry);
300 Q_ASSERT(bucket < SpanConstants::NEntries);
301 Q_ASSERT(offsets[bucket] != SpanConstants::UnusedEntry);
303 unsigned char entry = offsets[bucket];
304 offsets[bucket] = SpanConstants::UnusedEntry;
316 return (offsets[i] != SpanConstants::UnusedEntry);
318 Node &
at(size_t i)
noexcept
320 Q_ASSERT(i < SpanConstants::NEntries);
321 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
323 return entries[offsets[i]].node();
325 const Node &
at(size_t i)
const noexcept
327 Q_ASSERT(i < SpanConstants::NEntries);
328 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
330 return entries[offsets[i]].node();
346 Q_ASSERT(offsets[from] != SpanConstants::UnusedEntry);
347 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
348 offsets[to] = offsets[from];
349 offsets[from] = SpanConstants::UnusedEntry;
353 Q_ASSERT(to < SpanConstants::NEntries);
354 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
355 Q_ASSERT(fromIndex < SpanConstants::NEntries);
356 Q_ASSERT(fromSpan.offsets[fromIndex] != SpanConstants::UnusedEntry);
360 offsets[to] = nextFree;
364 size_t fromOffset = fromSpan.offsets[fromIndex];
365 fromSpan.offsets[fromIndex] = SpanConstants::UnusedEntry;
368 if constexpr (isRelocatable_v<Node>) {
369 memcpy(&toEntry, &fromEntry,
sizeof(
Entry));
371 new (&toEntry.node()) Node(
std::move(fromEntry.node()));
372 fromEntry.node().~Node();
374 fromEntry.nextFree() = fromSpan
.nextFree;
375 fromSpan
.nextFree =
static_cast<
unsigned char>(fromOffset);
380 Q_ASSERT(
allocated < SpanConstants::NEntries);
395 static_assert(SpanConstants::NEntries % 8 == 0);
397 alloc = SpanConstants::NEntries / 8 * 3;
398 else if (
allocated == SpanConstants::NEntries / 8 * 3)
399 alloc = SpanConstants::NEntries / 8 * 5;
401 alloc =
allocated + SpanConstants::NEntries/8;
405 if constexpr (isRelocatable_v<Node>) {
410 new (&newEntries[i].node()) Node(
std::move(
entries[i].node()));
414 for (size_t i =
allocated; i < alloc; ++i) {
415 newEntries[i].nextFree() = uchar(i + 1);
427 constexpr int SizeDigits = std::numeric_limits<size_t>::digits;
431 if (requestedCapacity <= 64)
432 return SpanConstants::NEntries;
440 int count = qCountLeadingZeroBits(requestedCapacity);
442 return (std::numeric_limits<size_t>::max)();
443 return size_t(1) << (SizeDigits - count + 1);
447 return hash & (nBuckets - 1);
451template <
typename Node>
454template <
typename Node>
470 return (std::numeric_limits<ptrdiff_t>::max)() /
sizeof(Span);
481 :
span(d
->spans + (bucket >> SpanConstants::SpanShift)),
490 return ((span - d->spans) << SpanConstants::SpanShift) | index;
499 advance_impl(d,
nullptr);
503 return !
span->hasNode(index);
507 return span->offset(index);
511 return span->atOffset(offset);
515 return &
span->at(index);
519 return span->insert(index);
525 return lhs.span == rhs.span && lhs.index == rhs.index;
529 void advance_impl(
const Data *d,
Span *whenAtEnd)
noexcept
533 if (Q_UNLIKELY(index == SpanConstants::NEntries)) {
536 if (
span - d
->spans == ptrdiff_t(d->numBuckets >> SpanConstants::SpanShift))
549 constexpr qptrdiff MaxSpanCount = (std::numeric_limits<qptrdiff>::max)() /
sizeof(Span);
550 constexpr size_t MaxBucketCount = MaxSpanCount << SpanConstants::SpanShift;
552 if (numBuckets > MaxBucketCount) {
557 size_t nSpans = numBuckets >> SpanConstants::SpanShift;
558 return R{
new Span[nSpans], nSpans };
563 numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
564 spans = allocateSpans(numBuckets).spans;
565 seed = QHashSeed::globalSeed();
570 template <
bool Resized>
574 for (size_t s = 0; s < nSpans; ++s) {
576 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
577 if (!span.hasNode(index))
579 const Node &n = span.at(index);
580 auto it = Resized ? findBucket(n.key) :
Bucket {
spans + s, index };
581 Q_ASSERT(it.isUnused());
582 Node *newNode = it.insert();
583 new (newNode) Node(n);
590 auto r = allocateSpans(numBuckets);
592 reallocationHelper<
false>(other, r.nSpans);
596 numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
597 spans = allocateSpans(numBuckets).spans;
598 size_t otherNSpans = other.numBuckets >> SpanConstants::SpanShift;
599 reallocationHelper<
true>(other, otherNSpans);
614 return new Data(size);
631 return iterator{
this, other.bucket};
651 size_t newBucketCount = GrowthPolicy::bucketsForCapacity(sizeHint);
654 size_t oldBucketCount = numBuckets;
655 spans = allocateSpans(newBucketCount).spans;
656 numBuckets = newBucketCount;
657 size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
659 for (size_t s = 0; s < oldNSpans; ++s) {
660 Span &span = oldSpans[s];
661 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
662 if (!span.hasNode(index))
664 Node &n = span.at(index);
665 auto it = findBucket(n.key);
666 Q_ASSERT(it.isUnused());
667 Node *newNode = it.insert();
668 new (newNode) Node(
std::move(n));
678 if (bucket == numBuckets)
685 return float(size)/numBuckets;
689 return size >= (numBuckets >> 1);
695 return findBucketWithHash(key, hash);
700 static_assert(std::is_same_v<std::remove_cv_t<Key>, K> ||
701 QHashHeterogeneousSearch<std::remove_cv_t<Key>, K>::value);
702 Q_ASSERT(numBuckets > 0);
703 Bucket bucket(
this, GrowthPolicy::bucketForHash(numBuckets, hash));
707 size_t offset = bucket.offset();
708 if (offset == SpanConstants::UnusedEntry) {
711 Node &n = bucket.nodeAtOffset(offset);
712 if (qHashEquals(n.key, key))
715 bucket.advanceWrapped(
this);
719 template <
typename K> Node *
findNode(
const K &key)
const noexcept
721 auto bucket = findBucket(key);
722 if (bucket.isUnused())
724 return bucket.node();
737 if (numBuckets > 0) {
738 it = findBucketWithHash(key, hash);
740 return { it.toIterator(
this),
true };
744 it = findBucketWithHash(key, hash);
746 Q_ASSERT(it.span !=
nullptr);
747 Q_ASSERT(it.isUnused());
750 return { it.toIterator(
this),
false };
755 Q_ASSERT(bucket.span->hasNode(bucket.index));
756 bucket.span->erase(bucket.index);
762 next.advanceWrapped(
this);
763 size_t offset = next.offset();
764 if (offset == SpanConstants::UnusedEntry)
766 size_t hash =
QHashPrivate::calculateHash(next.nodeAtOffset(offset).key, seed);
767 Bucket newBucket(
this, GrowthPolicy::bucketForHash(numBuckets, hash));
769 if (newBucket == next) {
772 }
else if (newBucket == bucket) {
774 if (next.span == bucket.span) {
775 bucket.span->moveLocal(next.index, bucket.index);
778 bucket.span->moveFromSpan(*next.span, next.index, bucket.index);
783 newBucket.advanceWrapped(
this);
794template <
typename Node>
801 size_t span()
const noexcept {
return bucket >> SpanConstants::SpanShift; }
802 size_t index()
const noexcept {
return bucket & SpanConstants::LocalBucketMask; }
803 inline bool isUnused()
const noexcept {
return !d->spans[span()].hasNode(index()); }
805 inline Node *
node()
const noexcept
808 return &d->spans[span()].at(index());
810 bool atEnd()
const noexcept {
return !
d; }
816 if (bucket == d->numBuckets) {
827 {
return d == other.d && bucket == other.bucket; }
829 {
return !(*
this == other); }
841template <
typename Key,
typename T>
846 friend class QSet<
Key>;
847 friend class QMultiHash<
Key,
T>;
863 : d(
new Data(list.size()))
865 for (
typename std::initializer_list<
std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
876 static_assert(
std::is_nothrow_destructible_v<Key>,
"Types with throwing destructors are not supported in Qt containers.");
877 static_assert(
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
879 if (d && !d->ref.deref())
889 if (d && !d->ref.deref())
897 : d(
std::exchange(other.d,
nullptr))
919 for (;
f !=
l; ++
f) {
921 using V =
decltype(
e);
932 static bool compareIterators(
const const_iterator &lhs,
const const_iterator &rhs)
934 return lhs.i.node()->valuesEqual(rhs.i.node());
937 template <
typename AKey = Key,
typename AT = T,
938 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> =
true>
943 if (lhs.size() != rhs.size())
948 if (i == lhs
.end() || !compareIterators(i, it))
954 QT_DECLARE_EQUALITY_OPERATORS_HELPER(
QHash,
QHash, ,
noexcept,
955 template <
typename AKey = Key,
typename AT = T,
956 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> =
true>)
966 inline bool isEmpty()
const noexcept {
return !
d ||
d->
size == 0; }
1064 while (
i !=
end()) {
1091 template <
typename K>
1133 while (
i !=
end()) {
1182 friend class iterator;
1187 friend class iterator;
1188 friend class QHash<Key, T>;
1189 friend class QSet<
Key>;
1191 explicit inline const_iterator(piter it) : i(it) { }
1203 inline const Key &
key()
const noexcept {
return i.node()->key; }
1204 inline const T &
value()
const noexcept {
return i.node()->value; }
1205 inline const T &
operator*()
const noexcept {
return i.node()->value; }
1206 inline const T *
operator->()
const noexcept {
return &i.node()->value; }
1238 const Key &
operator*()
const noexcept {
return i.key(); }
1239 const Key *
operator->()
const noexcept {
return &i.key(); }
1252 inline iterator begin() {
if (!d)
return iterator(); detach();
return iterator(d->begin()); }
1269 auto asKeyValueRange()
const & {
return QtPrivate::QKeyValueRange<
const QHash &>(*
this); }
1271 auto asKeyValueRange()
const && {
return QtPrivate::QKeyValueRange<QHash>(std::move(*
this)); }
1302 iterator i = iterator{d->detachedIterator(it.i)};
1303 typename Data::Bucket bucket(i.i);
1306 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
1313 return equal_range_impl(*
this, key);
1317 return equal_range_impl(*
this, key);
1320 template <
typename Hash,
typename K>
static auto equal_range_impl(Hash &self,
const K &key)
1322 auto first = self.find(key);
1323 auto second = first;
1324 if (second !=
decltype(first){})
1326 return std::make_pair(first, second);
1329 template <
typename K> iterator findImpl(
const K &key)
1333 auto it = d->findBucket(key);
1334 size_t bucket = it.toBucketIndex(d);
1336 it =
typename Data::Bucket(d, bucket);
1339 return iterator(it.toIterator(d));
1341 template <
typename K>
const_iterator constFindImpl(
const K &key)
const noexcept
1345 auto it = d->findBucket(key);
1357 return findImpl(key);
1361 return constFindImpl(key);
1370 return emplace(key, value);
1375 return emplace(key,
std::move(value));
1380 return emplace(
std::move(key), value);
1385 return emplace(
std::move(key),
std::move(value));
1390 if (d == hash.d || !hash.d)
1400 emplace(it.key(), it.value());
1403 template <
typename ...Args>
1407 return emplace(
std::move(copy),
std::forward<Args>(args)...);
1410 template <
typename ...Args>
1414 if (d->shouldGrow())
1415 return emplace_helper(
std::move(key), T(
std::forward<Args>(args)...));
1416 return emplace_helper(
std::move(key),
std::forward<Args>(args)...);
1419 const auto copy = *
this;
1421 return emplace_helper(
std::move(key),
std::forward<Args>(args)...);
1424 template <
typename... Args>
1427 return tryEmplace_impl(key,
std::forward<Args>(args)...);
1429 template <
typename... Args>
1432 return tryEmplace_impl(
std::move(key),
std::forward<Args>(args)...);
1437 return tryEmplace_impl(key, value);
1440 template <
typename... Args>
1443 return tryEmplace_impl(key,
std::forward<Args>(args)...);
1445 template <
typename... Args>
1448 return tryEmplace_impl(
std::move(key),
std::forward<Args>(args)...);
1450 template <
typename... Args>
1455 template <
typename... Args>
1462 template <
typename K,
typename... Args>
1469 size_t hash =
QHashPrivate::calculateHash(key, d->seed);
1470 typename Data::Bucket bucket = d->findBucketWithHash(key, hash);
1471 const bool shouldInsert = bucket.isUnused();
1475 if (!isDetached() || (shouldInsert && d->shouldGrow())) {
1476 detachGuard = *
this;
1477 const bool resized = shouldInsert && d->shouldGrow();
1478 const size_t bucketIndex = bucket.toBucketIndex(d);
1481 d = resized ? Data::detached(d, d->size + 1) : Data::detached(d);
1482 bucket = resized ? d->findBucketWithHash(key, hash) :
typename Data::Bucket(d, bucketIndex);
1485 Node *n = bucket.insert();
1486 using ConstructProxy =
typename QHashPrivate::HeterogenousConstructProxy<Key, K>;
1487 Node::createInPlace(n, ConstructProxy(
std::forward<K>(key)),
1488 std::forward<Args>(args)...);
1491 return {iterator(bucket.toIterator(d)), shouldInsert};
1494 template <
typename Value>
1497 return insertOrAssign_impl(key,
std::forward<Value>(value));
1499 template <
typename Value>
1502 return insertOrAssign_impl(
std::move(key),
std::forward<Value>(value));
1504 template <
typename Value>
1507 return insertOrAssign_impl(key,
std::forward<Value>(value));
1509 template <
typename Value>
1512 return insertOrAssign_impl(
std::move(key),
std::forward<Value>(value));
1514 template <
typename Value>
1519 template <
typename Value>
1526 template <
typename K,
typename Value>
1529 auto r = tryEmplace(
std::forward<K>(key),
std::forward<Value>(value));
1531 *r.iterator =
std::forward<Value>(value);
1537 float load_factor()
const noexcept {
return d ? d->loadFactor() : 0; }
1543 inline bool empty()
const noexcept {
return isEmpty(); }
1546 template <
typename ...Args>
1547 iterator emplace_helper(Key &&key, Args &&... args)
1549 auto result = d->findOrInsert(key);
1550 if (!result.initialized)
1551 Node::createInPlace(result.it.node(),
std::move(key),
std::forward<Args>(args)...);
1553 result.it.node()->emplaceValue(
std::forward<Args>(args)...);
1554 return iterator(result.it);
1557 template <
typename K>
1560 template <
typename K>
1564 template <
typename K, if_heterogeneously_searchable<K> =
true>
1567 return removeImpl(key);
1569 template <
typename K, if_heterogeneously_searchable<K> =
true>
1572 return takeImpl(key);
1574 template <
typename K, if_heterogeneously_searchable<K> =
true>
1577 return d ? d->findNode(key) !=
nullptr :
false;
1579 template <
typename K, if_heterogeneously_searchable<K> =
true>
1582 return contains(key) ? 1 : 0;
1584 template <
typename K, if_heterogeneously_searchable<K> =
true>
1587 if (
auto *v = valueImpl(key))
1592 template <
typename K, if_heterogeneously_searchable<K> =
true>
1593 T
value(
const K &key,
const T &defaultValue)
const noexcept
1595 if (
auto *v = valueImpl(key))
1598 return defaultValue;
1600 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1603 return *tryEmplace(key).iterator;
1605 template <
typename K, if_heterogeneously_searchable<K> =
true>
1610 template <
typename K, if_heterogeneously_searchable<K> =
true>
1614 return equal_range_impl(*
this, key);
1616 template <
typename K, if_heterogeneously_searchable<K> =
true>
1620 return equal_range_impl(*
this, key);
1622 template <
typename K, if_heterogeneously_searchable<K> =
true>
1625 return findImpl(key);
1627 template <
typename K, if_heterogeneously_searchable<K> =
true>
1630 return constFindImpl(key);
1632 template <
typename K, if_heterogeneously_searchable<K> =
true>
1637 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1640 return tryEmplace_impl(
std::forward<K>(key),
std::forward<Args>(args)...);
1642 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1645 return tryEmplace_impl(
std::forward<K>(key), value);
1647 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1650 return tryEmplace_impl(
std::forward<K>(key),
std::forward<Args>(args)...);
1652 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1657 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1660 return insertOrAssign_impl(
std::forward<K>(key),
std::forward<Value>(value));
1662 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1665 return insertOrAssign_impl(
std::forward<K>(key),
std::forward<Value>(value));
1667 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1675template <
typename Key,
typename T>
1678 using Node = QHashPrivate::MultiNode<Key, T>;
1679 using Data = QHashPrivate::Data<Node>;
1680 using Chain = QHashPrivate::MultiNodeChain<T>;
1683 qsizetype m_size = 0;
1686 using key_type = Key;
1687 using mapped_type = T;
1688 using value_type = T;
1689 using size_type = qsizetype;
1690 using difference_type = qsizetype;
1691 using reference = T &;
1692 using const_reference =
const T &;
1694 QMultiHash()
noexcept =
default;
1695 inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
1696 : d(
new Data(list.size()))
1698 for (
typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
1699 insert(it->first, it->second);
1702 template <
typename InputIterator>
1703 QMultiHash(InputIterator f, InputIterator l);
1705 template <
typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> =
true>
1706 QMultiHash(InputIterator f, InputIterator l)
1708 QtPrivate::reserveIfForwardIterator(
this, f, l);
1710 insert(f.key(), f.value());
1713 template <
typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> =
true>
1714 QMultiHash(InputIterator f, InputIterator l)
1716 QtPrivate::reserveIfForwardIterator(
this, f, l);
1717 for (; f != l; ++f) {
1719 using V =
decltype(e);
1720 insert(std::forward<V>(e).first, std::forward<V>(e).second);
1724 QMultiHash(
const QMultiHash &other)
noexcept
1725 : d(other.d), m_size(other.m_size)
1732 static_assert(std::is_nothrow_destructible_v<Key>,
"Types with throwing destructors are not supported in Qt containers.");
1733 static_assert(std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
1735 if (d && !d->ref.deref())
1739 QMultiHash &operator=(
const QMultiHash &other)
noexcept(std::is_nothrow_destructible<Node>::value)
1745 if (d && !d->ref.deref())
1748 m_size = other.m_size;
1752 QMultiHash(QMultiHash &&other)
noexcept
1753 : d(std::exchange(other.d,
nullptr)),
1754 m_size(std::exchange(other.m_size, 0))
1757 QMultiHash &operator=(QMultiHash &&other)
noexcept(std::is_nothrow_destructible<Node>::value)
1759 QMultiHash moved(std::move(other));
1764 explicit QMultiHash(
const QHash<Key, T> &other)
1765 : QMultiHash(other.begin(), other.end())
1768 explicit QMultiHash(QHash<Key, T> &&other)
1770 unite(std::move(other));
1773 void swap(QMultiHash &other)
noexcept
1775 qt_ptr_swap(d, other.d);
1776 std::swap(m_size, other.m_size);
1781 template <
typename AKey = Key,
typename AT = T,
1782 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> =
true>
1783 friend bool comparesEqual(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept
1787 if (lhs.m_size != rhs.m_size)
1789 if (lhs.m_size == 0)
1794 if (lhs.d->size != rhs.d->size)
1796 for (
auto it = rhs.d->begin(); it != rhs.d->end(); ++it) {
1797 auto *n = lhs.d->findNode(it.node()->key);
1800 Chain *e = it.node()->value;
1802 Chain *oe = n->value;
1804 if (oe->value == e->value)
1816 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiHash, QMultiHash, ,
noexcept,
1817 template <
typename AKey = Key,
typename AT = T,
1818 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> =
true>)
1821 friend bool operator==(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept;
1822 friend bool operator!=(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept;
1825 inline qsizetype size()
const noexcept {
return m_size; }
1828 inline bool isEmpty()
const noexcept {
return !m_size; }
1830 inline qsizetype capacity()
const noexcept {
return d ? qsizetype(d->numBuckets >> 1) : 0; }
1831 void reserve(qsizetype size)
1834 if (size && (
this->capacity() >= size))
1839 d = Data::detached(d, size_t(size));
1841 inline void squeeze() { reserve(0); }
1843 inline void detach() {
if (!d || d->ref.isShared()) d = Data::detached(d); }
1844 inline bool isDetached()
const noexcept {
return d && !d->ref.isShared(); }
1845 bool isSharedWith(
const QMultiHash &other)
const noexcept {
return d == other.d; }
1847 void clear()
noexcept(std::is_nothrow_destructible<Node>::value)
1849 if (d && !d->ref.deref())
1855 qsizetype remove(
const Key &key)
1857 return removeImpl(key);
1860 template <
typename K> qsizetype removeImpl(
const K &key)
1864 auto it = d->findBucket(key);
1865 size_t bucket = it.toBucketIndex(d);
1867 it =
typename Data::Bucket(d, bucket);
1871 qsizetype n = Node::freeChain(it.node());
1873 Q_ASSERT(m_size >= 0);
1879 template <
typename Predicate>
1880 qsizetype removeIf(Predicate pred)
1882 return QtPrivate::associative_erase_if(*
this, pred);
1885 T take(
const Key &key)
1887 return takeImpl(key);
1890 template <
typename K> T takeImpl(
const K &key)
1894 auto it = d->findBucket(key);
1895 size_t bucket = it.toBucketIndex(d);
1897 it =
typename Data::Bucket(d, bucket);
1901 Chain *e = it.node()->value;
1903 T t = std::move(e->value);
1905 it.node()->value = e->next;
1912 Q_ASSERT(m_size >= 0);
1917 bool contains(
const Key &key)
const noexcept
1921 return d->findNode(key) !=
nullptr;
1925 const Key *keyImpl(
const T &value)
const noexcept
1928 auto i = d->begin();
1929 while (i != d->end()) {
1930 Chain *e = i.node()->value;
1931 if (e->contains(value))
1932 return &i.node()->key;
1940 Key key(
const T &value)
const noexcept
1942 if (
auto *k = keyImpl(value))
1947 Key key(
const T &value,
const Key &defaultKey)
const noexcept
1949 if (
auto *k = keyImpl(value))
1956 template <
typename K>
1957 T *valueImpl(
const K &key)
const noexcept
1960 Node *n = d->findNode(key);
1963 return &n->value->value;
1969 T value(
const Key &key)
const noexcept
1971 if (
auto *v = valueImpl(key))
1976 T value(
const Key &key,
const T &defaultValue)
const noexcept
1978 if (
auto *v = valueImpl(key))
1981 return defaultValue;
1984 T &operator[](
const Key &key)
1986 return operatorIndexImpl(key);
1989 template <
typename K> T &operatorIndexImpl(
const K &key)
1991 const auto copy = isDetached() ? QMultiHash() : *
this;
1993 auto result = d->findOrInsert(key);
1994 Q_ASSERT(!result.it.atEnd());
1995 if (!result.initialized) {
1996 Node::createInPlace(result.it.node(), Key(key), T());
1999 return result.it.node()->value->value;
2003 const T operator[](
const Key &key)
const noexcept
2008 QList<Key> uniqueKeys()
const
2012 auto i = d->begin();
2013 while (i != d->end()) {
2014 res.append(i.node()->key);
2021 QList<Key> keys()
const {
return QList<Key>(keyBegin(), keyEnd()); }
2022 QList<Key> keys(
const T &value)
const
2025 const_iterator i = begin();
2026 while (i != end()) {
2027 if (i.value() == value)
2028 res.append(i.key());
2034 QList<T> values()
const {
return QList<T>(begin(), end()); }
2035 QList<T> values(
const Key &key)
const
2037 return valuesImpl(key);
2040 template <
typename K> QList<T> valuesImpl(
const K &key)
const
2044 Node *n = d->findNode(key);
2046 Chain *e = n->value;
2048 values.append(e->value);
2057 class const_iterator;
2061 using piter =
typename QHashPrivate::iterator<Node>;
2062 friend class const_iterator;
2063 friend class QMultiHash<Key, T>;
2065 Chain **e =
nullptr;
2066 explicit inline iterator(piter it, Chain **entry =
nullptr)
noexcept : i(it), e(entry)
2068 if (!it.atEnd() && !e) {
2069 e = &it.node()->value;
2075 typedef std::forward_iterator_tag iterator_category;
2076 typedef qptrdiff difference_type;
2077 typedef T value_type;
2079 typedef T &reference;
2081 constexpr iterator()
noexcept =
default;
2083 inline const Key &key()
const noexcept {
return i.node()->key; }
2084 inline T &value()
const noexcept {
return (*e)->value; }
2085 inline T &operator*()
const noexcept {
return (*e)->value; }
2086 inline T *operator->()
const noexcept {
return &(*e)->value; }
2087 inline bool operator==(
const iterator &o)
const noexcept {
return e == o.e; }
2088 inline bool operator!=(
const iterator &o)
const noexcept {
return e != o.e; }
2090 inline iterator &operator++()
noexcept {
2096 e = i.atEnd() ?
nullptr : &i.node()->value;
2100 inline iterator operator++(
int)
noexcept {
2106 inline bool operator==(
const const_iterator &o)
const noexcept {
return e == o.e; }
2107 inline bool operator!=(
const const_iterator &o)
const noexcept {
return e != o.e; }
2109 friend class iterator;
2111 class const_iterator
2113 using piter =
typename QHashPrivate::iterator<Node>;
2114 friend class iterator;
2115 friend class QMultiHash<Key, T>;
2117 Chain **e =
nullptr;
2118 explicit inline const_iterator(piter it, Chain **entry =
nullptr)
noexcept : i(it), e(entry)
2120 if (!it.atEnd() && !e) {
2121 e = &it.node()->value;
2127 typedef std::forward_iterator_tag iterator_category;
2128 typedef qptrdiff difference_type;
2129 typedef T value_type;
2130 typedef const T *pointer;
2131 typedef const T &reference;
2133 constexpr const_iterator()
noexcept =
default;
2134 inline const_iterator(
const iterator &o)
noexcept : i(o.i), e(o.e) { }
2136 inline const Key &key()
const noexcept {
return i.node()->key; }
2137 inline T &value()
const noexcept {
return (*e)->value; }
2138 inline T &operator*()
const noexcept {
return (*e)->value; }
2139 inline T *operator->()
const noexcept {
return &(*e)->value; }
2140 inline bool operator==(
const const_iterator &o)
const noexcept {
return e == o.e; }
2141 inline bool operator!=(
const const_iterator &o)
const noexcept {
return e != o.e; }
2143 inline const_iterator &operator++()
noexcept {
2149 e = i.atEnd() ?
nullptr : &i.node()->value;
2153 inline const_iterator operator++(
int)
noexcept
2155 const_iterator r = *
this;
2160 friend class const_iterator;
2167 typedef typename const_iterator::iterator_category iterator_category;
2168 typedef qptrdiff difference_type;
2169 typedef Key value_type;
2170 typedef const Key *pointer;
2171 typedef const Key &reference;
2173 key_iterator()
noexcept =
default;
2174 explicit key_iterator(const_iterator o)
noexcept : i(o) { }
2176 const Key &operator*()
const noexcept {
return i.key(); }
2177 const Key *operator->()
const noexcept {
return &i.key(); }
2178 bool operator==(key_iterator o)
const noexcept {
return i == o.i; }
2179 bool operator!=(key_iterator o)
const noexcept {
return i != o.i; }
2181 inline key_iterator &operator++()
noexcept { ++i;
return *
this; }
2182 inline key_iterator operator++(
int)
noexcept {
return key_iterator(i++);}
2183 const_iterator base()
const noexcept {
return i; }
2186 typedef QKeyValueIterator<
const Key&,
const T&, const_iterator> const_key_value_iterator;
2187 typedef QKeyValueIterator<
const Key&, T&, iterator> key_value_iterator;
2190 inline iterator begin() {
if (!d)
return iterator(); detach();
return iterator(d->begin()); }
2191 inline const_iterator begin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2192 inline const_iterator cbegin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2193 inline const_iterator constBegin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2194 inline iterator end()
noexcept {
return iterator(); }
2195 inline const_iterator end()
const noexcept {
return const_iterator(); }
2196 inline const_iterator cend()
const noexcept {
return const_iterator(); }
2197 inline const_iterator constEnd()
const noexcept {
return const_iterator(); }
2198 inline key_iterator keyBegin()
const noexcept {
return key_iterator(begin()); }
2199 inline key_iterator keyEnd()
const noexcept {
return key_iterator(end()); }
2200 inline key_value_iterator keyValueBegin()
noexcept {
return key_value_iterator(begin()); }
2201 inline key_value_iterator keyValueEnd()
noexcept {
return key_value_iterator(end()); }
2202 inline const_key_value_iterator keyValueBegin()
const noexcept {
return const_key_value_iterator(begin()); }
2203 inline const_key_value_iterator constKeyValueBegin()
const noexcept {
return const_key_value_iterator(begin()); }
2204 inline const_key_value_iterator keyValueEnd()
const noexcept {
return const_key_value_iterator(end()); }
2205 inline const_key_value_iterator constKeyValueEnd()
const noexcept {
return const_key_value_iterator(end()); }
2206 auto asKeyValueRange() & {
return QtPrivate::QKeyValueRange<QMultiHash &>(*
this); }
2207 auto asKeyValueRange()
const & {
return QtPrivate::QKeyValueRange<
const QMultiHash &>(*
this); }
2208 auto asKeyValueRange() && {
return QtPrivate::QKeyValueRange<QMultiHash>(std::move(*
this)); }
2209 auto asKeyValueRange()
const && {
return QtPrivate::QKeyValueRange<QMultiHash>(std::move(*
this)); }
2211 iterator detach(const_iterator it)
2215 if (d->ref.isShared()) {
2218 Chain *entry = i.node()->value;
2219 while (entry != *it.e) {
2221 entry = entry->next;
2226 i = d->detachedIterator(i);
2227 e = &i.node()->value;
2234 return iterator(i, e);
2237 iterator erase(const_iterator it)
2240 iterator iter = detach(it);
2243 Chain *next = e->next;
2247 if (i.e == &i.i.node()->value) {
2249 typename Data::Bucket bucket(i.i);
2251 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
2252 i = iterator(++iter.i);
2254 i = iterator(bucket.toIterator(d));
2256 i = iterator(++iter.i);
2260 Q_ASSERT(m_size >= 0);
2265 typedef iterator Iterator;
2266 typedef const_iterator ConstIterator;
2267 inline qsizetype count()
const noexcept {
return size(); }
2270 template <
typename K> iterator findImpl(
const K &key)
2274 auto it = d->findBucket(key);
2275 size_t bucket = it.toBucketIndex(d);
2277 it =
typename Data::Bucket(d, bucket);
2281 return iterator(it.toIterator(d));
2283 template <
typename K> const_iterator constFindImpl(
const K &key)
const noexcept
2287 auto it = d->findBucket(key);
2290 return const_iterator(it.toIterator(d));
2293 iterator find(
const Key &key)
2295 return findImpl(key);
2297 const_iterator constFind(
const Key &key)
const noexcept
2299 return constFindImpl(key);
2301 const_iterator find(
const Key &key)
const noexcept
2303 return constFindImpl(key);
2306 iterator insert(
const Key &key,
const T &value)
2308 return emplace(key, value);
2311 iterator insert(
const Key &key, T &&value)
2313 return emplace(key, std::move(value));
2316 iterator insert(Key &&key,
const T &value)
2318 return emplace(std::move(key), value);
2321 iterator insert(Key &&key, T &&value)
2323 return emplace(std::move(key), std::move(value));
2326 template <
typename ...Args>
2327 iterator emplace(
const Key &key, Args &&... args)
2329 return emplace(Key(key), std::forward<Args>(args)...);
2332 template <
typename ...Args>
2333 iterator emplace(Key &&key, Args &&... args)
2336 if (d->shouldGrow())
2337 return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
2338 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2341 const auto copy = *
this;
2343 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2347 float load_factor()
const noexcept {
return d ? d->loadFactor() : 0; }
2348 static float max_load_factor()
noexcept {
return 0.5; }
2349 size_t bucket_count()
const noexcept {
return d ? d->numBuckets : 0; }
2350 static size_t max_bucket_count()
noexcept {
return Data::maxNumBuckets(); }
2353 inline bool empty()
const noexcept {
return isEmpty(); }
2355 inline iterator replace(
const Key &key,
const T &value)
2357 return emplaceReplace(key, value);
2360 template <
typename ...Args>
2361 iterator emplaceReplace(
const Key &key, Args &&... args)
2363 return emplaceReplace(Key(key), std::forward<Args>(args)...);
2366 template <
typename ...Args>
2367 iterator emplaceReplace(Key &&key, Args &&... args)
2370 if (d->shouldGrow())
2371 return emplaceReplace_helper(std::move(key), T(std::forward<Args>(args)...));
2372 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2375 const auto copy = *
this;
2377 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2380 inline QMultiHash &operator+=(
const QMultiHash &other)
2381 {
this->unite(other);
return *
this; }
2382 inline QMultiHash operator+(
const QMultiHash &other)
const
2383 { QMultiHash result = *
this; result += other;
return result; }
2385 bool contains(
const Key &key,
const T &value)
const noexcept
2387 return containsImpl(key, value);
2390 template <
typename K>
bool containsImpl(
const K &key,
const T &value)
const noexcept
2394 auto n = d->findNode(key);
2397 return n->value->contains(value);
2401 qsizetype remove(
const Key &key,
const T &value)
2403 return removeImpl(key, value);
2406 template <
typename K> qsizetype removeImpl(
const K &key,
const T &value)
2410 auto it = d->findBucket(key);
2411 size_t bucket = it.toBucketIndex(d);
2413 it =
typename Data::Bucket(d, bucket);
2418 Chain **e = &it.node()->value;
2421 if (entry->value == value) {
2429 if (!it.node()->value)
2432 Q_ASSERT(m_size >= 0);
2437 qsizetype count(
const Key &key)
const noexcept
2439 return countImpl(key);
2442 template <
typename K> qsizetype countImpl(
const K &key)
const noexcept
2446 auto it = d->findBucket(key);
2450 Chain *e = it.node()->value;
2460 qsizetype count(
const Key &key,
const T &value)
const noexcept
2462 return countImpl(key, value);
2465 template <
typename K> qsizetype countImpl(
const K &key,
const T &value)
const noexcept
2469 auto it = d->findBucket(key);
2473 Chain *e = it.node()->value;
2475 if (e->value == value)
2483 template <
typename K> iterator findImpl(
const K &key,
const T &value)
2487 const auto copy = isDetached() ? QMultiHash() : *
this;
2489 auto it = constFind(key, value);
2490 return iterator(it.i, it.e);
2492 template <
typename K> const_iterator constFindImpl(
const K &key,
const T &value)
const noexcept
2494 const_iterator i(constFind(key));
2495 const_iterator end(constEnd());
2496 while (i != end && i.key() == key) {
2497 if (i.value() == value)
2505 iterator find(
const Key &key,
const T &value)
2507 return findImpl(key, value);
2510 const_iterator constFind(
const Key &key,
const T &value)
const noexcept
2512 return constFindImpl(key, value);
2514 const_iterator find(
const Key &key,
const T &value)
const noexcept
2516 return constFind(key, value);
2519 QMultiHash &unite(
const QMultiHash &other)
2523 }
else if (other.isEmpty()) {
2526 QMultiHash copy(other);
2528 for (
auto cit = copy.cbegin(); cit != copy.cend(); ++cit)
2529 insert(cit.key(), *cit);
2534 QMultiHash &unite(
const QHash<Key, T> &other)
2536 for (
auto cit = other.cbegin(); cit != other.cend(); ++cit)
2537 insert(cit.key(), *cit);
2541 QMultiHash &unite(QHash<Key, T> &&other)
2543 if (!other.isDetached()) {
2547 auto it = other.d->begin();
2548 for (
const auto end = other.d->end(); it != end; ++it)
2549 emplace(std::move(it.node()->key), it.node()->takeValue());
2554 std::pair<iterator, iterator> equal_range(
const Key &key)
2556 return equal_range_impl(key);
2559 template <
typename K> std::pair<iterator, iterator> equal_range_impl(
const K &key)
2561 const auto copy = isDetached() ? QMultiHash() : *
this;
2563 auto pair = std::as_const(*
this).equal_range(key);
2564 return {iterator(pair.first.i), iterator(pair.second.i)};
2568 std::pair<const_iterator, const_iterator> equal_range(
const Key &key)
const noexcept
2570 return equal_range_impl(key);
2573 template <
typename K> std::pair<const_iterator, const_iterator> equal_range_impl(
const K &key)
const noexcept
2576 return {end(), end()};
2578 auto bucket = d->findBucket(key);
2579 if (bucket.isUnused())
2580 return {end(), end()};
2581 auto it = bucket.toIterator(d);
2584 return {const_iterator(it), const_iterator(end)};
2587 void detach_helper()
2593 Data *dd =
new Data(*d);
2594 if (!d->ref.deref())
2599 template<
typename... Args>
2600 iterator emplace_helper(Key &&key, Args &&...args)
2602 auto result = d->findOrInsert(key);
2603 if (!result.initialized)
2604 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2606 result.it.node()->insertMulti(std::forward<Args>(args)...);
2608 return iterator(result.it);
2611 template<
typename... Args>
2612 iterator emplaceReplace_helper(Key &&key, Args &&...args)
2614 auto result = d->findOrInsert(key);
2615 if (!result.initialized) {
2616 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2619 result.it.node()->emplaceValue(std::forward<Args>(args)...);
2621 return iterator(result.it);
2624 template <
typename K>
2625 using if_heterogeneously_searchable = QHashPrivate::if_heterogeneously_searchable_with<Key, K>;
2627 template <
typename K>
2628 using if_key_constructible_from = std::enable_if_t<std::is_constructible_v<Key, K>,
bool>;
2631 template <
typename K, if_heterogeneously_searchable<K> =
true>
2632 qsizetype remove(
const K &key)
2634 return removeImpl(key);
2636 template <
typename K, if_heterogeneously_searchable<K> =
true>
2637 T take(
const K &key)
2639 return takeImpl(key);
2641 template <
typename K, if_heterogeneously_searchable<K> =
true>
2642 bool contains(
const K &key)
const noexcept
2646 return d->findNode(key) !=
nullptr;
2648 template <
typename K, if_heterogeneously_searchable<K> =
true>
2649 T value(
const K &key)
const noexcept
2651 if (
auto *v = valueImpl(key))
2656 template <
typename K, if_heterogeneously_searchable<K> =
true>
2657 T value(
const K &key,
const T &defaultValue)
const noexcept
2659 if (
auto *v = valueImpl(key))
2662 return defaultValue;
2664 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
2665 T &operator[](
const K &key)
2667 return operatorIndexImpl(key);
2669 template <
typename K, if_heterogeneously_searchable<K> =
true>
2670 const T operator[](
const K &key)
const noexcept
2674 template <
typename K, if_heterogeneously_searchable<K> =
true>
2675 QList<T> values(
const K &key)
2677 return valuesImpl(key);
2679 template <
typename K, if_heterogeneously_searchable<K> =
true>
2680 iterator find(
const K &key)
2682 return findImpl(key);
2684 template <
typename K, if_heterogeneously_searchable<K> =
true>
2685 const_iterator constFind(
const K &key)
const noexcept
2687 return constFindImpl(key);
2689 template <
typename K, if_heterogeneously_searchable<K> =
true>
2690 const_iterator find(
const K &key)
const noexcept
2692 return constFindImpl(key);
2694 template <
typename K, if_heterogeneously_searchable<K> =
true>
2695 bool contains(
const K &key,
const T &value)
const noexcept
2697 return containsImpl(key, value);
2699 template <
typename K, if_heterogeneously_searchable<K> =
true>
2700 qsizetype remove(
const K &key,
const T &value)
2702 return removeImpl(key, value);
2704 template <
typename K, if_heterogeneously_searchable<K> =
true>
2705 qsizetype count(
const K &key)
const noexcept
2707 return countImpl(key);
2709 template <
typename K, if_heterogeneously_searchable<K> =
true>
2710 qsizetype count(
const K &key,
const T &value)
const noexcept
2712 return countImpl(key, value);
2714 template <
typename K, if_heterogeneously_searchable<K> =
true>
2715 iterator find(
const K &key,
const T &value)
2717 return findImpl(key, value);
2719 template <
typename K, if_heterogeneously_searchable<K> =
true>
2720 const_iterator constFind(
const K &key,
const T &value)
const noexcept
2722 return constFindImpl(key, value);
2724 template <
typename K, if_heterogeneously_searchable<K> =
true>
2725 const_iterator find(
const K &key,
const T &value)
const noexcept
2727 return constFind(key, value);
2729 template <
typename K, if_heterogeneously_searchable<K> =
true>
2730 std::pair<iterator, iterator>
2731 equal_range(
const K &key)
2733 return equal_range_impl(key);
2735 template <
typename K, if_heterogeneously_searchable<K> =
true>
2736 std::pair<const_iterator, const_iterator>
2737 equal_range(
const K &key)
const noexcept
2739 return equal_range_impl(key);
2743Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2744Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2745Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2746Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2748template <
class Key,
class T>
2749size_t qHash(
const QHash<Key, T> &key, size_t seed = 0)
2750 noexcept(
noexcept(qHash(std::declval<Key&>())) &&
noexcept(qHash(std::declval<T&>())))
2752 const QtPrivate::QHashCombine combine(seed);
2754 for (
auto it = key.begin(), end = key.end(); it != end; ++it) {
2755 size_t h = combine(seed, it.key());
2757 hash += combine(h, it.value());
2762template <
class Key,
class T>
2766 const QtPrivate::QHashCombine combine(seed);
2768 for (
auto it = key.begin(), end = key.end(); it != end; ++it) {
2769 size_t h = combine(seed, it.key());
2771 hash += combine(h, it.value());
2776template <
typename Key,
typename T,
typename Predicate>
2779 return QtPrivate::associative_erase_if(hash, pred);
2782template <
typename Key,
typename T,
typename Predicate>
2785 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.
QHash & operator=(const QHash &other) noexcept(std::is_nothrow_destructible< Node >::value)
Assigns other to this hash and returns a reference to this hash.
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.
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)
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