diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 3ae6404ed4..4ca66a2634 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -290,6 +290,26 @@ bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) return QtPrivate::compareStrings(haystack.right(needleLen), needle, cs) == 0; } + +template +static void append_helper(QString &self, T view, F appendToUtf16) +{ + const auto strData = view.data(); + const qsizetype strSize = view.size(); + auto &d = self.data_ptr(); + if (strData && strSize > 0) { + // the number of UTF-8 code units is always at a minimum equal to the number + // of equivalent UTF-16 code units + d.detachAndGrow(QArrayData::GrowsAtEnd, strSize, nullptr, nullptr); + Q_CHECK_PTR(d.data()); + Q_ASSERT(strSize <= d.freeSpaceAtEnd()); + const auto newEnd = appendToUtf16(self.data() + self.size(), view); + self.resize(newEnd - std::as_const(self).data()); + } else if (d.isNull() && !view.isNull()) { // special case + self = QLatin1StringView(""); + } +} + } // unnamed namespace /* @@ -3125,23 +3145,35 @@ QString &QString::append(const QChar *str, qsizetype len) /*! \overload append() - Appends the Latin-1 string \a str to this string. + Appends the Latin-1 string view \a str to this string. */ QString &QString::append(QLatin1StringView str) { - const char *s = str.latin1(); - const qsizetype len = str.size(); - if (s && len > 0) { - d.detachAndGrow(Data::GrowsAtEnd, len, nullptr, nullptr); - Q_CHECK_PTR(d.data()); - Q_ASSERT(len <= d->freeSpaceAtEnd()); - char16_t *i = d.data() + d.size; + auto appendUtf16 = [](QChar *dst, QLatin1StringView str) { + const qsizetype len = str.size(); + const char *s = str.latin1(); + char16_t *i = reinterpret_cast(dst); qt_from_latin1(i, s, size_t(len)); - d.size += len; - d.data()[d.size] = '\0'; - } else if (d.isNull() && !str.isNull()) { // special case - d = DataPointer::fromRawData(&_empty, 0); - } + return dst + len; + }; + + append_helper(*this, str, appendUtf16); + return *this; +} + +/*! + \overload append() + \since 6.5 + + Appends the UTF-8 string view \a str to this string. +*/ +QString &QString::append(QUtf8StringView str) +{ + auto appendUtf16 = [](QChar *dst, QUtf8StringView str) { + return QUtf8::convertToUnicode(dst, str); + }; + + append_helper(*this, str, appendUtf16); return *this; } diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 32847e30f6..74dcf3986a 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -693,6 +693,7 @@ public: QString &append(const QString &s); inline QString &append(QStringView v) { return append(v.data(), v.size()); } QString &append(QLatin1StringView s); + QString &append(QUtf8StringView s); inline QString &prepend(QChar c) { return insert(0, c); } inline QString &prepend(const QChar *uc, qsizetype len) { return insert(0, uc, len); } diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 86c012882e..35596976f9 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -150,6 +150,22 @@ public: { (s.*mf)(a1, l1); } }; +template +class Arg> +{ + QUtf8StringView u8; +public: + explicit Arg(const char *str) : u8(str) {} + + template + void apply0(QString &s, MemFunc mf) const + { (s.*mf)(u8); } + + template + void apply1(QString &s, MemFunc mf, A1 a1) const + { (s.*mf)(a1, u8); } +}; + template <> class Arg { @@ -402,6 +418,8 @@ private slots: void append_qstringview_data() { append_data(EmptyIsNoop); } void append_qlatin1string() { append_impl(); } void append_qlatin1string_data() { append_data(Latin1Encoded); } + void append_qutf8stringview() { append_impl(); } + void append_qutf8stringview_data() { append_data(); } void append_qcharstar_int() { append_impl, QString&(QString::*)(const QChar *, qsizetype)>(); } void append_qcharstar_int_data() { append_data(EmptyIsNoop); } void append_qchar() { append_impl(); }