QTypeRevision: use comparison helper macros
QTypeRevision consists of two quint8 values: major and minor version. Each of the versions can be unknown. The rules for comparing with the unknown version are as follows: zero version < unknown version < non-zero version At the same time, two unknown versions are considered equal. This makes the comparison a bit tricky, but it still fits into the category of strong ordering. Replace the existing friend relational operators with helper functions and comparison helper macros, making this type strongly ordered. Update the unit-tests to use the new comparison helper test functions. As the test functions check the reversed arguments as well, we can reduce the number of rows for the data-driven comparison test. Fixes: QTBUG-120359 Change-Id: Ib6f1037fc7b5fed148e35ee48b56b05dcd36b3b4 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
81dcb7c8be
commit
e55ee873e9
@ -26,6 +26,7 @@ QT_IMPL_METATYPE_EXTERN(QTypeRevision)
|
||||
\brief The QTypeRevision class contains a lightweight representation of
|
||||
a version number with two 8-bit segments, major and minor, either
|
||||
of which can be unknown.
|
||||
\compares strong
|
||||
|
||||
Use this class to describe revisions of a type. Compatible revisions can be
|
||||
expressed as increments of the minor version. Breaking changes can be
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define QTYPEREVISION_H
|
||||
|
||||
#include <QtCore/qassert.h>
|
||||
#include <QtCore/qcompare.h>
|
||||
#include <QtCore/qcontainertools_impl.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#include <QtCore/qtypeinfo.h>
|
||||
@ -98,53 +99,38 @@ public:
|
||||
return Integer(m_majorVersion << 8) | Integer(m_minorVersion);
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(QTypeRevision lhs, QTypeRevision rhs)
|
||||
{
|
||||
return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>();
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator!=(QTypeRevision lhs, QTypeRevision rhs)
|
||||
{
|
||||
return lhs.toEncodedVersion<quint16>() != rhs.toEncodedVersion<quint16>();
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator<(QTypeRevision lhs, QTypeRevision rhs)
|
||||
{
|
||||
return (!lhs.hasMajorVersion() && rhs.hasMajorVersion())
|
||||
// non-0 major > unspecified major > major 0
|
||||
? rhs.majorVersion() != 0
|
||||
: ((lhs.hasMajorVersion() && !rhs.hasMajorVersion())
|
||||
// major 0 < unspecified major < non-0 major
|
||||
? lhs.majorVersion() == 0
|
||||
: (lhs.majorVersion() != rhs.majorVersion()
|
||||
// both majors specified and non-0
|
||||
? lhs.majorVersion() < rhs.majorVersion()
|
||||
: ((!lhs.hasMinorVersion() && rhs.hasMinorVersion())
|
||||
// non-0 minor > unspecified minor > minor 0
|
||||
? rhs.minorVersion() != 0
|
||||
: ((lhs.hasMinorVersion() && !rhs.hasMinorVersion())
|
||||
// minor 0 < unspecified minor < non-0 minor
|
||||
? lhs.minorVersion() == 0
|
||||
// both minors specified and non-0
|
||||
: lhs.minorVersion() < rhs.minorVersion()))));
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator>(QTypeRevision lhs, QTypeRevision rhs)
|
||||
{
|
||||
return lhs != rhs && !(lhs < rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator<=(QTypeRevision lhs, QTypeRevision rhs)
|
||||
{
|
||||
return lhs == rhs || lhs < rhs;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator>=(QTypeRevision lhs, QTypeRevision rhs)
|
||||
{
|
||||
return lhs == rhs || !(lhs < rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
friend constexpr bool
|
||||
comparesEqual(const QTypeRevision &lhs, const QTypeRevision &rhs) noexcept
|
||||
{ return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>(); }
|
||||
friend constexpr Qt::strong_ordering
|
||||
compareThreeWay(const QTypeRevision &lhs, const QTypeRevision &rhs) noexcept
|
||||
{
|
||||
// For both major and minor the following rule applies:
|
||||
// non-0 ver > unspecified ver > 0 ver
|
||||
auto cmpUnspecified = [](quint8 leftVer, quint8 rightVer) {
|
||||
Q_ASSERT(leftVer != rightVer
|
||||
&& (leftVer == QTypeRevision::SegmentUnknown
|
||||
|| rightVer == QTypeRevision::SegmentUnknown));
|
||||
if (leftVer != QTypeRevision::SegmentUnknown)
|
||||
return leftVer > 0 ? Qt::strong_ordering::greater : Qt::strong_ordering::less;
|
||||
return rightVer > 0 ? Qt::strong_ordering::less : Qt::strong_ordering::greater;
|
||||
};
|
||||
|
||||
if (lhs.hasMajorVersion() != rhs.hasMajorVersion()) {
|
||||
return cmpUnspecified(lhs.majorVersion(), rhs.majorVersion());
|
||||
} else {
|
||||
const auto majorRes = Qt::compareThreeWay(lhs.majorVersion(), rhs.majorVersion());
|
||||
if (is_eq(majorRes)) {
|
||||
if (lhs.hasMinorVersion() != rhs.hasMinorVersion())
|
||||
return cmpUnspecified(lhs.minorVersion(), rhs.minorVersion());
|
||||
return Qt::compareThreeWay(lhs.minorVersion(), rhs.minorVersion());
|
||||
}
|
||||
return majorRes;
|
||||
}
|
||||
}
|
||||
Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QTypeRevision)
|
||||
|
||||
enum { SegmentUnknown = 0xff };
|
||||
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
|
@ -10,4 +10,6 @@ endif()
|
||||
qt_internal_add_test(tst_qtyperevision
|
||||
SOURCES
|
||||
tst_qtyperevision.cpp
|
||||
LIBRARIES
|
||||
Qt::TestPrivate
|
||||
)
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <QTest>
|
||||
#include <QtCore/qtyperevision.h>
|
||||
#include <QtTest/private/qcomparisontesthelper_p.h>
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
@ -15,6 +16,7 @@ private slots:
|
||||
void qTypeRevision_data();
|
||||
void qTypeRevision();
|
||||
void qTypeRevisionTypes();
|
||||
void qTypeRevisionComparisonCompiles();
|
||||
void qTypeRevisionComparison_data();
|
||||
void qTypeRevisionComparison();
|
||||
};
|
||||
@ -131,11 +133,16 @@ void tst_QTypeRevision::qTypeRevisionTypes()
|
||||
QVERIFY(maxRevision.hasMinorVersion());
|
||||
}
|
||||
|
||||
void tst_QTypeRevision::qTypeRevisionComparisonCompiles()
|
||||
{
|
||||
QTestPrivate::testAllComparisonOperatorsCompile<QTypeRevision>();
|
||||
}
|
||||
|
||||
void tst_QTypeRevision::qTypeRevisionComparison_data()
|
||||
{
|
||||
QTest::addColumn<QTypeRevision>("lhs");
|
||||
QTest::addColumn<QTypeRevision>("rhs");
|
||||
QTest::addColumn<int>("expectedResult");
|
||||
QTest::addColumn<Qt::strong_ordering>("expectedResult");
|
||||
|
||||
static auto versionStr = [](QTypeRevision r) {
|
||||
QByteArray res = r.hasMajorVersion() ? QByteArray::number(r.majorVersion())
|
||||
@ -167,10 +174,11 @@ void tst_QTypeRevision::qTypeRevisionComparison_data()
|
||||
|
||||
const int length = sizeof(revisions) / sizeof(QTypeRevision);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
for (int j = 0; j < length; ++j) {
|
||||
const int expectedRes = (i == j)
|
||||
? 0
|
||||
: (i < j) ? -1 : 1;
|
||||
for (int j = i; j < length; ++j) {
|
||||
const Qt::strong_ordering expectedRes = (i == j)
|
||||
? Qt::strong_ordering::equal
|
||||
: (i < j) ? Qt::strong_ordering::less
|
||||
: Qt::strong_ordering::greater;
|
||||
|
||||
const auto lhs = revisions[i];
|
||||
const auto rhs = revisions[j];
|
||||
@ -184,14 +192,9 @@ void tst_QTypeRevision::qTypeRevisionComparison()
|
||||
{
|
||||
QFETCH(const QTypeRevision, lhs);
|
||||
QFETCH(const QTypeRevision, rhs);
|
||||
QFETCH(const int, expectedResult);
|
||||
QFETCH(const Qt::strong_ordering, expectedResult);
|
||||
|
||||
QCOMPARE(lhs == rhs, expectedResult == 0);
|
||||
QCOMPARE(lhs != rhs, expectedResult != 0);
|
||||
QCOMPARE(lhs < rhs, expectedResult < 0);
|
||||
QCOMPARE(lhs > rhs, expectedResult > 0);
|
||||
QCOMPARE(lhs <= rhs, expectedResult <= 0);
|
||||
QCOMPARE(lhs >= rhs, expectedResult >= 0);
|
||||
QT_TEST_ALL_COMPARISON_OPS(lhs, rhs, expectedResult);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QTypeRevision)
|
||||
|
Loading…
x
Reference in New Issue
Block a user