QString: optimize insert(qsizetype, QUtf8StringView)

Utf8 data is variable-width, ideally we want to write characters at most
once, so insert directly into the QString buffer if inserting at the end
(by delegating to append(QUtf8SV)), and use an intermediate buffer to
hold the converted data before inserting anywhere else.

Task-number: QTBUG-108546
Change-Id: Iabfaeecaf34a1ba11946bd67951e69a45d954d6d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ahmad Samir 2022-12-11 15:31:33 +02:00
parent cc6324665e
commit 5f73f48556
2 changed files with 30 additions and 2 deletions

View File

@ -2939,7 +2939,9 @@ QString &QString::operator=(QChar ch)
defined.
*/
/*! \internal
T is a view or a container on/of QChar, char16_t, or char
*/
template <typename T>
static void insert_helper(QString &str, qsizetype i, T toInsert)
{
@ -3021,7 +3023,32 @@ QString &QString::insert(qsizetype i, QLatin1StringView str)
*/
QString &QString::insert(qsizetype i, QUtf8StringView s)
{
return insert(i, s.toString()); // ### optimize (QTBUG-108546)
auto insert_size = s.size();
if (i < 0 || insert_size <= 0)
return *this;
qsizetype difference = 0;
if (Q_UNLIKELY(i > d.size))
difference = i - d.size;
if (i >= d.size) {
d.detachAndGrow(QArrayData::GrowsAtEnd, difference + insert_size, nullptr, nullptr);
Q_CHECK_PTR(d.data());
if (difference > 0)
resize(i, u' ');
append(s);
} else {
// Optimal insertion of Utf8 data is at the end, anywhere else could
// potentially lead to moving characters twice if Utf8 data size
// (variable-width) is less than the equiavalent Utf16 data size
QVarLengthArray<char16_t> buffer(insert_size); // ### optimize (QTBUG-108546)
char16_t *b = QUtf8::convertToUnicode(buffer.data(), s);
buffer.resize(std::distance(buffer.begin(), b));
insert_helper(*this, i, buffer);
}
return *this;
}
/*!

View File

@ -2803,6 +2803,7 @@ void tst_QString::insert_data(DataOptions options)
QTest::newRow("a.insert(1, ba)") << a << baC << 1 << (a + ba);
QTest::newRow("ba.insert(1, a)") << ba << aC << 1 << (ba + a);
QTest::newRow("ba.insert(2, b)") << ba << bC << 2 << (ba + b);
QTest::newRow("ba.insert(10, b)") << ba << bC << 10 << (ba + QString(10 - ba.size(), u' ') + b);
QTest::newRow("null-insert-0-yumlaut") << null << yumlautC << 0 << yumlaut;
QTest::newRow("empty-insert-0-yumlaut") << empty << yumlautC << 0 << yumlaut;