From 0fec7417ca305e52cfd1382b3f9f8e4adcb597de Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 10 Jul 2019 19:40:06 +0200 Subject: [PATCH] QHash: optimize equality operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 Reviewed-by: Volker Hilsheimer --- src/corelib/tools/qhash.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index f4590c6672a..ee754a79d50 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -957,23 +957,27 @@ Q_OUTOFLINE_TEMPLATE typename QHash::Node **QHash::findNode(cons template Q_OUTOFLINE_TEMPLATE bool QHash::operator==(const QHash &other) const { - if (size() != other.size()) - return false; if (d == other.d) return true; + if (size() != other.size()) + return false; const_iterator it = begin(); while (it != end()) { // 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. - auto thisEqualRangeEnd = it; - while (thisEqualRangeEnd != end() && it.key() == thisEqualRangeEnd.key()) - ++thisEqualRangeEnd; + auto thisEqualRangeStart = it; + const Key &thisEqualRangeKey = it.key(); + 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; // Keys in the ranges are equal by construction; this checks only the values. @@ -986,15 +990,13 @@ Q_OUTOFLINE_TEMPLATE bool QHash::operator==(const QHash &other) const // is supported since MSVC 2015). // // ### 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 , otherEqualRange.second #endif )) { return false; } - - it = thisEqualRangeEnd; } return true;