QString: use comparison helper macros - trivial changes [1/3]

Replace the hidden friend relational operators with hidden friend
helper functions and comparison helper macros.

Provide more unit-tests for the updated types.

This enables operator<=> in C++20 builds.

Task-number: QTBUG-117661
Change-Id: I17329cd6422f272a435fc1da241203581eef7fbb
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ivan Solovev 2024-02-16 18:37:14 +01:00
parent 6d08db8666
commit 755581e2e7
4 changed files with 125 additions and 102 deletions

View File

@ -1702,6 +1702,10 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\ingroup shared \ingroup shared
\ingroup string-processing \ingroup string-processing
\compares strong
\compareswith strong QChar QLatin1StringView {const char16_t *}
\endcompareswith
QString stores a string of 16-bit \l{QChar}s, where each QChar QString stores a string of 16-bit \l{QChar}s, where each QChar
corresponds to one UTF-16 code unit. (Unicode characters corresponds to one UTF-16 code unit. (Unicode characters
with code values above 65535 are stored using surrogate pairs, with code values above 65535 are stored using surrogate pairs,
@ -4052,10 +4056,10 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
} }
/*! /*!
\fn bool QString::operator==(const QString &s1, const QString &s2) \fn bool QString::operator==(const QString &lhs, const QString &rhs)
\overload operator==() \overload operator==()
Returns \c true if string \a s1 is equal to string \a s2; otherwise Returns \c true if string \a lhs is equal to string \a rhs; otherwise
returns \c false. returns \c false.
\include qstring.cpp compare-isNull-vs-isEmpty \include qstring.cpp compare-isNull-vs-isEmpty
@ -4064,20 +4068,20 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
*/ */
/*! /*!
\fn bool QString::operator==(const QString &s1, QLatin1StringView s2) \fn bool QString::operator==(const QString &lhs, const QLatin1StringView &rhs)
\overload operator==() \overload operator==()
Returns \c true if \a s1 is equal to \a s2; otherwise Returns \c true if \a lhs is equal to \a rhs; otherwise
returns \c false. returns \c false.
*/ */
/*! /*!
\fn bool QString::operator==(QLatin1StringView s1, const QString &s2) \fn bool QString::operator==(const QLatin1StringView &lhs, const QString &rhs)
\overload operator==() \overload operator==()
Returns \c true if \a s1 is equal to \a s2; otherwise Returns \c true if \a lhs is equal to \a rhs; otherwise
returns \c false. returns \c false.
*/ */
@ -4111,31 +4115,31 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
*/ */
/*! /*!
\fn bool QString::operator<(const QString &s1, const QString &s2) \fn bool QString::operator<(const QString &lhs, const QString &rhs)
\overload operator<() \overload operator<()
Returns \c true if string \a s1 is lexically less than string Returns \c true if string \a lhs is lexically less than string
\a s2; otherwise returns \c false. \a rhs; otherwise returns \c false.
\sa {Comparing Strings} \sa {Comparing Strings}
*/ */
/*! /*!
\fn bool QString::operator<(const QString &s1, QLatin1StringView s2) \fn bool QString::operator<(const QString &lhs, const QLatin1StringView &rhs)
\overload operator<() \overload operator<()
Returns \c true if \a s1 is lexically less than \a s2; Returns \c true if \a lhs is lexically less than \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
/*! /*!
\fn bool QString::operator<(QLatin1StringView s1, const QString &s2) \fn bool QString::operator<(const QLatin1StringView &lhs, const QString &rhs)
\overload operator<() \overload operator<()
Returns \c true if \a s1 is lexically less than \a s2; Returns \c true if \a lhs is lexically less than \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
@ -4169,29 +4173,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example. go through QObject::tr(), for example.
*/ */
/*! \fn bool QString::operator<=(const QString &s1, const QString &s2) /*! \fn bool QString::operator<=(const QString &lhs, const QString &rhs)
Returns \c true if string \a s1 is lexically less than or equal to Returns \c true if string \a lhs is lexically less than or equal to
string \a s2; otherwise returns \c false. string \a rhs; otherwise returns \c false.
\sa {Comparing Strings} \sa {Comparing Strings}
*/ */
/*! /*!
\fn bool QString::operator<=(const QString &s1, QLatin1StringView s2) \fn bool QString::operator<=(const QString &lhs, const QLatin1StringView &rhs)
\overload operator<=() \overload operator<=()
Returns \c true if \a s1 is lexically less than or equal to \a s2; Returns \c true if \a lhs is lexically less than or equal to \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
/*! /*!
\fn bool QString::operator<=(QLatin1StringView s1, const QString &s2) \fn bool QString::operator<=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator<=() \overload operator<=()
Returns \c true if \a s1 is lexically less than or equal to \a s2; Returns \c true if \a lhs is lexically less than or equal to \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
@ -4222,29 +4226,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example. go through QObject::tr(), for example.
*/ */
/*! \fn bool QString::operator>(const QString &s1, const QString &s2) /*! \fn bool QString::operator>(const QString &lhs, const QString &rhs)
Returns \c true if string \a s1 is lexically greater than string \a s2; Returns \c true if string \a lhs is lexically greater than string \a rhs;
otherwise returns \c false. otherwise returns \c false.
\sa {Comparing Strings} \sa {Comparing Strings}
*/ */
/*! /*!
\fn bool QString::operator>(const QString &s1, QLatin1StringView s2) \fn bool QString::operator>(const QString &lhs, const QLatin1StringView &rhs)
\overload operator>() \overload operator>()
Returns \c true if \a s1 is lexically greater than \a s2; Returns \c true if \a lhs is lexically greater than \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
/*! /*!
\fn bool QString::operator>(QLatin1StringView s1, const QString &s2) \fn bool QString::operator>(const QLatin1StringView &lhs, const QString &rhs)
\overload operator>() \overload operator>()
Returns \c true if \a s1 is lexically greater than \a s2; Returns \c true if \a lhs is lexically greater than \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
@ -4275,29 +4279,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example. for example.
*/ */
/*! \fn bool QString::operator>=(const QString &s1, const QString &s2) /*! \fn bool QString::operator>=(const QString &lhs, const QString &rhs)
Returns \c true if string \a s1 is lexically greater than or equal to Returns \c true if string \a lhs is lexically greater than or equal to
string \a s2; otherwise returns \c false. string \a rhs; otherwise returns \c false.
\sa {Comparing Strings} \sa {Comparing Strings}
*/ */
/*! /*!
\fn bool QString::operator>=(const QString &s1, QLatin1StringView s2) \fn bool QString::operator>=(const QString &lhs, const QLatin1StringView &rhs)
\overload operator>=() \overload operator>=()
Returns \c true if \a s1 is lexically greater than or equal to \a s2; Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
/*! /*!
\fn bool QString::operator>=(QLatin1StringView s1, const QString &s2) \fn bool QString::operator>=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator>=() \overload operator>=()
Returns \c true if \a s1 is lexically greater than or equal to \a s2; Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
otherwise returns \c false. otherwise returns \c false.
*/ */
@ -4328,17 +4332,17 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example. for example.
*/ */
/*! \fn bool QString::operator!=(const QString &s1, const QString &s2) /*! \fn bool QString::operator!=(const QString &lhs, const QString &rhs)
Returns \c true if string \a s1 is not equal to string \a s2; Returns \c true if string \a lhs is not equal to string \a rhs;
otherwise returns \c false. otherwise returns \c false.
\sa {Comparing Strings} \sa {Comparing Strings}
*/ */
/*! \fn bool QString::operator!=(const QString &s1, QLatin1StringView s2) /*! \fn bool QString::operator!=(const QString &lhs, const QLatin1StringView &rhs)
Returns \c true if string \a s1 is not equal to string \a s2. Returns \c true if string \a lhs is not equal to string \a rhs.
Otherwise returns \c false. Otherwise returns \c false.
\overload operator!=() \overload operator!=()

View File

@ -12,6 +12,7 @@
#endif #endif
#include <QtCore/qchar.h> #include <QtCore/qchar.h>
#include <QtCore/qcompare.h>
#include <QtCore/qbytearray.h> #include <QtCore/qbytearray.h>
#include <QtCore/qbytearrayview.h> #include <QtCore/qbytearrayview.h>
#include <QtCore/qarraydata.h> #include <QtCore/qarraydata.h>
@ -760,78 +761,44 @@ public:
static QString number(qulonglong, int base=10); static QString number(qulonglong, int base=10);
static QString number(double, char format='g', int precision=6); static QString number(double, char format='g', int precision=6);
friend bool operator==(const QString &s1, const QString &s2) noexcept friend bool comparesEqual(const QString &s1, const QString &s2) noexcept
{ return (s1.size() == s2.size()) && QtPrivate::equalStrings(s1, s2); } { return comparesEqual(QStringView(s1), QStringView(s2)); }
friend bool operator< (const QString &s1, const QString &s2) noexcept friend Qt::strong_ordering compareThreeWay(const QString &s1, const QString &s2) noexcept
{ return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) < 0; } { return compareThreeWay(QStringView(s1), QStringView(s2)); }
friend bool operator> (const QString &s1, const QString &s2) noexcept { return s2 < s1; } Q_DECLARE_STRONGLY_ORDERED(QString)
friend bool operator!=(const QString &s1, const QString &s2) noexcept { return !(s1 == s2); }
friend bool operator<=(const QString &s1, const QString &s2) noexcept { return !(s1 > s2); }
friend bool operator>=(const QString &s1, const QString &s2) noexcept { return !(s1 < s2); }
friend bool operator==(const QString &s1, QLatin1StringView s2) noexcept friend bool comparesEqual(const QString &s1, QLatin1StringView s2) noexcept
{ return (s1.size() == s2.size()) && QtPrivate::equalStrings(s1, s2); } { return (s1.size() == s2.size()) && QtPrivate::equalStrings(s1, s2); }
friend bool operator< (const QString &s1, QLatin1StringView s2) noexcept friend Qt::strong_ordering
{ return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) < 0; } compareThreeWay(const QString &s1, QLatin1StringView s2) noexcept
friend bool operator> (const QString &s1, QLatin1StringView s2) noexcept {
{ return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) > 0; } const int res = QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive);
friend bool operator!=(const QString &s1, QLatin1StringView s2) noexcept { return !(s1 == s2); } return Qt::compareThreeWay(res, 0);
friend bool operator<=(const QString &s1, QLatin1StringView s2) noexcept { return !(s1 > s2); } }
friend bool operator>=(const QString &s1, QLatin1StringView s2) noexcept { return !(s1 < s2); } Q_DECLARE_STRONGLY_ORDERED(QString, QLatin1StringView)
friend bool operator==(QLatin1StringView s1, const QString &s2) noexcept { return s2 == s1; }
friend bool operator< (QLatin1StringView s1, const QString &s2) noexcept { return s2 > s1; }
friend bool operator> (QLatin1StringView s1, const QString &s2) noexcept { return s2 < s1; }
friend bool operator!=(QLatin1StringView s1, const QString &s2) noexcept { return s2 != s1; }
friend bool operator<=(QLatin1StringView s1, const QString &s2) noexcept { return s2 >= s1; }
friend bool operator>=(QLatin1StringView s1, const QString &s2) noexcept { return s2 <= s1; }
// Check isEmpty() instead of isNull() for backwards compatibility. // Check isEmpty() instead of isNull() for backwards compatibility.
friend bool operator==(const QString &s1, std::nullptr_t) noexcept { return s1.isEmpty(); } friend bool comparesEqual(const QString &s1, std::nullptr_t) noexcept
friend bool operator!=(const QString &s1, std::nullptr_t) noexcept { return !s1.isEmpty(); } { return s1.isEmpty(); }
friend bool operator< (const QString & , std::nullptr_t) noexcept { return false; } friend Qt::strong_ordering compareThreeWay(const QString &s1, std::nullptr_t) noexcept
friend bool operator> (const QString &s1, std::nullptr_t) noexcept { return !s1.isEmpty(); } { return s1.isEmpty() ? Qt::strong_ordering::equivalent : Qt::strong_ordering::greater; }
friend bool operator<=(const QString &s1, std::nullptr_t) noexcept { return s1.isEmpty(); } Q_DECLARE_STRONGLY_ORDERED(QString, std::nullptr_t)
friend bool operator>=(const QString & , std::nullptr_t) noexcept { return true; }
friend bool operator==(std::nullptr_t, const QString &s2) noexcept { return s2 == nullptr; }
friend bool operator!=(std::nullptr_t, const QString &s2) noexcept { return s2 != nullptr; }
friend bool operator< (std::nullptr_t, const QString &s2) noexcept { return s2 > nullptr; }
friend bool operator> (std::nullptr_t, const QString &s2) noexcept { return s2 < nullptr; }
friend bool operator<=(std::nullptr_t, const QString &s2) noexcept { return s2 >= nullptr; }
friend bool operator>=(std::nullptr_t, const QString &s2) noexcept { return s2 <= nullptr; }
friend bool operator==(const QString &s1, const char16_t *s2) noexcept { return s1 == QStringView(s2); } friend bool comparesEqual(const QString &s1, const char16_t *s2) noexcept
friend bool operator!=(const QString &s1, const char16_t *s2) noexcept { return s1 != QStringView(s2); } { return comparesEqual(s1, QStringView(s2)); }
friend bool operator< (const QString &s1, const char16_t *s2) noexcept { return s1 < QStringView(s2); } friend Qt::strong_ordering compareThreeWay(const QString &s1, const char16_t *s2) noexcept
friend bool operator> (const QString &s1, const char16_t *s2) noexcept { return s1 > QStringView(s2); } { return compareThreeWay(s1, QStringView(s2)); }
friend bool operator<=(const QString &s1, const char16_t *s2) noexcept { return s1 <= QStringView(s2); } Q_DECLARE_STRONGLY_ORDERED(QString, const char16_t *)
friend bool operator>=(const QString &s1, const char16_t *s2) noexcept { return s1 >= QStringView(s2); }
friend bool operator==(const char16_t *s1, const QString &s2) noexcept { return s2 == s1; }
friend bool operator!=(const char16_t *s1, const QString &s2) noexcept { return s2 != s1; }
friend bool operator< (const char16_t *s1, const QString &s2) noexcept { return s2 > s1; }
friend bool operator> (const char16_t *s1, const QString &s2) noexcept { return s2 < s1; }
friend bool operator<=(const char16_t *s1, const QString &s2) noexcept { return s2 >= s1; }
friend bool operator>=(const char16_t *s1, const QString &s2) noexcept { return s2 <= s1; }
// QChar <> QString // QChar <> QString
friend inline bool operator==(QChar lhs, const QString &rhs) noexcept friend bool comparesEqual(const QString &lhs, QChar rhs) noexcept
{ return rhs.size() == 1 && lhs == rhs.front(); } { return lhs.size() == 1 && rhs == lhs.front(); }
friend inline bool operator< (QChar lhs, const QString &rhs) noexcept friend Qt::strong_ordering compareThreeWay(const QString &lhs, QChar rhs) noexcept
{ return compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; } {
friend inline bool operator> (QChar lhs, const QString &rhs) noexcept const int res = compare_helper(lhs.data(), lhs.size(), &rhs, 1);
{ return compare_helper(&lhs, 1, rhs.data(), rhs.size()) > 0; } return Qt::compareThreeWay(res, 0);
}
friend inline bool operator!=(QChar lhs, const QString &rhs) noexcept { return !(lhs == rhs); } Q_DECLARE_STRONGLY_ORDERED(QString, QChar)
friend inline bool operator<=(QChar lhs, const QString &rhs) noexcept { return !(lhs > rhs); }
friend inline bool operator>=(QChar lhs, const QString &rhs) noexcept { return !(lhs < rhs); }
friend inline bool operator==(const QString &lhs, QChar rhs) noexcept { return rhs == lhs; }
friend inline bool operator!=(const QString &lhs, QChar rhs) noexcept { return !(rhs == lhs); }
friend inline bool operator< (const QString &lhs, QChar rhs) noexcept { return rhs > lhs; }
friend inline bool operator> (const QString &lhs, QChar rhs) noexcept { return rhs < lhs; }
friend inline bool operator<=(const QString &lhs, QChar rhs) noexcept { return !(rhs < lhs); }
friend inline bool operator>=(const QString &lhs, QChar rhs) noexcept { return !(rhs > lhs); }
// ASCII compatibility // ASCII compatibility
#if defined(QT_RESTRICTED_CAST_FROM_ASCII) #if defined(QT_RESTRICTED_CAST_FROM_ASCII)

View File

@ -27,6 +27,7 @@ foreach(test tst_qstring tst_qstring_restricted_ascii tst_qstring_no_cast_from_a
${tst_qstring_extra_sources} ${tst_qstring_extra_sources}
LIBRARIES LIBRARIES
Qt::CorePrivate Qt::CorePrivate
Qt::TestPrivate
${tst_qstring_extra_libraries} ${tst_qstring_extra_libraries}
DEFINES DEFINES
${tst_qstring_extra_defines} ${tst_qstring_extra_defines}

View File

@ -10,6 +10,7 @@
#endif #endif
#include <private/qglobal_p.h> // for the icu feature test #include <private/qglobal_p.h> // for the icu feature test
#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QTest> #include <QTest>
#include <QString> #include <QString>
#include <QStringBuilder> #include <QStringBuilder>
@ -668,8 +669,11 @@ private slots:
void isNan_data(); void isNan_data();
void isNan(); void isNan();
void nanAndInf(); void nanAndInf();
void comparisonCompiles();
void compare_data(); void compare_data();
void compare(); void compare();
void comparisonMacros_data();
void comparisonMacros();
void resize(); void resize();
void resizeAfterFromRawData(); void resizeAfterFromRawData();
void resizeAfterReserve(); void resizeAfterReserve();
@ -8030,6 +8034,15 @@ void tst_QString::arg_fillChar()
QCOMPARE(actual, expected); QCOMPARE(actual, expected);
} }
void tst_QString::comparisonCompiles()
{
QTestPrivate::testAllComparisonOperatorsCompile<QString>();
QTestPrivate::testAllComparisonOperatorsCompile<QString, std::nullptr_t>();
QTestPrivate::testAllComparisonOperatorsCompile<QString, QChar>();
QTestPrivate::testAllComparisonOperatorsCompile<QString, QLatin1StringView>();
QTestPrivate::testAllComparisonOperatorsCompile<QString, const char16_t *>();
}
void tst_QString::compare_data() void tst_QString::compare_data()
{ {
QTest::addColumn<QString>("s1"); QTest::addColumn<QString>("s1");
@ -8219,6 +8232,44 @@ void tst_QString::compare()
} }
} }
void tst_QString::comparisonMacros_data()
{
compare_data();
}
void tst_QString::comparisonMacros()
{
QFETCH(const QString, s1);
QFETCH(const QString, s2);
QFETCH(int, csr);
const Qt::strong_ordering expectedOrdering = [&csr] {
if (csr > 0)
return Qt::strong_ordering::greater;
else if (csr < 0)
return Qt::strong_ordering::less;
return Qt::strong_ordering::equal;
}();
QT_TEST_ALL_COMPARISON_OPS(s1, s2, expectedOrdering);
if (!s2.contains(QChar(u'\0'))) {
const char16_t *utfData = reinterpret_cast<const char16_t*>(s2.constData());
QT_TEST_ALL_COMPARISON_OPS(s1, utfData, expectedOrdering);
}
if (s2.size() == 1) {
const QChar ch = s2.front();
QT_TEST_ALL_COMPARISON_OPS(s1, ch, expectedOrdering);
}
if (isLatin(s2)) {
QByteArray ba = s2.toLatin1();
const QLatin1StringView l1s2{ba};
QT_TEST_ALL_COMPARISON_OPS(s1, l1s2, expectedOrdering);
}
}
void tst_QString::resize() void tst_QString::resize()
{ {
QString s; QString s;