diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2024-02-22 11:43:35 +0100 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2024-03-02 00:12:54 +0100 |
commit | ee612626f99d5a8da6814c2df90db00f9beb463f (patch) | |
tree | 5a92a286c27418b2b4e76e0faf01a24246f5fa82 | |
parent | a08bafc9205d0b67f71a1896ad84272eeb294374 (diff) |
Q(Latin1)Char: use comparison helper macros
Replace the existing friend relational operators with the macros.
Add the previously-missing QChar vs `const char *` relational operators.
These require out-of-line helper methods, because we need to interpret
the `const char *` array as utf-8.
The `const char *` relational operators cause ambiguities when
comparing QChar with 0 (previously it was only handled by the nullptr_t
overloads). As we have it in several places in our tests, I'd assume
that the users can also do it. To resolve the ambiguities, mark the
new relational operators as Q_WEAK_OVERLOADs.
This allows to remove the dummy QChar vs `const char *` relational
operators from tst_qstringapisymmetry, but at the same time requires
that we introduce new dummy operators for QByteArray vs char16_t
comparison. These will be fixed in a follow-up patch.
For QLatin1Char - convert to uchar before doing the comparison, to
match the behavior of QLatin1StringView and QChar. Extend QChar's
unit tests.
Task-number: QTBUG-117661
Change-Id: I9213fe05a5efdb96d48688f07bec9519f9887a77
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r-- | src/corelib/text/qchar.cpp | 19 | ||||
-rw-r--r-- | src/corelib/text/qchar.h | 87 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 14 | ||||
-rw-r--r-- | tests/auto/corelib/text/qchar/tst_qchar.cpp | 32 | ||||
-rw-r--r-- | tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp | 5 |
5 files changed, 107 insertions, 50 deletions
diff --git a/src/corelib/text/qchar.cpp b/src/corelib/text/qchar.cpp index 7b62b1e04a..63296a92de 100644 --- a/src/corelib/text/qchar.cpp +++ b/src/corelib/text/qchar.cpp @@ -55,6 +55,13 @@ QT_BEGIN_NAMESPACE \ingroup string-processing \reentrant + \compares strong + \compareswith strong char16_t QString QStringView QLatin1StringView QUtf8StringView + \endcompareswith + \compareswith strong {const char *} QByteArray QByteArrayView + The contents of the byte array is interpreted as utf-8. + \endcompareswith + In Qt, Unicode characters are 16-bit entities without any markup or structure. This class represents such an entity. It is lightweight, so it can be used everywhere. Most compilers treat @@ -1740,42 +1747,42 @@ QDataStream &operator>>(QDataStream &in, QChar &chr) *****************************************************************************/ /*! - \fn bool QChar::operator==(QChar c1, QChar c2) + \fn bool QChar::operator==(const QChar &c1, const QChar &c2) Returns \c true if \a c1 and \a c2 are the same Unicode character; otherwise returns \c false. */ /*! - \fn int QChar::operator!=(QChar c1, QChar c2) + \fn bool QChar::operator!=(const QChar &c1, const QChar &c2) Returns \c true if \a c1 and \a c2 are not the same Unicode character; otherwise returns \c false. */ /*! - \fn int QChar::operator<=(QChar c1, QChar c2) + \fn bool QChar::operator<=(const QChar &c1, const QChar &c2) Returns \c true if the numeric Unicode value of \a c1 is less than or equal to that of \a c2; otherwise returns \c false. */ /*! - \fn int QChar::operator>=(QChar c1, QChar c2) + \fn bool QChar::operator>=(const QChar &c1, const QChar &c2) Returns \c true if the numeric Unicode value of \a c1 is greater than or equal to that of \a c2; otherwise returns \c false. */ /*! - \fn int QChar::operator<(QChar c1, QChar c2) + \fn bool QChar::operator<(const QChar &c1, const QChar &c2) Returns \c true if the numeric Unicode value of \a c1 is less than that of \a c2; otherwise returns \c false. */ /*! - \fn int QChar::operator>(QChar c1, QChar c2) + \fn bool QChar::operator>(const QChar &c1, const QChar &c2) Returns \c true if the numeric Unicode value of \a c1 is greater than that of \a c2; otherwise returns \c false. diff --git a/src/corelib/text/qchar.h b/src/corelib/text/qchar.h index fa3483db75..c0c53664c2 100644 --- a/src/corelib/text/qchar.h +++ b/src/corelib/text/qchar.h @@ -5,6 +5,7 @@ #define QCHAR_H #include <QtCore/qglobal.h> +#include <QtCore/qcompare.h> #include <functional> // for std::hash @@ -20,26 +21,20 @@ public: constexpr inline char toLatin1() const noexcept { return ch; } constexpr inline char16_t unicode() const noexcept { return char16_t(uchar(ch)); } - friend constexpr inline bool operator==(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch == rhs.ch; } - friend constexpr inline bool operator!=(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch != rhs.ch; } - friend constexpr inline bool operator<=(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch <= rhs.ch; } - friend constexpr inline bool operator>=(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch >= rhs.ch; } - friend constexpr inline bool operator< (QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch < rhs.ch; } - friend constexpr inline bool operator> (QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch > rhs.ch; } - - friend constexpr inline bool operator==(char lhs, QLatin1Char rhs) noexcept { return lhs == rhs.toLatin1(); } - friend constexpr inline bool operator!=(char lhs, QLatin1Char rhs) noexcept { return lhs != rhs.toLatin1(); } - friend constexpr inline bool operator<=(char lhs, QLatin1Char rhs) noexcept { return lhs <= rhs.toLatin1(); } - friend constexpr inline bool operator>=(char lhs, QLatin1Char rhs) noexcept { return lhs >= rhs.toLatin1(); } - friend constexpr inline bool operator< (char lhs, QLatin1Char rhs) noexcept { return lhs < rhs.toLatin1(); } - friend constexpr inline bool operator> (char lhs, QLatin1Char rhs) noexcept { return lhs > rhs.toLatin1(); } - - friend constexpr inline bool operator==(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() == rhs; } - friend constexpr inline bool operator!=(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() != rhs; } - friend constexpr inline bool operator<=(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() <= rhs; } - friend constexpr inline bool operator>=(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() >= rhs; } - friend constexpr inline bool operator< (QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() < rhs; } - friend constexpr inline bool operator> (QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() > rhs; } + friend constexpr bool + comparesEqual(const QLatin1Char &lhs, const QLatin1Char &rhs) noexcept + { return lhs.ch == rhs.ch; } + friend constexpr Qt::strong_ordering + compareThreeWay(const QLatin1Char &lhs, const QLatin1Char &rhs) noexcept + { return Qt::compareThreeWay(uchar(lhs.ch), uchar(rhs.ch)); } + Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QLatin1Char) + + friend constexpr bool comparesEqual(const QLatin1Char &lhs, char rhs) noexcept + { return lhs.toLatin1() == rhs; } + friend constexpr Qt::strong_ordering + compareThreeWay(const QLatin1Char &lhs, char rhs) noexcept + { return Qt::compareThreeWay(uchar(lhs.toLatin1()), uchar(rhs)); } + Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QLatin1Char, char) private: char ch; @@ -581,28 +576,19 @@ public: static constexpr inline bool isTitleCase(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION { return ucs4 > 127 && QChar::category(ucs4) == Letter_Titlecase; } - friend constexpr inline bool operator==(QChar c1, QChar c2) noexcept { return c1.ucs == c2.ucs; } - friend constexpr inline bool operator< (QChar c1, QChar c2) noexcept { return c1.ucs < c2.ucs; } + friend constexpr bool comparesEqual(const QChar &lhs, const QChar &rhs) noexcept + { return lhs.ucs == rhs.ucs; } + friend constexpr Qt::strong_ordering + compareThreeWay(const QChar &lhs, const QChar &rhs) noexcept + { return Qt::compareThreeWay(lhs.ucs, rhs.ucs); } + Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QChar) - friend constexpr inline bool operator!=(QChar c1, QChar c2) noexcept { return !operator==(c1, c2); } - friend constexpr inline bool operator>=(QChar c1, QChar c2) noexcept { return !operator< (c1, c2); } - friend constexpr inline bool operator> (QChar c1, QChar c2) noexcept { return operator< (c2, c1); } - friend constexpr inline bool operator<=(QChar c1, QChar c2) noexcept { return !operator< (c2, c1); } - - friend constexpr inline bool operator==(QChar lhs, std::nullptr_t) noexcept { return lhs.isNull(); } - friend constexpr inline bool operator< (QChar, std::nullptr_t) noexcept { return false; } - friend constexpr inline bool operator==(std::nullptr_t, QChar rhs) noexcept { return rhs.isNull(); } - friend constexpr inline bool operator< (std::nullptr_t, QChar rhs) noexcept { return !rhs.isNull(); } - - friend constexpr inline bool operator!=(QChar lhs, std::nullptr_t) noexcept { return !operator==(lhs, nullptr); } - friend constexpr inline bool operator>=(QChar lhs, std::nullptr_t) noexcept { return !operator< (lhs, nullptr); } - friend constexpr inline bool operator> (QChar lhs, std::nullptr_t) noexcept { return operator< (nullptr, lhs); } - friend constexpr inline bool operator<=(QChar lhs, std::nullptr_t) noexcept { return !operator< (nullptr, lhs); } - - friend constexpr inline bool operator!=(std::nullptr_t, QChar rhs) noexcept { return !operator==(nullptr, rhs); } - friend constexpr inline bool operator>=(std::nullptr_t, QChar rhs) noexcept { return !operator< (nullptr, rhs); } - friend constexpr inline bool operator> (std::nullptr_t, QChar rhs) noexcept { return operator< (rhs, nullptr); } - friend constexpr inline bool operator<=(std::nullptr_t, QChar rhs) noexcept { return !operator< (rhs, nullptr); } + friend constexpr bool comparesEqual(const QChar &lhs, std::nullptr_t) noexcept + { return lhs.isNull(); } + friend constexpr Qt::strong_ordering + compareThreeWay(const QChar &lhs, std::nullptr_t) noexcept + { return lhs.isNull() ? Qt::strong_ordering::equivalent : Qt::strong_ordering::greater; } + Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QChar, std::nullptr_t) private: static bool QT_CHAR_FASTCALL isSpace_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION; @@ -610,6 +596,25 @@ private: static bool QT_CHAR_FASTCALL isNumber_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION; static bool QT_CHAR_FASTCALL isLetterOrNumber_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION; + // defined in qstring.cpp, because we need to go via QUtf8StringView + static bool QT_CHAR_FASTCALL + equal_helper(QChar lhs, const char *rhs) noexcept Q_DECL_CONST_FUNCTION; + static int QT_CHAR_FASTCALL + compare_helper(QChar lhs, const char *rhs) noexcept Q_DECL_CONST_FUNCTION; + +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) + Q_WEAK_OVERLOAD + friend bool comparesEqual(const QChar &lhs, const char *rhs) noexcept + { return equal_helper(lhs, rhs); } + Q_WEAK_OVERLOAD + friend Qt::strong_ordering compareThreeWay(const QChar &lhs, const char *rhs) noexcept + { + const int res = compare_helper(lhs, rhs); + return Qt::compareThreeWay(res, 0); + } + Q_DECLARE_STRONGLY_ORDERED(QChar, const char *, Q_WEAK_OVERLOAD QT_ASCII_CAST_WARN) +#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) + #ifdef QT_NO_CAST_FROM_ASCII QChar(char c) = delete; QChar(uchar c) = delete; diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 28417a304e..58b9a42813 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -6735,6 +6735,20 @@ Qt::strong_ordering QByteArrayView::compareThreeWay(const QByteArrayView &lhs, \internal \since 6.8 */ +bool QT_FASTCALL QChar::equal_helper(QChar lhs, const char *rhs) noexcept +{ + return QtPrivate::equalStrings(QStringView(&lhs, 1), QUtf8StringView(rhs)); +} + +int QT_FASTCALL QChar::compare_helper(QChar lhs, const char *rhs) noexcept +{ + return QtPrivate::compareStrings(QStringView(&lhs, 1), QUtf8StringView(rhs)); +} + +/*! + \internal + \since 6.8 +*/ bool QStringView::equal_helper(QStringView sv, const char *data, qsizetype len) { Q_ASSERT(len >= 0); diff --git a/tests/auto/corelib/text/qchar/tst_qchar.cpp b/tests/auto/corelib/text/qchar/tst_qchar.cpp index e0578bacb2..b112538a8c 100644 --- a/tests/auto/corelib/text/qchar/tst_qchar.cpp +++ b/tests/auto/corelib/text/qchar/tst_qchar.cpp @@ -17,6 +17,8 @@ private slots: void operator_eqeq_null(); void operators_data(); void operators(); + void qchar_qlatin1char_operators_symmetry_data(); + void qchar_qlatin1char_operators_symmetry(); void toUpper(); void toLower(); void toTitle(); @@ -174,6 +176,36 @@ void tst_QChar::operators() #undef CHECK } +void tst_QChar::qchar_qlatin1char_operators_symmetry_data() +{ + QTest::addColumn<char>("lhs"); + QTest::addColumn<char>("rhs"); + + const uchar values[] = {0x00, 0x3a, 0x7f, 0x80, 0xab, 0xff}; + + for (uchar i : values) { + for (uchar j : values) + QTest::addRow("'\\x%02x'_op_'\\x%02x'", i, j) << char(i) << char(j); + } +} + +void tst_QChar::qchar_qlatin1char_operators_symmetry() +{ + QFETCH(char, lhs); + QFETCH(char, rhs); + + const QLatin1Char l1lhs(lhs); + const QLatin1Char l1rhs(rhs); +#define CHECK(op) QCOMPARE((l1lhs op l1rhs), (QChar(l1lhs) op QChar(l1rhs))) + CHECK(==); + CHECK(!=); + CHECK(< ); + CHECK(> ); + CHECK(<=); + CHECK(>=); +#undef CHECK +} + void tst_QChar::toUpper() { QVERIFY(QChar('a').toUpper() == 'A'); diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index 854d0ac991..33bfdf163a 100644 --- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -61,9 +61,8 @@ constexpr bool is_fake_comparator_v = false; /*end*/ -MAKE_ALL(const char*, QChar) - -MAKE_ALL(QChar, const char*) +MAKE_ALL(char16_t, QByteArray) +MAKE_ALL(QByteArray, char16_t) #undef MAKE_ALL #undef MAKE_RELOP |