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 <tatiana.borisova@qt.io>
This commit is contained in:
Ivan Solovev 2024-04-05 17:07:05 +02:00
parent 9bedf8a53c
commit 30bf163355
4 changed files with 99 additions and 19 deletions

View File

@ -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,

View File

@ -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;

View File

@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qrect
SOURCES
tst_qrect.cpp
LIBRARIES
Qt::TestPrivate
)

View File

@ -7,6 +7,8 @@
#include <limits.h>
#include <qdebug.h>
#include <private/qcomparisontesthelper_p.h>
#include <array>
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<qreal>::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<QRect>();
QTestPrivate::testEqualityOperatorsCompile<QRectF>();
QTestPrivate::testEqualityOperatorsCompile<QRectF, QRect>();
}
void tst_QRect::comparison_data()
{
QTest::addColumn<QRectF>("lhsF");
QTest::addColumn<QRectF>("rhsF");
QTest::addColumn<bool>("result");
QTest::addColumn<bool>("floatResult");
QTest::addColumn<bool>("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<QRect>("r");