QHash: optimize equality operator
- First compare the d-pointer before dipping into *d - Keep a running count as we calculate thisEqualRange, as std::distance() on QHash::iterator is very expensive. - Skip the pointless first comparison of the unadvanced iterator's key() with itself (found by Mårten Nordheim) Also rename (it, thisEqualRangeEnd) → (thisEqualRangeStart, it), to keep advancing `it`, which is more natural than advancing an `end` and later resetting it = end. Change-Id: I2c27c071b9ee23425a763328402dad9efee4cbd0 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
2d2e16d3ef
commit
0fec7417ca
@ -957,23 +957,27 @@ Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::Node **QHash<Key, T>::findNode(cons
|
|||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash &other) const
|
Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash &other) const
|
||||||
{
|
{
|
||||||
if (size() != other.size())
|
|
||||||
return false;
|
|
||||||
if (d == other.d)
|
if (d == other.d)
|
||||||
return true;
|
return true;
|
||||||
|
if (size() != other.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
const_iterator it = begin();
|
const_iterator it = begin();
|
||||||
|
|
||||||
while (it != end()) {
|
while (it != end()) {
|
||||||
// Build two equal ranges for i.key(); one for *this and one for other.
|
// Build two equal ranges for i.key(); one for *this and one for other.
|
||||||
// For *this we can avoid a lookup via equal_range, as we know the beginning of the range.
|
// For *this we can avoid a lookup via equal_range, as we know the beginning of the range.
|
||||||
auto thisEqualRangeEnd = it;
|
auto thisEqualRangeStart = it;
|
||||||
while (thisEqualRangeEnd != end() && it.key() == thisEqualRangeEnd.key())
|
const Key &thisEqualRangeKey = it.key();
|
||||||
++thisEqualRangeEnd;
|
size_type n = 0;
|
||||||
|
do {
|
||||||
|
++it;
|
||||||
|
++n;
|
||||||
|
} while (it != end() && it.key() == thisEqualRangeKey);
|
||||||
|
|
||||||
const auto otherEqualRange = other.equal_range(it.key());
|
const auto otherEqualRange = other.equal_range(thisEqualRangeKey);
|
||||||
|
|
||||||
if (std::distance(it, thisEqualRangeEnd) != std::distance(otherEqualRange.first, otherEqualRange.second))
|
if (n != std::distance(otherEqualRange.first, otherEqualRange.second))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Keys in the ranges are equal by construction; this checks only the values.
|
// Keys in the ranges are equal by construction; this checks only the values.
|
||||||
@ -986,15 +990,13 @@ Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash &other) const
|
|||||||
// is supported since MSVC 2015).
|
// is supported since MSVC 2015).
|
||||||
//
|
//
|
||||||
// ### Qt 6: if C++14 library support is a mandated minimum, remove the ifdef for MSVC.
|
// ### Qt 6: if C++14 library support is a mandated minimum, remove the ifdef for MSVC.
|
||||||
if (!std::is_permutation(it, thisEqualRangeEnd, otherEqualRange.first
|
if (!std::is_permutation(thisEqualRangeStart, it, otherEqualRange.first
|
||||||
#ifdef Q_CC_MSVC
|
#ifdef Q_CC_MSVC
|
||||||
, otherEqualRange.second
|
, otherEqualRange.second
|
||||||
#endif
|
#endif
|
||||||
)) {
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
it = thisEqualRangeEnd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user