diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index b8026fded82..286af51209f 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -2873,16 +2873,7 @@ QString &QString::operator=(QLatin1StringView other) */ QString &QString::operator=(QChar ch) { - const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin(); - if (isDetached() && capacityAtEnd >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull) - // re-use existing capacity: - d.data()[0] = ch.unicode(); - d.data()[1] = 0; - d.size = 1; - } else { - operator=(QString(ch)); - } - return *this; + return assign(1, ch); } /*! diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index b2344f94f32..cc49eb27169 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -786,10 +786,21 @@ public: : QString(fromUtf8(a)) {} QT_ASCII_CAST_WARN inline QString &operator=(const char *ch) - { return (*this = fromUtf8(ch)); } + { + if (!ch) { + clear(); + return *this; + } + return assign(ch); + } QT_ASCII_CAST_WARN inline QString &operator=(const QByteArray &a) - { return (*this = fromUtf8(a)); } - + { + if (a.isNull()) { + clear(); + return *this; + } + return assign(a); + } // these are needed, so it compiles with STL support enabled QT_ASCII_CAST_WARN inline QString &prepend(const char *s) { return prepend(QUtf8StringView(s)); } diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 0f1c5083353..2d03fb9d7c6 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -486,6 +486,7 @@ private slots: void operator_pluseq_qbytearray_data() { operator_pluseq_data(); } void operator_pluseq_charstar() { operator_pluseq_impl(); } void operator_pluseq_charstar_data() { operator_pluseq_data(); } + void operator_assign_symmetry(); #endif // !defined(QT_RESTRICTED_CAST_FROM_ASCII) && !defined(QT_NO_CAST_FROM_ASCII) void operator_pluseq_special_cases(); @@ -3706,6 +3707,29 @@ void tst_QString::operator_eqeq_bytearray() QVERIFY(!(expected != src.constData())); } } + +void tst_QString::operator_assign_symmetry() +{ + { + QString str("DATA"); + str.operator=(QString()); + QCOMPARE_EQ(str.capacity(), 0); + QVERIFY(str.isNull()); + } + { + QString str("DATA"); + str.operator=(QByteArray()); + QCOMPARE_EQ(str.capacity(), 0); + QVERIFY(str.isNull()); + } + { + QString str("DATA"); + const char *data = nullptr; + str.operator=(data); + QCOMPARE_EQ(str.capacity(), 0); + QVERIFY(str.isNull()); + } +} #endif // !defined(QT_RESTRICTED_CAST_FROM_ASCII) && !defined(QT_NO_CAST_FROM_ASCII) void tst_QString::swap() @@ -8552,12 +8576,14 @@ void tst_QString::assignQChar() // assign to null QString: s = sp; QCOMPARE(s, QString(sp)); - QCOMPARE(s.capacity(), 1); // assign to non-null QString with enough capacity: + s.clear(); + s.squeeze(); + s.reserve(3); s = QLatin1String("foo"); const int capacity = s.capacity(); - QCOMPARE(capacity, 3); + QCOMPARE(s.capacity(), 3); s = sp; QCOMPARE(s, QString(sp)); QCOMPARE(s.capacity(), capacity); @@ -8567,7 +8593,6 @@ void tst_QString::assignQChar() QString s2 = s; s = sp; QCOMPARE(s, QString(sp)); - QCOMPARE(s.capacity(), 1); // assign to empty QString: s = QString(u""_s); @@ -8575,7 +8600,6 @@ void tst_QString::assignQChar() QCOMPARE(s.capacity(), 0); s = sp; QCOMPARE(s, QString(sp)); - QCOMPARE(s.capacity(), 1); } void tst_QString::isRightToLeft_data() diff --git a/tests/benchmarks/corelib/text/qstring/tst_bench_qstring.cpp b/tests/benchmarks/corelib/text/qstring/tst_bench_qstring.cpp index 4d2eaafd288..a4412727ccb 100644 --- a/tests/benchmarks/corelib/text/qstring/tst_bench_qstring.cpp +++ b/tests/benchmarks/corelib/text/qstring/tst_bench_qstring.cpp @@ -1,6 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include +#include +#include #include #include #include @@ -43,10 +45,22 @@ private slots: void toDouble_data(); void toDouble(); + // operator=(~) +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) + void operator_assign_BA() { operator_assign(); } + void operator_assign_BA_data() { operator_assign_data(); } + void operator_assign_char() { operator_assign(); }; + void operator_assign_char_data() { operator_assign_data();} +#endif + void operator_assign_L1SV() { operator_assign(); } + void operator_assign_L1SV_data() { operator_assign_data(); } + private: void section_data_impl(bool includeRegExOnly = true); template void section_impl(); template void number_impl(); + template void operator_assign(); + void operator_assign_data(); }; tst_QString::tst_QString() @@ -450,6 +464,47 @@ void tst_QString::toDouble() QCOMPARE(actual, expected); } +template void tst_QString::operator_assign() +{ + QFETCH(QByteArray, data); + QString str(data.size(), Qt::Uninitialized); + + T tdata; + if constexpr (std::is_same_v) { + tdata = data.constData(); + } else if constexpr (std::is_same_v) { + tdata = T(data.constData(), data.size()); + } else { + tdata = T(data.constData(), data.size()); + tdata.detach(); + } + + QBENCHMARK { + str.operator=(tdata); + } +} + +void tst_QString::operator_assign_data() +{ + QTest::addColumn("data"); + + QByteArray data; + data.fill('a', 5); + QTest::newRow("length: 5") << data; + data.fill('b', 10); + QTest::newRow("length: 10") << data; + data.fill('c', 20); + QTest::newRow("length: 20") << data; + data.fill('d', 50); + QTest::newRow("length: 50") << data; + data.fill('e', 100); + QTest::newRow("length: 100") << data; + data.fill('f', 500); + QTest::newRow("length: 500") << data; + data.fill('g', 1'000); + QTest::newRow("length: 1'000") << data; +} + QTEST_APPLESS_MAIN(tst_QString) #include "tst_bench_qstring.moc"