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 +#include #include // 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 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 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, 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 @@ -6731,6 +6731,20 @@ Qt::strong_ordering QByteArrayView::compareThreeWay(const QByteArrayView &lhs, return Qt::compareThreeWay(res, 0); } +/*! + \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 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("lhs"); + QTest::addColumn("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