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 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
corresponds to one UTF-16 code unit. (Unicode characters
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==()
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.
\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==()
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.
*/
/*!
\fn bool QString::operator==(QLatin1StringView s1, const QString &s2)
\fn bool QString::operator==(const QLatin1StringView &lhs, const QString &rhs)
\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.
*/
@ -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<()
Returns \c true if string \a s1 is lexically less than string
\a s2; otherwise returns \c false.
Returns \c true if string \a lhs is lexically less than string
\a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
\fn bool QString::operator<(const QString &s1, QLatin1StringView s2)
\fn bool QString::operator<(const QString &lhs, const QLatin1StringView &rhs)
\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.
*/
/*!
\fn bool QString::operator<(QLatin1StringView s1, const QString &s2)
\fn bool QString::operator<(const QLatin1StringView &lhs, const QString &rhs)
\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.
*/
@ -4169,29 +4173,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
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
string \a s2; otherwise returns \c false.
Returns \c true if string \a lhs is lexically less than or equal to
string \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
\fn bool QString::operator<=(const QString &s1, QLatin1StringView s2)
\fn bool QString::operator<=(const QString &lhs, const QLatin1StringView &rhs)
\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.
*/
/*!
\fn bool QString::operator<=(QLatin1StringView s1, const QString &s2)
\fn bool QString::operator<=(const QLatin1StringView &lhs, const QString &rhs)
\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.
*/
@ -4222,29 +4226,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
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.
\sa {Comparing Strings}
*/
/*!
\fn bool QString::operator>(const QString &s1, QLatin1StringView s2)
\fn bool QString::operator>(const QString &lhs, const QLatin1StringView &rhs)
\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.
*/
/*!
\fn bool QString::operator>(QLatin1StringView s1, const QString &s2)
\fn bool QString::operator>(const QLatin1StringView &lhs, const QString &rhs)
\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.
*/
@ -4275,29 +4279,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
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
string \a s2; otherwise returns \c false.
Returns \c true if string \a lhs is lexically greater than or equal to
string \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
\fn bool QString::operator>=(const QString &s1, QLatin1StringView s2)
\fn bool QString::operator>=(const QString &lhs, const QLatin1StringView &rhs)
\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.
*/
/*!
\fn bool QString::operator>=(QLatin1StringView s1, const QString &s2)
\fn bool QString::operator>=(const QLatin1StringView &lhs, const QString &rhs)
\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.
*/
@ -4328,17 +4332,17 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
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.
\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.
\overload operator!=()

View File

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

View File

@ -10,6 +10,7 @@
#endif
#include <private/qglobal_p.h> // for the icu feature test
#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QTest>
#include <QString>
#include <QStringBuilder>
@ -668,8 +669,11 @@ private slots:
void isNan_data();
void isNan();
void nanAndInf();
void comparisonCompiles();
void compare_data();
void compare();
void comparisonMacros_data();
void comparisonMacros();
void resize();
void resizeAfterFromRawData();
void resizeAfterReserve();
@ -8030,6 +8034,15 @@ void tst_QString::arg_fillChar()
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()
{
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()
{
QString s;