8#include <QtCore/qalgorithms.h>
9#include <QtCore/qcontainertools_impl.h>
10#include <QtCore/qhashfunctions.h>
11#include <QtCore/qiterator.h>
12#include <QtCore/qlist.h>
13#include <QtCore/qrefcount.h>
14#include <QtCore/qttypetraits.h>
16#include <initializer_list>
18#include <QtCore/q20type_traits.h>
26 bool operator==(
const QHashDummyValue &)
const noexcept {
return true; }
31template <
typename T,
typename =
void>
39template <
typename T,
typename =
void>
47template <
typename T,
typename =
void>
58 if constexpr (HasQHashOverload<T>) {
59 return qHash(t, seed);
60 }
else if constexpr (HasStdHashSpecializationWithSeed<T>) {
61 return std::hash<T>()(t, seed);
62 }
else if constexpr (HasStdHashSpecializationWithoutSeed<T>) {
64 return std::hash<T>()(t);
66 static_assert(QtPrivate::type_dependent_false<T>(),
"The key type must have a qHash overload or a std::hash specialization");
71template <
typename Key,
typename T>
79 template<
typename ...Args>
81 {
new (n)
Node{
std::move(k), T(
std::forward<Args>(args)...) }; }
82 template<
typename ...Args>
84 {
new (n)
Node{ Key(k), T(
std::forward<Args>(args)...) }; }
85 template<
typename ...Args>
88 value = T(
std::forward<Args>(args)...);
97template <
typename Key>
98struct Node<Key, QHashDummyValue> {
100 using ValueType = QHashDummyValue;
103 template<
typename ...Args>
105 {
new (n)
Node{
std::move(k) }; }
106 template<
typename ...Args>
108 {
new (n)
Node{ k }; }
109 template<
typename ...Args>
127 qsizetype nEntries = 0;
149template <
typename Key,
typename T>
159 template<
typename ...Args>
161 {
new (n)
MultiNode(
std::move(k),
new Chain{ T(
std::forward<Args>(args)...),
nullptr }); }
162 template<
typename ...Args>
164 {
new (n)
MultiNode(k,
new Chain{ T(
std::forward<Args>(args)...),
nullptr }); }
187 Chain *chain =
new Chain{ c->value,
nullptr };
200 qsizetype size = n
->value->free();
204 template<
typename ...Args>
207 Chain *e =
new Chain{ T(
std::forward<Args>(args)...),
nullptr };
208 e->next = std::exchange(value, e);
210 template<
typename ...Args>
213 value->value = T(
std::forward<Args>(args)...);
217template<
typename Node>
220 return QTypeInfo<
typename Node::KeyType>::isRelocatable && QTypeInfo<
typename Node::ValueType>::isRelocatable;
229 static_assert ((NEntries & LocalBucketMask) == 0,
"NEntries must be a power of two.");
240template<
typename Node>
249 struct {
alignas(Node)
unsigned char data[
sizeof(Node)]; } storage;
251 unsigned char &
nextFree() {
return *
reinterpret_cast<
unsigned char *>(&storage); }
252 Node &
node() {
return *
reinterpret_cast<Node *>(&storage); }
261 memset(offsets, SpanConstants::UnusedEntry,
sizeof(offsets));
270 if constexpr (!
std::is_trivially_destructible<Node>::value) {
271 for (
auto o : offsets) {
272 if (o != SpanConstants::UnusedEntry)
273 entries[o].node().~Node();
282 Q_ASSERT(i < SpanConstants::NEntries);
283 Q_ASSERT(offsets[i] == SpanConstants::UnusedEntry);
294 Q_ASSERT(bucket < SpanConstants::NEntries);
295 Q_ASSERT(offsets[bucket] != SpanConstants::UnusedEntry);
297 unsigned char entry = offsets[bucket];
298 offsets[bucket] = SpanConstants::UnusedEntry;
310 return (offsets[i] != SpanConstants::UnusedEntry);
312 Node &
at(size_t i)
noexcept
314 Q_ASSERT(i < SpanConstants::NEntries);
315 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
317 return entries[offsets[i]].node();
319 const Node &
at(size_t i)
const noexcept
321 Q_ASSERT(i < SpanConstants::NEntries);
322 Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
324 return entries[offsets[i]].node();
340 Q_ASSERT(offsets[from] != SpanConstants::UnusedEntry);
341 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
342 offsets[to] = offsets[from];
343 offsets[from] = SpanConstants::UnusedEntry;
347 Q_ASSERT(to < SpanConstants::NEntries);
348 Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
349 Q_ASSERT(fromIndex < SpanConstants::NEntries);
350 Q_ASSERT(fromSpan.offsets[fromIndex] != SpanConstants::UnusedEntry);
354 offsets[to] = nextFree;
358 size_t fromOffset = fromSpan.offsets[fromIndex];
359 fromSpan.offsets[fromIndex] = SpanConstants::UnusedEntry;
362 if constexpr (isRelocatable<Node>()) {
363 memcpy(&toEntry, &fromEntry,
sizeof(
Entry));
365 new (&toEntry.node()) Node(
std::move(fromEntry.node()));
366 fromEntry.node().~Node();
368 fromEntry.nextFree() = fromSpan
.nextFree;
369 fromSpan
.nextFree =
static_cast<
unsigned char>(fromOffset);
374 Q_ASSERT(
allocated < SpanConstants::NEntries);
389 static_assert(SpanConstants::NEntries % 8 == 0);
391 alloc = SpanConstants::NEntries / 8 * 3;
392 else if (
allocated == SpanConstants::NEntries / 8 * 3)
393 alloc = SpanConstants::NEntries / 8 * 5;
395 alloc =
allocated + SpanConstants::NEntries/8;
399 if constexpr (isRelocatable<Node>()) {
404 new (&newEntries[i].node()) Node(
std::move(
entries[i].node()));
408 for (size_t i =
allocated; i < alloc; ++i) {
409 newEntries[i].nextFree() = uchar(i + 1);
421 constexpr int SizeDigits = std::numeric_limits<size_t>::digits;
425 if (requestedCapacity <= 64)
426 return SpanConstants::NEntries;
434 int count = qCountLeadingZeroBits(requestedCapacity);
436 return (std::numeric_limits<size_t>::max)();
437 return size_t(1) << (SizeDigits - count + 1);
441 return hash & (nBuckets - 1);
445template <
typename Node>
448template <
typename Node>
451 using Key =
typename Node::KeyType;
452 using T =
typename Node::ValueType;
464 return (std::numeric_limits<ptrdiff_t>::max)() /
sizeof(Span);
475 :
span(d
->spans + (bucket >> SpanConstants::SpanShift)),
484 return ((span - d->spans) << SpanConstants::SpanShift) | index;
486 iterator
toIterator(
const Data *d)
const noexcept {
return iterator{d, toBucketIndex(d)}; }
493 advance_impl(d,
nullptr);
497 return !span->hasNode(index);
501 return span->offset(index);
505 return span->atOffset(offset);
509 return &span->at(index);
513 return span->insert(index);
519 return lhs.span == rhs.span && lhs.index == rhs.index;
523 void advance_impl(
const Data *d, Span *whenAtEnd)
noexcept
527 if (Q_UNLIKELY(index == SpanConstants::NEntries)) {
530 if (
span - d
->spans == ptrdiff_t(d->numBuckets >> SpanConstants::SpanShift))
543 constexpr qptrdiff MaxSpanCount = (std::numeric_limits<qptrdiff>::max)() /
sizeof(Span);
544 constexpr size_t MaxBucketCount = MaxSpanCount << SpanConstants::SpanShift;
546 if (numBuckets > MaxBucketCount) {
551 size_t nSpans = numBuckets >> SpanConstants::SpanShift;
552 return R{
new Span[nSpans], nSpans };
557 numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
558 spans = allocateSpans(numBuckets).spans;
559 seed = QHashSeed::globalSeed();
564 template <
bool Resized>
568 for (size_t s = 0; s < nSpans; ++s) {
569 const Span &span = other
.spans[s];
570 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
571 if (!span.hasNode(index))
573 const Node &n = span.at(index);
574 auto it = Resized ? findBucket(n.key) :
Bucket {
spans + s, index };
575 Q_ASSERT(it.isUnused());
576 Node *newNode = it.insert();
577 new (newNode) Node(n);
584 auto r = allocateSpans(numBuckets);
586 reallocationHelper<
false>(other, r.nSpans);
590 numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
591 spans = allocateSpans(numBuckets).spans;
592 size_t otherNSpans = other.numBuckets >> SpanConstants::SpanShift;
593 reallocationHelper<
true>(other, otherNSpans);
608 return new Data(size);
625 return iterator{
this, other.bucket};
630 iterator it{
this, 0 };
636 constexpr iterator
end()
const noexcept
645 size_t newBucketCount = GrowthPolicy::bucketsForCapacity(sizeHint);
647 Span *oldSpans =
spans;
648 size_t oldBucketCount = numBuckets;
649 spans = allocateSpans(newBucketCount).spans;
650 numBuckets = newBucketCount;
651 size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
653 for (size_t s = 0; s < oldNSpans; ++s) {
654 Span &span = oldSpans[s];
655 for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
656 if (!span.hasNode(index))
658 Node &n = span.at(index);
659 auto it = findBucket(n.key);
660 Q_ASSERT(it.isUnused());
661 Node *newNode = it.insert();
662 new (newNode) Node(
std::move(n));
672 if (bucket == numBuckets)
679 return float(size)/numBuckets;
683 return size >= (numBuckets >> 1);
688 size_t hash = QHashPrivate::calculateHash(key, seed);
689 return findBucketWithHash(key, hash);
694 static_assert(std::is_same_v<std::remove_cv_t<Key>, K> ||
695 QHashHeterogeneousSearch<std::remove_cv_t<Key>, K>::value);
696 Q_ASSERT(numBuckets > 0);
697 Bucket bucket(
this, GrowthPolicy::bucketForHash(numBuckets, hash));
701 size_t offset = bucket.offset();
702 if (offset == SpanConstants::UnusedEntry) {
705 Node &n = bucket.nodeAtOffset(offset);
706 if (qHashEquals(n.key, key))
709 bucket.advanceWrapped(
this);
713 template <
typename K> Node *
findNode(
const K &key)
const noexcept
715 auto bucket = findBucket(key);
716 if (bucket.isUnused())
718 return bucket.node();
729 Bucket it(
static_cast<Span *>(
nullptr), 0);
730 size_t hash = QHashPrivate::calculateHash(key, seed);
731 if (numBuckets > 0) {
732 it = findBucketWithHash(key, hash);
734 return { it.toIterator(
this),
true };
738 it = findBucketWithHash(key, hash);
740 Q_ASSERT(it.span !=
nullptr);
741 Q_ASSERT(it.isUnused());
744 return { it.toIterator(
this),
false };
749 Q_ASSERT(bucket.span->hasNode(bucket.index));
750 bucket.span->erase(bucket.index);
756 next.advanceWrapped(
this);
757 size_t offset = next.offset();
758 if (offset == SpanConstants::UnusedEntry)
760 size_t hash = QHashPrivate::calculateHash(next.nodeAtOffset(offset).key, seed);
761 Bucket newBucket(
this, GrowthPolicy::bucketForHash(numBuckets, hash));
763 if (newBucket == next) {
766 }
else if (newBucket == bucket) {
768 if (next.span == bucket.span) {
769 bucket.span->moveLocal(next.index, bucket.index);
772 bucket.span->moveFromSpan(*next.span, next.index, bucket.index);
777 newBucket.advanceWrapped(
this);
788template <
typename Node>
795 size_t span()
const noexcept {
return bucket >> SpanConstants::SpanShift; }
796 size_t index()
const noexcept {
return bucket & SpanConstants::LocalBucketMask; }
797 inline bool isUnused()
const noexcept {
return !d->spans[span()].hasNode(index()); }
799 inline Node *
node()
const noexcept
802 return &d->spans[span()].at(index());
804 bool atEnd()
const noexcept {
return !
d; }
810 if (bucket == d->numBuckets) {
821 {
return d == other.d && bucket == other.bucket; }
823 {
return !(*
this == other); }
835template <
typename Key,
typename T>
840 friend class QSet<
Key>;
841 friend class QMultiHash<
Key,
T>;
847 using key_type = Key;
848 using mapped_type = T;
849 using value_type = T;
852 using reference = T &;
853 using const_reference =
const T &;
857 : d(
new Data(list.size()))
859 for (
typename std::initializer_list<
std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
870 static_assert(
std::is_nothrow_destructible_v<Key>,
"Types with throwing destructors are not supported in Qt containers.");
871 static_assert(
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
873 if (d && !d->ref.deref())
883 if (d && !d->ref.deref())
913 for (;
f !=
l; ++
f) {
915 using V =
decltype(
e);
926 static bool compareIterators(
const const_iterator &lhs,
const const_iterator &rhs)
928 return lhs.i.node()->valuesEqual(rhs.i.node());
931 template <
typename AKey = Key,
typename AT = T,
932 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> =
true>
937 if (lhs.size() != rhs.size())
942 if (i == lhs
.end() || !compareIterators(i, it))
948 QT_DECLARE_EQUALITY_OPERATORS_HELPER(
QHash,
QHash, ,
noexcept,
949 template <
typename AKey = Key,
typename AT = T,
950 QTypeTraits::compare_eq_result_container<QHash, AKey, AT> =
true>)
960 inline bool isEmpty()
const noexcept {
return !
d ||
d->
size == 0; }
1056 while (
i !=
end()) {
1083 template <
typename K>
1125 while (
i !=
end()) {
1174 friend class iterator;
1179 friend class iterator;
1180 friend class QHash<Key, T>;
1181 friend class QSet<
Key>;
1183 explicit inline const_iterator(piter it) : i(it) { }
1195 inline const Key &
key()
const noexcept {
return i.node()->key; }
1196 inline const T &
value()
const noexcept {
return i.node()->value; }
1197 inline const T &
operator*()
const noexcept {
return i.node()->value; }
1198 inline const T *
operator->()
const noexcept {
return &i.node()->value; }
1230 const Key &
operator*()
const noexcept {
return i.key(); }
1231 const Key *
operator->()
const noexcept {
return &i.key(); }
1244 inline iterator begin() {
if (!d)
return iterator(); detach();
return iterator(d->begin()); }
1294 iterator i = iterator{d->detachedIterator(it.i)};
1295 typename Data::Bucket bucket(i.i);
1298 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
1305 return equal_range_impl(*
this, key);
1309 return equal_range_impl(*
this, key);
1312 template <
typename Hash,
typename K>
static auto equal_range_impl(Hash &self,
const K &key)
1314 auto first = self.find(key);
1315 auto second = first;
1316 if (second !=
decltype(first){})
1318 return std::make_pair(first, second);
1321 template <
typename K> iterator findImpl(
const K &key)
1325 auto it = d->findBucket(key);
1326 size_t bucket = it.toBucketIndex(d);
1328 it =
typename Data::Bucket(d, bucket);
1331 return iterator(it.toIterator(d));
1333 template <
typename K>
const_iterator constFindImpl(
const K &key)
const noexcept
1337 auto it = d->findBucket(key);
1349 return findImpl(key);
1353 return constFindImpl(key);
1361 return emplace(key, value);
1366 if (d == hash.d || !hash.d)
1376 emplace(it.key(), it.value());
1379 template <
typename ...Args>
1383 return emplace(
std::move(copy),
std::forward<Args>(args)...);
1386 template <
typename ...Args>
1390 if (d->shouldGrow())
1391 return emplace_helper(
std::move(key), T(
std::forward<Args>(args)...));
1392 return emplace_helper(
std::move(key),
std::forward<Args>(args)...);
1395 const auto copy = *
this;
1397 return emplace_helper(
std::move(key),
std::forward<Args>(args)...);
1400 template <
typename... Args>
1403 return tryEmplace_impl(key,
std::forward<Args>(args)...);
1405 template <
typename... Args>
1408 return tryEmplace_impl(
std::move(key),
std::forward<Args>(args)...);
1413 return tryEmplace_impl(key, value);
1416 template <
typename... Args>
1419 return tryEmplace_impl(key,
std::forward<Args>(args)...);
1421 template <
typename... Args>
1424 return tryEmplace_impl(
std::move(key),
std::forward<Args>(args)...);
1426 template <
typename... Args>
1431 template <
typename... Args>
1438 template <
typename K,
typename... Args>
1445 size_t hash =
QHashPrivate::calculateHash(key, d->seed);
1446 typename Data::Bucket bucket = d->findBucketWithHash(key, hash);
1447 const bool shouldInsert = bucket.isUnused();
1451 if (!isDetached() || (shouldInsert && d->shouldGrow())) {
1452 detachGuard = *
this;
1453 const bool resized = shouldInsert && d->shouldGrow();
1454 const size_t bucketIndex = bucket.toBucketIndex(d);
1457 d = resized ? Data::detached(d, d->size + 1) : Data::detached(d);
1458 bucket = resized ? d->findBucketWithHash(key, hash) :
typename Data::Bucket(d, bucketIndex);
1461 Node *n = bucket.insert();
1462 using ConstructProxy =
typename QHashPrivate::HeterogenousConstructProxy<Key, K>;
1463 Node::createInPlace(n, ConstructProxy(
std::forward<K>(key)),
1464 std::forward<Args>(args)...);
1467 return {iterator(bucket.toIterator(d)), shouldInsert};
1470 template <
typename Value>
1473 return insertOrAssign_impl(key,
std::forward<Value>(value));
1475 template <
typename Value>
1478 return insertOrAssign_impl(
std::move(key),
std::forward<Value>(value));
1480 template <
typename Value>
1483 return insertOrAssign_impl(key,
std::forward<Value>(value));
1485 template <
typename Value>
1488 return insertOrAssign_impl(
std::move(key),
std::forward<Value>(value));
1490 template <
typename Value>
1495 template <
typename Value>
1502 template <
typename K,
typename Value>
1505 auto r = tryEmplace(
std::forward<K>(key),
std::forward<Value>(value));
1507 *r.iterator =
std::forward<Value>(value);
1513 float load_factor()
const noexcept {
return d ? d->loadFactor() : 0; }
1519 inline bool empty()
const noexcept {
return isEmpty(); }
1522 template <
typename ...Args>
1523 iterator emplace_helper(Key &&key, Args &&... args)
1525 auto result = d->findOrInsert(key);
1526 if (!result.initialized)
1527 Node::createInPlace(result.it.node(),
std::move(key),
std::forward<Args>(args)...);
1529 result.it.node()->emplaceValue(
std::forward<Args>(args)...);
1530 return iterator(result.it);
1533 template <
typename K>
1536 template <
typename K>
1540 template <
typename K, if_heterogeneously_searchable<K> =
true>
1543 return removeImpl(key);
1545 template <
typename K, if_heterogeneously_searchable<K> =
true>
1548 return takeImpl(key);
1550 template <
typename K, if_heterogeneously_searchable<K> =
true>
1553 return d ? d->findNode(key) !=
nullptr :
false;
1555 template <
typename K, if_heterogeneously_searchable<K> =
true>
1558 return contains(key) ? 1 : 0;
1560 template <
typename K, if_heterogeneously_searchable<K> =
true>
1563 if (
auto *v = valueImpl(key))
1568 template <
typename K, if_heterogeneously_searchable<K> =
true>
1569 T
value(
const K &key,
const T &defaultValue)
const noexcept
1571 if (
auto *v = valueImpl(key))
1574 return defaultValue;
1576 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1579 return *tryEmplace(key).iterator;
1581 template <
typename K, if_heterogeneously_searchable<K> =
true>
1586 template <
typename K, if_heterogeneously_searchable<K> =
true>
1590 return equal_range_impl(*
this, key);
1592 template <
typename K, if_heterogeneously_searchable<K> =
true>
1596 return equal_range_impl(*
this, key);
1598 template <
typename K, if_heterogeneously_searchable<K> =
true>
1601 return findImpl(key);
1603 template <
typename K, if_heterogeneously_searchable<K> =
true>
1606 return constFindImpl(key);
1608 template <
typename K, if_heterogeneously_searchable<K> =
true>
1613 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1616 return tryEmplace_impl(
std::forward<K>(key),
std::forward<Args>(args)...);
1618 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1621 return tryEmplace_impl(
std::forward<K>(key), value);
1623 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1626 return tryEmplace_impl(
std::forward<K>(key),
std::forward<Args>(args)...);
1628 template <
typename K,
typename... Args, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1633 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1636 return insertOrAssign_impl(
std::forward<K>(key),
std::forward<Value>(value));
1638 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1641 return insertOrAssign_impl(
std::forward<K>(key),
std::forward<Value>(value));
1643 template <
typename K,
typename Value, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
1651template <
typename Key,
typename T>
1654 using Node = QHashPrivate::MultiNode<Key, T>;
1655 using Data = QHashPrivate::Data<Node>;
1656 using Chain = QHashPrivate::MultiNodeChain<T>;
1659 qsizetype m_size = 0;
1662 using key_type = Key;
1663 using mapped_type = T;
1664 using value_type = T;
1665 using size_type = qsizetype;
1666 using difference_type = qsizetype;
1667 using reference = T &;
1668 using const_reference =
const T &;
1670 QMultiHash()
noexcept =
default;
1671 inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
1672 : d(
new Data(list.size()))
1674 for (
typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
1675 insert(it->first, it->second);
1678 template <
typename InputIterator>
1679 QMultiHash(InputIterator f, InputIterator l);
1681 template <
typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> =
true>
1682 QMultiHash(InputIterator f, InputIterator l)
1684 QtPrivate::reserveIfForwardIterator(
this, f, l);
1686 insert(f.key(), f.value());
1689 template <
typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> =
true>
1690 QMultiHash(InputIterator f, InputIterator l)
1692 QtPrivate::reserveIfForwardIterator(
this, f, l);
1693 for (; f != l; ++f) {
1695 using V =
decltype(e);
1696 insert(std::forward<V>(e).first, std::forward<V>(e).second);
1700 QMultiHash(
const QMultiHash &other)
noexcept
1701 : d(other.d), m_size(other.m_size)
1708 static_assert(std::is_nothrow_destructible_v<Key>,
"Types with throwing destructors are not supported in Qt containers.");
1709 static_assert(std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
1711 if (d && !d->ref.deref())
1715 QMultiHash &operator=(
const QMultiHash &other)
noexcept(std::is_nothrow_destructible<Node>::value)
1721 if (d && !d->ref.deref())
1724 m_size = other.m_size;
1728 QMultiHash(QMultiHash &&other)
noexcept
1729 : d(std::exchange(other.d,
nullptr)),
1730 m_size(std::exchange(other.m_size, 0))
1733 QMultiHash &operator=(QMultiHash &&other)
noexcept(std::is_nothrow_destructible<Node>::value)
1735 QMultiHash moved(std::move(other));
1740 explicit QMultiHash(
const QHash<Key, T> &other)
1741 : QMultiHash(other.begin(), other.end())
1744 explicit QMultiHash(QHash<Key, T> &&other)
1746 unite(std::move(other));
1749 void swap(QMultiHash &other)
noexcept
1751 qt_ptr_swap(d, other.d);
1752 std::swap(m_size, other.m_size);
1757 template <
typename AKey = Key,
typename AT = T,
1758 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> =
true>
1759 friend bool comparesEqual(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept
1763 if (lhs.m_size != rhs.m_size)
1765 if (lhs.m_size == 0)
1770 if (lhs.d->size != rhs.d->size)
1772 for (
auto it = rhs.d->begin(); it != rhs.d->end(); ++it) {
1773 auto *n = lhs.d->findNode(it.node()->key);
1776 Chain *e = it.node()->value;
1778 Chain *oe = n->value;
1780 if (oe->value == e->value)
1792 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QMultiHash, QMultiHash, ,
noexcept,
1793 template <
typename AKey = Key,
typename AT = T,
1794 QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> =
true>)
1797 friend bool operator==(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept;
1798 friend bool operator!=(
const QMultiHash &lhs,
const QMultiHash &rhs)
noexcept;
1801 inline qsizetype size()
const noexcept {
return m_size; }
1804 inline bool isEmpty()
const noexcept {
return !m_size; }
1806 inline qsizetype capacity()
const noexcept {
return d ? qsizetype(d->numBuckets >> 1) : 0; }
1807 void reserve(qsizetype size)
1810 if (size && (
this->capacity() >= size))
1815 d = Data::detached(d, size_t(size));
1817 inline void squeeze() { reserve(0); }
1819 inline void detach() {
if (!d || d->ref.isShared()) d = Data::detached(d); }
1820 inline bool isDetached()
const noexcept {
return d && !d->ref.isShared(); }
1821 bool isSharedWith(
const QMultiHash &other)
const noexcept {
return d == other.d; }
1823 void clear()
noexcept(std::is_nothrow_destructible<Node>::value)
1825 if (d && !d->ref.deref())
1831 qsizetype remove(
const Key &key)
1833 return removeImpl(key);
1836 template <
typename K> qsizetype removeImpl(
const K &key)
1840 auto it = d->findBucket(key);
1841 size_t bucket = it.toBucketIndex(d);
1843 it =
typename Data::Bucket(d, bucket);
1847 qsizetype n = Node::freeChain(it.node());
1849 Q_ASSERT(m_size >= 0);
1855 template <
typename Predicate>
1856 qsizetype removeIf(Predicate pred)
1858 return QtPrivate::associative_erase_if(*
this, pred);
1861 T take(
const Key &key)
1863 return takeImpl(key);
1866 template <
typename K> T takeImpl(
const K &key)
1870 auto it = d->findBucket(key);
1871 size_t bucket = it.toBucketIndex(d);
1873 it =
typename Data::Bucket(d, bucket);
1877 Chain *e = it.node()->value;
1879 T t = std::move(e->value);
1881 it.node()->value = e->next;
1888 Q_ASSERT(m_size >= 0);
1893 bool contains(
const Key &key)
const noexcept
1897 return d->findNode(key) !=
nullptr;
1901 const Key *keyImpl(
const T &value)
const noexcept
1904 auto i = d->begin();
1905 while (i != d->end()) {
1906 Chain *e = i.node()->value;
1907 if (e->contains(value))
1908 return &i.node()->key;
1916 Key key(
const T &value)
const noexcept
1918 if (
auto *k = keyImpl(value))
1923 Key key(
const T &value,
const Key &defaultKey)
const noexcept
1925 if (
auto *k = keyImpl(value))
1932 template <
typename K>
1933 T *valueImpl(
const K &key)
const noexcept
1936 Node *n = d->findNode(key);
1939 return &n->value->value;
1945 T value(
const Key &key)
const noexcept
1947 if (
auto *v = valueImpl(key))
1952 T value(
const Key &key,
const T &defaultValue)
const noexcept
1954 if (
auto *v = valueImpl(key))
1957 return defaultValue;
1960 T &operator[](
const Key &key)
1962 return operatorIndexImpl(key);
1965 template <
typename K> T &operatorIndexImpl(
const K &key)
1967 const auto copy = isDetached() ? QMultiHash() : *
this;
1969 auto result = d->findOrInsert(key);
1970 Q_ASSERT(!result.it.atEnd());
1971 if (!result.initialized) {
1972 Node::createInPlace(result.it.node(), Key(key), T());
1975 return result.it.node()->value->value;
1979 const T operator[](
const Key &key)
const noexcept
1984 QList<Key> uniqueKeys()
const
1988 auto i = d->begin();
1989 while (i != d->end()) {
1990 res.append(i.node()->key);
1997 QList<Key> keys()
const {
return QList<Key>(keyBegin(), keyEnd()); }
1998 QList<Key> keys(
const T &value)
const
2001 const_iterator i = begin();
2002 while (i != end()) {
2003 if (i.value() == value)
2004 res.append(i.key());
2010 QList<T> values()
const {
return QList<T>(begin(), end()); }
2011 QList<T> values(
const Key &key)
const
2013 return valuesImpl(key);
2016 template <
typename K> QList<T> valuesImpl(
const K &key)
const
2020 Node *n = d->findNode(key);
2022 Chain *e = n->value;
2024 values.append(e->value);
2033 class const_iterator;
2037 using piter =
typename QHashPrivate::iterator<Node>;
2038 friend class const_iterator;
2039 friend class QMultiHash<Key, T>;
2041 Chain **e =
nullptr;
2042 explicit inline iterator(piter it, Chain **entry =
nullptr)
noexcept : i(it), e(entry)
2044 if (!it.atEnd() && !e) {
2045 e = &it.node()->value;
2051 typedef std::forward_iterator_tag iterator_category;
2052 typedef qptrdiff difference_type;
2053 typedef T value_type;
2055 typedef T &reference;
2057 constexpr iterator()
noexcept =
default;
2059 inline const Key &key()
const noexcept {
return i.node()->key; }
2060 inline T &value()
const noexcept {
return (*e)->value; }
2061 inline T &operator*()
const noexcept {
return (*e)->value; }
2062 inline T *operator->()
const noexcept {
return &(*e)->value; }
2063 inline bool operator==(
const iterator &o)
const noexcept {
return e == o.e; }
2064 inline bool operator!=(
const iterator &o)
const noexcept {
return e != o.e; }
2066 inline iterator &operator++()
noexcept {
2072 e = i.atEnd() ?
nullptr : &i.node()->value;
2076 inline iterator operator++(
int)
noexcept {
2082 inline bool operator==(
const const_iterator &o)
const noexcept {
return e == o.e; }
2083 inline bool operator!=(
const const_iterator &o)
const noexcept {
return e != o.e; }
2085 friend class iterator;
2087 class const_iterator
2089 using piter =
typename QHashPrivate::iterator<Node>;
2090 friend class iterator;
2091 friend class QMultiHash<Key, T>;
2093 Chain **e =
nullptr;
2094 explicit inline const_iterator(piter it, Chain **entry =
nullptr)
noexcept : i(it), e(entry)
2096 if (!it.atEnd() && !e) {
2097 e = &it.node()->value;
2103 typedef std::forward_iterator_tag iterator_category;
2104 typedef qptrdiff difference_type;
2105 typedef T value_type;
2106 typedef const T *pointer;
2107 typedef const T &reference;
2109 constexpr const_iterator()
noexcept =
default;
2110 inline const_iterator(
const iterator &o)
noexcept : i(o.i), e(o.e) { }
2112 inline const Key &key()
const noexcept {
return i.node()->key; }
2113 inline T &value()
const noexcept {
return (*e)->value; }
2114 inline T &operator*()
const noexcept {
return (*e)->value; }
2115 inline T *operator->()
const noexcept {
return &(*e)->value; }
2116 inline bool operator==(
const const_iterator &o)
const noexcept {
return e == o.e; }
2117 inline bool operator!=(
const const_iterator &o)
const noexcept {
return e != o.e; }
2119 inline const_iterator &operator++()
noexcept {
2125 e = i.atEnd() ?
nullptr : &i.node()->value;
2129 inline const_iterator operator++(
int)
noexcept
2131 const_iterator r = *
this;
2136 friend class const_iterator;
2143 typedef typename const_iterator::iterator_category iterator_category;
2144 typedef qptrdiff difference_type;
2145 typedef Key value_type;
2146 typedef const Key *pointer;
2147 typedef const Key &reference;
2149 key_iterator()
noexcept =
default;
2150 explicit key_iterator(const_iterator o)
noexcept : i(o) { }
2152 const Key &operator*()
const noexcept {
return i.key(); }
2153 const Key *operator->()
const noexcept {
return &i.key(); }
2154 bool operator==(key_iterator o)
const noexcept {
return i == o.i; }
2155 bool operator!=(key_iterator o)
const noexcept {
return i != o.i; }
2157 inline key_iterator &operator++()
noexcept { ++i;
return *
this; }
2158 inline key_iterator operator++(
int)
noexcept {
return key_iterator(i++);}
2159 const_iterator base()
const noexcept {
return i; }
2162 typedef QKeyValueIterator<
const Key&,
const T&, const_iterator> const_key_value_iterator;
2163 typedef QKeyValueIterator<
const Key&, T&, iterator> key_value_iterator;
2166 inline iterator begin() {
if (!d)
return iterator(); detach();
return iterator(d->begin()); }
2167 inline const_iterator begin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2168 inline const_iterator cbegin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2169 inline const_iterator constBegin()
const noexcept {
return d ? const_iterator(d->begin()): const_iterator(); }
2170 inline iterator end()
noexcept {
return iterator(); }
2171 inline const_iterator end()
const noexcept {
return const_iterator(); }
2172 inline const_iterator cend()
const noexcept {
return const_iterator(); }
2173 inline const_iterator constEnd()
const noexcept {
return const_iterator(); }
2174 inline key_iterator keyBegin()
const noexcept {
return key_iterator(begin()); }
2175 inline key_iterator keyEnd()
const noexcept {
return key_iterator(end()); }
2176 inline key_value_iterator keyValueBegin()
noexcept {
return key_value_iterator(begin()); }
2177 inline key_value_iterator keyValueEnd()
noexcept {
return key_value_iterator(end()); }
2178 inline const_key_value_iterator keyValueBegin()
const noexcept {
return const_key_value_iterator(begin()); }
2179 inline const_key_value_iterator constKeyValueBegin()
const noexcept {
return const_key_value_iterator(begin()); }
2180 inline const_key_value_iterator keyValueEnd()
const noexcept {
return const_key_value_iterator(end()); }
2181 inline const_key_value_iterator constKeyValueEnd()
const noexcept {
return const_key_value_iterator(end()); }
2182 auto asKeyValueRange() & {
return QtPrivate::QKeyValueRange(*
this); }
2183 auto asKeyValueRange()
const & {
return QtPrivate::QKeyValueRange(*
this); }
2184 auto asKeyValueRange() && {
return QtPrivate::QKeyValueRange(std::move(*
this)); }
2185 auto asKeyValueRange()
const && {
return QtPrivate::QKeyValueRange(std::move(*
this)); }
2187 iterator detach(const_iterator it)
2191 if (d->ref.isShared()) {
2194 Chain *entry = i.node()->value;
2195 while (entry != *it.e) {
2197 entry = entry->next;
2202 i = d->detachedIterator(i);
2203 e = &i.node()->value;
2210 return iterator(i, e);
2213 iterator erase(const_iterator it)
2216 iterator iter = detach(it);
2219 Chain *next = e->next;
2223 if (i.e == &i.i.node()->value) {
2225 typename Data::Bucket bucket(i.i);
2227 if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
2228 i = iterator(++iter.i);
2230 i = iterator(bucket.toIterator(d));
2232 i = iterator(++iter.i);
2236 Q_ASSERT(m_size >= 0);
2241 typedef iterator Iterator;
2242 typedef const_iterator ConstIterator;
2243 inline qsizetype count()
const noexcept {
return size(); }
2246 template <
typename K> iterator findImpl(
const K &key)
2250 auto it = d->findBucket(key);
2251 size_t bucket = it.toBucketIndex(d);
2253 it =
typename Data::Bucket(d, bucket);
2257 return iterator(it.toIterator(d));
2259 template <
typename K> const_iterator constFindImpl(
const K &key)
const noexcept
2263 auto it = d->findBucket(key);
2266 return const_iterator(it.toIterator(d));
2269 iterator find(
const Key &key)
2271 return findImpl(key);
2273 const_iterator constFind(
const Key &key)
const noexcept
2275 return constFindImpl(key);
2277 const_iterator find(
const Key &key)
const noexcept
2279 return constFindImpl(key);
2282 iterator insert(
const Key &key,
const T &value)
2284 return emplace(key, value);
2287 template <
typename ...Args>
2288 iterator emplace(
const Key &key, Args &&... args)
2290 return emplace(Key(key), std::forward<Args>(args)...);
2293 template <
typename ...Args>
2294 iterator emplace(Key &&key, Args &&... args)
2297 if (d->shouldGrow())
2298 return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
2299 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2302 const auto copy = *
this;
2304 return emplace_helper(std::move(key), std::forward<Args>(args)...);
2308 float load_factor()
const noexcept {
return d ? d->loadFactor() : 0; }
2309 static float max_load_factor()
noexcept {
return 0.5; }
2310 size_t bucket_count()
const noexcept {
return d ? d->numBuckets : 0; }
2311 static size_t max_bucket_count()
noexcept {
return Data::maxNumBuckets(); }
2314 inline bool empty()
const noexcept {
return isEmpty(); }
2316 inline iterator replace(
const Key &key,
const T &value)
2318 return emplaceReplace(key, value);
2321 template <
typename ...Args>
2322 iterator emplaceReplace(
const Key &key, Args &&... args)
2324 return emplaceReplace(Key(key), std::forward<Args>(args)...);
2327 template <
typename ...Args>
2328 iterator emplaceReplace(Key &&key, Args &&... args)
2331 if (d->shouldGrow())
2332 return emplaceReplace_helper(std::move(key), T(std::forward<Args>(args)...));
2333 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2336 const auto copy = *
this;
2338 return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
2341 inline QMultiHash &operator+=(
const QMultiHash &other)
2342 {
this->unite(other);
return *
this; }
2343 inline QMultiHash operator+(
const QMultiHash &other)
const
2344 { QMultiHash result = *
this; result += other;
return result; }
2346 bool contains(
const Key &key,
const T &value)
const noexcept
2348 return containsImpl(key, value);
2351 template <
typename K>
bool containsImpl(
const K &key,
const T &value)
const noexcept
2355 auto n = d->findNode(key);
2358 return n->value->contains(value);
2362 qsizetype remove(
const Key &key,
const T &value)
2364 return removeImpl(key, value);
2367 template <
typename K> qsizetype removeImpl(
const K &key,
const T &value)
2371 auto it = d->findBucket(key);
2372 size_t bucket = it.toBucketIndex(d);
2374 it =
typename Data::Bucket(d, bucket);
2379 Chain **e = &it.node()->value;
2382 if (entry->value == value) {
2390 if (!it.node()->value)
2393 Q_ASSERT(m_size >= 0);
2398 qsizetype count(
const Key &key)
const noexcept
2400 return countImpl(key);
2403 template <
typename K> qsizetype countImpl(
const K &key)
const noexcept
2407 auto it = d->findBucket(key);
2411 Chain *e = it.node()->value;
2421 qsizetype count(
const Key &key,
const T &value)
const noexcept
2423 return countImpl(key, value);
2426 template <
typename K> qsizetype countImpl(
const K &key,
const T &value)
const noexcept
2430 auto it = d->findBucket(key);
2434 Chain *e = it.node()->value;
2436 if (e->value == value)
2444 template <
typename K> iterator findImpl(
const K &key,
const T &value)
2448 const auto copy = isDetached() ? QMultiHash() : *
this;
2450 auto it = constFind(key, value);
2451 return iterator(it.i, it.e);
2453 template <
typename K> const_iterator constFindImpl(
const K &key,
const T &value)
const noexcept
2455 const_iterator i(constFind(key));
2456 const_iterator end(constEnd());
2457 while (i != end && i.key() == key) {
2458 if (i.value() == value)
2466 iterator find(
const Key &key,
const T &value)
2468 return findImpl(key, value);
2471 const_iterator constFind(
const Key &key,
const T &value)
const noexcept
2473 return constFindImpl(key, value);
2475 const_iterator find(
const Key &key,
const T &value)
const noexcept
2477 return constFind(key, value);
2480 QMultiHash &unite(
const QMultiHash &other)
2484 }
else if (other.isEmpty()) {
2487 QMultiHash copy(other);
2489 for (
auto cit = copy.cbegin(); cit != copy.cend(); ++cit)
2490 insert(cit.key(), *cit);
2495 QMultiHash &unite(
const QHash<Key, T> &other)
2497 for (
auto cit = other.cbegin(); cit != other.cend(); ++cit)
2498 insert(cit.key(), *cit);
2502 QMultiHash &unite(QHash<Key, T> &&other)
2504 if (!other.isDetached()) {
2508 auto it = other.d->begin();
2509 for (
const auto end = other.d->end(); it != end; ++it)
2510 emplace(std::move(it.node()->key), std::move(it.node()->takeValue()));
2515 std::pair<iterator, iterator> equal_range(
const Key &key)
2517 return equal_range_impl(key);
2520 template <
typename K> std::pair<iterator, iterator> equal_range_impl(
const K &key)
2522 const auto copy = isDetached() ? QMultiHash() : *
this;
2524 auto pair = std::as_const(*
this).equal_range(key);
2525 return {iterator(pair.first.i), iterator(pair.second.i)};
2529 std::pair<const_iterator, const_iterator> equal_range(
const Key &key)
const noexcept
2531 return equal_range_impl(key);
2534 template <
typename K> std::pair<const_iterator, const_iterator> equal_range_impl(
const K &key)
const noexcept
2537 return {end(), end()};
2539 auto bucket = d->findBucket(key);
2540 if (bucket.isUnused())
2541 return {end(), end()};
2542 auto it = bucket.toIterator(d);
2545 return {const_iterator(it), const_iterator(end)};
2548 void detach_helper()
2554 Data *dd =
new Data(*d);
2555 if (!d->ref.deref())
2560 template<
typename... Args>
2561 iterator emplace_helper(Key &&key, Args &&...args)
2563 auto result = d->findOrInsert(key);
2564 if (!result.initialized)
2565 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2567 result.it.node()->insertMulti(std::forward<Args>(args)...);
2569 return iterator(result.it);
2572 template<
typename... Args>
2573 iterator emplaceReplace_helper(Key &&key, Args &&...args)
2575 auto result = d->findOrInsert(key);
2576 if (!result.initialized) {
2577 Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
2580 result.it.node()->emplaceValue(std::forward<Args>(args)...);
2582 return iterator(result.it);
2585 template <
typename K>
2586 using if_heterogeneously_searchable = QHashPrivate::if_heterogeneously_searchable_with<Key, K>;
2588 template <
typename K>
2589 using if_key_constructible_from = std::enable_if_t<std::is_constructible_v<Key, K>,
bool>;
2592 template <
typename K, if_heterogeneously_searchable<K> =
true>
2593 qsizetype remove(
const K &key)
2595 return removeImpl(key);
2597 template <
typename K, if_heterogeneously_searchable<K> =
true>
2598 T take(
const K &key)
2600 return takeImpl(key);
2602 template <
typename K, if_heterogeneously_searchable<K> =
true>
2603 bool contains(
const K &key)
const noexcept
2607 return d->findNode(key) !=
nullptr;
2609 template <
typename K, if_heterogeneously_searchable<K> =
true>
2610 T value(
const K &key)
const noexcept
2612 if (
auto *v = valueImpl(key))
2617 template <
typename K, if_heterogeneously_searchable<K> =
true>
2618 T value(
const K &key,
const T &defaultValue)
const noexcept
2620 if (
auto *v = valueImpl(key))
2623 return defaultValue;
2625 template <
typename K, if_heterogeneously_searchable<K> =
true, if_key_constructible_from<K> =
true>
2626 T &operator[](
const K &key)
2628 return operatorIndexImpl(key);
2630 template <
typename K, if_heterogeneously_searchable<K> =
true>
2631 const T operator[](
const K &key)
const noexcept
2635 template <
typename K, if_heterogeneously_searchable<K> =
true>
2636 QList<T> values(
const K &key)
2638 return valuesImpl(key);
2640 template <
typename K, if_heterogeneously_searchable<K> =
true>
2641 iterator find(
const K &key)
2643 return findImpl(key);
2645 template <
typename K, if_heterogeneously_searchable<K> =
true>
2646 const_iterator constFind(
const K &key)
const noexcept
2648 return constFindImpl(key);
2650 template <
typename K, if_heterogeneously_searchable<K> =
true>
2651 const_iterator find(
const K &key)
const noexcept
2653 return constFindImpl(key);
2655 template <
typename K, if_heterogeneously_searchable<K> =
true>
2656 bool contains(
const K &key,
const T &value)
const noexcept
2658 return containsImpl(key, value);
2660 template <
typename K, if_heterogeneously_searchable<K> =
true>
2661 qsizetype remove(
const K &key,
const T &value)
2663 return removeImpl(key, value);
2665 template <
typename K, if_heterogeneously_searchable<K> =
true>
2666 qsizetype count(
const K &key)
const noexcept
2668 return countImpl(key);
2670 template <
typename K, if_heterogeneously_searchable<K> =
true>
2671 qsizetype count(
const K &key,
const T &value)
const noexcept
2673 return countImpl(key, value);
2675 template <
typename K, if_heterogeneously_searchable<K> =
true>
2676 iterator find(
const K &key,
const T &value)
2678 return findImpl(key, value);
2680 template <
typename K, if_heterogeneously_searchable<K> =
true>
2681 const_iterator constFind(
const K &key,
const T &value)
const noexcept
2683 return constFindImpl(key, value);
2685 template <
typename K, if_heterogeneously_searchable<K> =
true>
2686 const_iterator find(
const K &key,
const T &value)
const noexcept
2688 return constFind(key, value);
2690 template <
typename K, if_heterogeneously_searchable<K> =
true>
2691 std::pair<iterator, iterator>
2692 equal_range(
const K &key)
2694 return equal_range_impl(key);
2696 template <
typename K, if_heterogeneously_searchable<K> =
true>
2697 std::pair<const_iterator, const_iterator>
2698 equal_range(
const K &key)
const noexcept
2700 return equal_range_impl(key);
2704Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2705Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
2706Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2707Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
2709template <
class Key,
class T>
2710size_t qHash(
const QHash<Key, T> &key, size_t seed = 0)
2711 noexcept(
noexcept(qHash(std::declval<Key&>())) &&
noexcept(qHash(std::declval<T&>())))
2714 for (
auto it = key.begin(), end = key.end(); it != end; ++it) {
2715 QtPrivate::QHashCombine combine;
2716 size_t h = combine(seed, it.key());
2718 hash += combine(h, it.value());
2723template <
class Key,
class T>
2728 for (
auto it = key.begin(), end = key.end(); it != end; ++it) {
2729 QtPrivate::QHashCombine combine;
2730 size_t h = combine(seed, it.key());
2732 hash += combine(h, it.value());
2737template <
typename Key,
typename T,
typename Predicate>
2740 return QtPrivate::associative_erase_if(hash, pred);
2743template <
typename Key,
typename T,
typename Predicate>
2746 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)
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
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 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...
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
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.
TryEmplaceResult tryEmplace(Key &&key, Args &&...args)
key_value_iterator try_emplace(const_iterator, const Key &key, Args &&...args)
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 isRelocatable()
constexpr bool HasStdHashSpecializationWithoutSeed
size_t calculateHash(const T &t, size_t seed=0)
constexpr bool HasQHashOverload
constexpr bool HasQHashOverload< T, std::enable_if_t< std::is_convertible_v< decltype(qHash(std::declval< const T & >(), std::declval< size_t >())), size_t > > >
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 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 comparesEqual(const QDir &lhs, const QDir &rhs)
static bool treatAsAbsolute(const QString &path)
bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
Q_AUTOTEST_EXPORT bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags)
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
size_t nextBucket(size_t bucket) const noexcept
InsertionResult findOrInsert(const K &key) noexcept
Node * findNode(const K &key) const noexcept
static Data * detached(Data *d)
iterator detachedIterator(iterator other) const noexcept
constexpr iterator end() const noexcept
bool shouldGrow() const noexcept
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 >)
void emplaceValue(Args &&... args)
static void createInPlace(Node *n, const Key &k, Args &&...)
void emplaceValue(Args &&...)
bool valuesEqual(const Node *) const
static void createInPlace(Node *n, Key &&k, Args &&...)
void emplaceValue(Args &&... args)
bool valuesEqual(const Node *other) const
static void createInPlace(Node *n, const Key &k, Args &&... args)
static void createInPlace(Node *n, Key &&k, Args &&... args)
T && takeValue() noexcept(std::is_nothrow_move_assignable_v< T >)
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
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