diff --git a/src/corelib/text/qchar.cpp b/src/corelib/text/qchar.cpp index 1b8cfb642e..94d2322fa6 100644 --- a/src/corelib/text/qchar.cpp +++ b/src/corelib/text/qchar.cpp @@ -710,6 +710,46 @@ QT_BEGIN_NAMESPACE Constructs a QChar for the character with Unicode code point \a code. */ +/*! + \fn static QChar QChar::fromUcs2(char16_t c) + \since 6.0 + + Constructs a QChar from UTF-16 character \a c. + + \sa fromUcs4() +*/ + +/*! + \fn static auto QChar::fromUcs4(char32_t c) + \since 6.0 + + Returns an anonymous struct that + \list + \li contains a \c{char16_t chars[2]} array, + \li can be implicitly converted to a QStringView, and + \li iterated over with a C++11 ranged for loop. + \endlist + + If \a c requires surrogates, \c{chars[0]} contains the high surrogate + and \c{chars[1]} the low surrogate, and the QStringView has size 2. + Otherwise, \c{chars[0]} contains \a c and \c{chars[1]} is + \l{QChar::isNull}{null}, and the QStringView has size 1. + + This allows easy use of the result: + + \code + QString s; + s += QChar::fromUcs4(ch); + \endcode + + \code + for (char16_t c16 : QChar::fromUcs4(ch)) + use(c16); + \endcode + + \sa fromUcs2(), requiresSurrogates() +*/ + /*! \fn bool QChar::isNull() const @@ -1564,12 +1604,10 @@ static FullConvertCaseResult fullConvertCase(char32_t uc, QUnicodeTables::Case w auto length = *specialCase++; while (length--) *pp++ = *specialCase++; - } else if (Q_UNLIKELY(QChar::requiresSurrogates(uc))) { - // so far, case convertion never changes planes (guaranteed by the qunicodetables generator) - *pp++ = QChar::highSurrogate(uc); - *pp++ = QChar::lowSurrogate(uc + caseDiff); } else { - *pp++ = uc + caseDiff; + // so far, case convertion never changes planes (guaranteed by the qunicodetables generator) + for (char16_t c : QChar::fromUcs4(uc + caseDiff)) + *pp++ = c; } return result; } @@ -2002,14 +2040,10 @@ static void composeHelper(QString *str, QChar::UnicodeVersion version, int from) stcode = ligature; QChar *d = s.data(); // ligatureHelper() never changes planes - if (QChar::requiresSurrogates(ligature)) { - d[starter] = QChar(QChar::highSurrogate(ligature)); - d[starter + 1] = QChar(QChar::lowSurrogate(ligature)); - s.remove(i, 2); - } else { - d[starter] = QChar(ligature); - s.remove(i, 1); - } + int j = 0; + for (QChar ch : QChar::fromUcs4(ligature)) + d[starter + j++] = ch; + s.remove(i, j); continue; } } @@ -2079,18 +2113,10 @@ static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, in QChar *uc = s.data(); int p = pos; // exchange characters - if (!QChar::requiresSurrogates(u2)) { - uc[p++] = QChar(u2); - } else { - uc[p++] = QChar(QChar::highSurrogate(u2)); - uc[p++] = QChar(QChar::lowSurrogate(u2)); - } - if (!QChar::requiresSurrogates(u1)) { - uc[p++] = QChar(u1); - } else { - uc[p++] = QChar(QChar::highSurrogate(u1)); - uc[p++] = QChar(QChar::lowSurrogate(u1)); - } + for (QChar ch : QChar::fromUcs4(u2)) + uc[p++] = ch; + for (QChar ch : QChar::fromUcs4(u1)) + uc[p++] = ch; if (pos > 0) --pos; if (pos > 0 && s.at(pos).isLowSurrogate()) diff --git a/src/corelib/text/qchar.h b/src/corelib/text/qchar.h index ea1ce1e4bb..9fea104ec1 100644 --- a/src/corelib/text/qchar.h +++ b/src/corelib/text/qchar.h @@ -120,6 +120,10 @@ public: QT_ASCII_CAST_WARN Q_DECL_CONSTEXPR QChar(uchar c) noexcept : ucs(c) { } #endif #endif + + static constexpr QChar fromUcs2(char16_t c) noexcept { return QChar{c}; } + static constexpr inline auto fromUcs4(char32_t c) noexcept; + // Unicode information enum Category @@ -680,3 +684,5 @@ struct hash } // namespace std #endif // QCHAR_H + +#include // for QChar::fromUcs4() definition diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index 2dd933284b..7e70238cb2 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -351,6 +351,22 @@ template ("ucs4"); + auto row = [](uint ucs4) { + QTest::addRow("0x%08X", ucs4) << ucs4; + }; + + row(0x2f868); + row(0x1D157); + row(0x1D157); +} + +void tst_QChar::fromUcs4() +{ + QFETCH(const uint, ucs4); + + const auto result = QChar::fromUcs4(ucs4); + if (QChar::requiresSurrogates(ucs4)) { + QCOMPARE(result.chars[0], QChar::highSurrogate(ucs4)); + QCOMPARE(result.chars[1], QChar::lowSurrogate(ucs4)); + QCOMPARE(QStringView{result}.size(), 2); + } else { + QCOMPARE(result.chars[0], ucs4); + QCOMPARE(result.chars[1], 0u); + QCOMPARE(QStringView{result}.size(), 1); + } +} + void tst_QChar::fromWchar_t() { #if defined(Q_OS_WIN) @@ -835,13 +865,7 @@ void tst_QChar::normalization_data() for (int j = 0; j < c.size(); ++j) { bool ok; uint uc = c.at(j).toInt(&ok, 16); - if (!QChar::requiresSurrogates(uc)) { - columns[i].append(QChar(uc)); - } else { - // convert to utf16 - columns[i].append(QChar(QChar::highSurrogate(uc))); - columns[i].append(QChar(QChar::lowSurrogate(uc))); - } + columns[i].append(QChar::fromUcs4(uc)); } }