From 30bf163355b5a955eb66b968059666c506033e77 Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Fri, 5 Apr 2024 17:07:05 +0200 Subject: [PATCH] QRect(F): use comparison helper macros Also explicitly add QRectF vs QRect comparison. Previously such comparison was implicitly converting QRect to QRectF, and doing the fuzzy comparison. The new operators are directly calling operator==(QPointF, QPoint), which also does the fuzzy comparison, so the old behavior is preserved. As a drive-by: move the operators into the private section. Task-number: QTBUG-120308 Change-Id: I9b96ed4266e6a6c02a52c8cfff6ec1b2d036a7ca Reviewed-by: Tatiana Borisova --- src/corelib/tools/qrect.cpp | 28 +++++--- src/corelib/tools/qrect.h | 21 +++--- tests/auto/corelib/tools/qrect/CMakeLists.txt | 2 + tests/auto/corelib/tools/qrect/tst_qrect.cpp | 67 +++++++++++++++++++ 4 files changed, 99 insertions(+), 19 deletions(-) diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp index 6d345ce5432..c0e5127c6ec 100644 --- a/src/corelib/tools/qrect.cpp +++ b/src/corelib/tools/qrect.cpp @@ -15,6 +15,10 @@ QT_BEGIN_NAMESPACE \ingroup painting \reentrant + \compares equality + \compareswith equality QRectF + \endcompareswith + \brief The QRect class defines a rectangle in the plane using integer precision. @@ -1105,18 +1109,18 @@ bool QRect::intersects(const QRect &r) const noexcept } /*! - \fn bool QRect::operator==(const QRect &r1, const QRect &r2) + \fn bool QRect::operator==(const QRect &lhs, const QRect &rhs) - Returns \c true if the rectangles \a r1 and \a r2 are equal, + Returns \c true if the rectangles \a lhs and \a rhs are equal, otherwise returns \c false. */ /*! - \fn bool QRect::operator!=(const QRect &r1, const QRect &r2) + \fn bool QRect::operator!=(const QRect &lhs, const QRect &rhs) - Returns \c true if the rectangles \a r1 and \a r2 are different, otherwise - returns \c false. + Returns \c true if the rectangles \a lhs and \a rhs are different, + otherwise returns \c false. */ /*! @@ -1279,6 +1283,10 @@ QDebug operator<<(QDebug dbg, const QRect &r) \ingroup painting \reentrant + \compares equality + \compareswith equality QRect + \endcompareswith + \brief The QRectF class defines a finite rectangle in the plane using floating point precision. @@ -2346,10 +2354,10 @@ QRect QRectF::toAlignedRect() const noexcept */ /*! - \fn bool QRectF::operator==(const QRectF &r1, const QRectF &r2) + \fn bool QRectF::operator==(const QRectF &lhs, const QRectF &rhs) - Returns \c true if the rectangles \a r1 and \a r2 are \b approximately equal, - otherwise returns \c false. + Returns \c true if the rectangles \a lhs and \a rhs are \b approximately + equal, otherwise returns \c false. \warning This function does not check for strict equality; instead, it uses a fuzzy comparison to compare the rectangles' coordinates. @@ -2359,9 +2367,9 @@ QRect QRectF::toAlignedRect() const noexcept /*! - \fn bool QRectF::operator!=(const QRectF &r1, const QRectF &r2) + \fn bool QRectF::operator!=(const QRectF &lhs, const QRectF &rhs) - Returns \c true if the rectangles \a r1 and \a r2 are sufficiently + Returns \c true if the rectangles \a lhs and \a rhs are sufficiently different, otherwise returns \c false. \warning This function does not check for strict inequality; instead, diff --git a/src/corelib/tools/qrect.h b/src/corelib/tools/qrect.h index e69a217f48a..db70535a18c 100644 --- a/src/corelib/tools/qrect.h +++ b/src/corelib/tools/qrect.h @@ -119,12 +119,13 @@ public: [[nodiscard]] static constexpr inline QRect span(const QPoint &p1, const QPoint &p2) noexcept; - friend constexpr inline bool operator==(const QRect &r1, const QRect &r2) noexcept +private: + friend constexpr bool comparesEqual(const QRect &r1, const QRect &r2) noexcept { return r1.x1==r2.x1 && r1.x2==r2.x2 && r1.y1==r2.y1 && r1.y2==r2.y2; } - friend constexpr inline bool operator!=(const QRect &r1, const QRect &r2) noexcept - { return r1.x1!=r2.x1 || r1.x2!=r2.x2 || r1.y1!=r2.y1 || r1.y2!=r2.y2; } + Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QRect) friend constexpr inline size_t qHash(const QRect &, size_t) noexcept; +public: #if defined(Q_OS_DARWIN) || defined(Q_QDOC) [[nodiscard]] CGRect toCGRect() const noexcept; #endif @@ -572,17 +573,19 @@ public: constexpr inline QRectF &operator+=(const QMarginsF &margins) noexcept; constexpr inline QRectF &operator-=(const QMarginsF &margins) noexcept; - friend constexpr inline bool operator==(const QRectF &r1, const QRectF &r2) noexcept +private: + friend constexpr bool comparesEqual(const QRectF &r1, const QRectF &r2) noexcept { return r1.topLeft() == r2.topLeft() && r1.size() == r2.size(); } - friend constexpr inline bool operator!=(const QRectF &r1, const QRectF &r2) noexcept - { - return r1.topLeft() != r2.topLeft() - || r1.size() != r2.size(); - } + Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QRectF) + friend constexpr bool comparesEqual(const QRectF &r1, const QRect &r2) noexcept + { return r1.topLeft() == r2.topLeft() && r1.size() == r2.size(); } + Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QRectF, QRect) + +public: [[nodiscard]] constexpr inline QRect toRect() const noexcept; [[nodiscard]] QRect toAlignedRect() const noexcept; diff --git a/tests/auto/corelib/tools/qrect/CMakeLists.txt b/tests/auto/corelib/tools/qrect/CMakeLists.txt index a02e1c33a54..c98c8363793 100644 --- a/tests/auto/corelib/tools/qrect/CMakeLists.txt +++ b/tests/auto/corelib/tools/qrect/CMakeLists.txt @@ -14,4 +14,6 @@ endif() qt_internal_add_test(tst_qrect SOURCES tst_qrect.cpp + LIBRARIES + Qt::TestPrivate ) diff --git a/tests/auto/corelib/tools/qrect/tst_qrect.cpp b/tests/auto/corelib/tools/qrect/tst_qrect.cpp index 0f3dd1a0efa..43b46d8d8e0 100644 --- a/tests/auto/corelib/tools/qrect/tst_qrect.cpp +++ b/tests/auto/corelib/tools/qrect/tst_qrect.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include class tst_QRect : public QObject @@ -33,6 +35,9 @@ public: static QPoint getQPointCase( QPointCases p ); private slots: + void comparisonCompiles(); + void comparison_data(); + void comparison(); void isNull_data(); void isNull(); void newIsEmpty_data(); @@ -160,6 +165,8 @@ private slots: #define LARGE 1000000000 static bool isLarge(int x) { return x > LARGE || x < -LARGE; } +static constexpr qreal qreal_min = std::numeric_limits::min(); + QRect tst_QRect::getQRectCase( QRectCases c ) { // Should return the best variety of possible QRects, if a @@ -242,6 +249,66 @@ QPoint tst_QRect::getQPointCase( QPointCases p ) } } +void tst_QRect::comparisonCompiles() +{ + QTestPrivate::testEqualityOperatorsCompile(); + QTestPrivate::testEqualityOperatorsCompile(); + QTestPrivate::testEqualityOperatorsCompile(); +} + +void tst_QRect::comparison_data() +{ + QTest::addColumn("lhsF"); + QTest::addColumn("rhsF"); + QTest::addColumn("result"); + QTest::addColumn("floatResult"); + QTest::addColumn("mixedResult"); + + QTest::newRow("Invalid_vs_Invalid") << getQRectCase(InvalidQRect).toRectF() + << getQRectCase(InvalidQRect).toRectF() + << true << true << true; + + QTest::newRow("Null_vs_Null") << getQRectCase(NullQRect).toRectF() + << getQRectCase(NullQRect).toRectF() + << true << true << true; + + QTest::newRow("Empty_vs_Empty") << getQRectCase(EmptyQRect).toRectF() + << getQRectCase(EmptyQRect).toRectF() + << true << true << true; + + QTest::newRow("NegativeSize_vs_NegativeSize") << getQRectCase(NegativeSizeQRect).toRectF() + << getQRectCase(NegativeSizeQRect).toRectF() + << true << true << true; + + QTest::newRow("Invalid_vs_Null") << getQRectCase(InvalidQRect).toRectF() + << getQRectCase(NullQRect).toRectF() + << false << false << false; + + QTest::newRow("NearlySimilar") << QRectF(QPointF(1.1, 9.9), QPointF(9.9, 1.1)) + << QRectF(QPointF(1., 10.), QPointF(10., 1.)) + << true << false << true; + + QTest::newRow("WithQREAL_MIN") << QRectF(QPointF(0., -10.), QPointF(-1., 0.)) + << QRectF(QPointF(-qreal_min, -10.), QPointF(-1., qreal_min)) + << true << true << true; +} + +void tst_QRect::comparison() +{ + QFETCH(const QRectF, lhsF); + QFETCH(const QRectF, rhsF); + QFETCH(const bool, result); + QFETCH(const bool, floatResult); + QFETCH(const bool, mixedResult); + + const QRect lhs = lhsF.toRect(); + const QRect rhs = rhsF.toRect(); + + QT_TEST_EQUALITY_OPS(lhs, rhs, result); + QT_TEST_EQUALITY_OPS(lhsF, rhsF, floatResult); + QT_TEST_EQUALITY_OPS(lhs, rhsF, mixedResult); +} + void tst_QRect::isNull_data() { QTest::addColumn("r");