diff options
author | Dennis Oberst <dennis.oberst@qt.io> | 2023-05-25 12:51:19 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2023-06-04 06:33:12 +0000 |
commit | 54d8d8055edafcd571fe190eb6077d14a6ff8ce1 (patch) | |
tree | c3f60a331e5c05fc67af902c0ea041c2d9da15cd | |
parent | ef1be84551ae1e131dbee8212fd1bd6064e889da (diff) |
QString: add STL-style assign() [1/4]: non-(it,it) overloads
Implemented assign() methods for QString to align with the
criteria of std::basic_string, addressing the previously missing
functionality. This is a subset of the overloads provided by the
standard.
Reference:
https://en.cppreference.com/w/cpp/string/basic_string/assign
The assign(it, it) overload is a bit more complicated and will be
added in follow-up patches.
[ChangeLog][QtCore][QString] Added assign().
Task-number: QTBUG-106198
Change-Id: Ia1481d184865f46db872cf94c266fef83b962351
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
-rw-r--r-- | src/corelib/text/qstring.cpp | 46 | ||||
-rw-r--r-- | src/corelib/text/qstring.h | 10 | ||||
-rw-r--r-- | tests/auto/corelib/text/qstring/tst_qstring.cpp | 98 |
3 files changed, 154 insertions, 0 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index b6b6f3c8a1..de1409960a 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -3310,6 +3310,52 @@ QString &QString::append(QChar ch) */ /*! + \fn QString &QString::assign(QAnyStringView v) + \since 6.6 + + Replaces the contents of this string with a copy of \a v and returns a + reference to this string. + + The size of this string will be equal to the size of \a v, converted to + UTF-16 as if by \c{v.toString()}. Unlike QAnyStringView::toString(), however, + this function only allocates memory if the estimated size exceeds the capacity + of this string or this string is shared. + + \sa QAnyStringView::toString() +*/ + +/*! + \fn QString &QString::assign(qsizetype n, QChar c) + \since 6.6 + + Replaces the contents of this string with \a n copies of \a c and + returns a reference to this string. + + The size of this string will be equal to \a n, which has to be non-negative. + + This function will only allocate memory if \a n exceeds the capacity of this + string or this string is shared. + + \sa fill() +*/ + +QString &QString::assign(QAnyStringView s) +{ + if (s.size() <= capacity() && isDetached()) { + const auto offset = d.freeSpaceAtBegin(); + if (offset) + d.setBegin(d.begin() - offset); + resize(0); + s.visit([this](auto input) { + this->append(input); + }); + } else { + *this = s.toString(); + } + return *this; +} + +/*! \fn QString &QString::remove(qsizetype position, qsizetype n) Removes \a n characters from the string, starting at the given \a diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 62eb64d775..71b712c3e9 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -36,6 +36,8 @@ Q_FORWARD_DECLARE_CF_TYPE(CFString); Q_FORWARD_DECLARE_OBJC_CLASS(NSString); #endif +class tst_QString; + QT_BEGIN_NAMESPACE class QRegularExpression; @@ -116,6 +118,8 @@ constexpr QChar QAnyStringView::back() const class Q_CORE_EXPORT QString { typedef QTypedArrayData<char16_t> Data; + + friend class ::tst_QString; public: typedef QStringPrivate DataPointer; @@ -375,6 +379,12 @@ public: inline QString &prepend(QLatin1StringView s) { return insert(0, s); } QString &prepend(QUtf8StringView s) { return insert(0, s); } + QString &assign(QAnyStringView s); + inline QString &assign(qsizetype n, QChar c) + { + Q_ASSERT(n >= 0); + return fill(c, n); + } inline QString &operator+=(QChar c) { return append(c); } inline QString &operator+=(const QString &s) { return append(s); } diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 957fb35f87..a99b354b95 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -526,6 +526,10 @@ private slots: void insert_special_cases(); + void assign(); + void assign_shared(); + void assign_uses_prepend_buffer(); + void simplified_data(); void simplified(); void trimmed(); @@ -3386,6 +3390,100 @@ void tst_QString::append_bytearray_special_cases() } #endif // !defined(QT_RESTRICTED_CAST_FROM_ASCII) && !defined(QT_NO_CAST_FROM_ASCII) +void tst_QString::assign() +{ + // QString &assign(QAnyStringView) + { + QString str; + QCOMPARE(str.assign("data"), u"data"); + QCOMPARE(str.size(), 4); + QCOMPARE(str.assign(u8"data\0data"), u"data\0data"); + QCOMPARE(str.size(), 4); + QCOMPARE(str.assign(u"\0data\0data"), u"\0data\0data"); + QCOMPARE(str.size(), 0); + QCOMPARE(str.assign(QAnyStringView("data\0")), u"data\0"); + QCOMPARE(str.size(), 4); + QCOMPARE(str.assign(QStringView(u"(ノಠ益ಠ)ノ彡┻━┻\0")), u"(ノಠ益ಠ)ノ彡┻━┻\0"); + QCOMPARE(str.size(), 11); + QCOMPARE(str.assign(QUtf8StringView(u8"٩(⁎❛ᴗ❛⁎)۶")), u"٩(⁎❛ᴗ❛⁎)۶"); + QCOMPARE(str.size(), 9); + QCOMPARE(str.assign(QLatin1String("datadata")), u"datadata"); + QCOMPARE(str.size(), 8); + } + // QString &assign(qsizetype, char); + { + QString str; + QCOMPARE(str.assign(3, u'è'), u"èèè"); + QCOMPARE(str.size(), 3); + QCOMPARE(str.assign(20, u'd').assign(2, u'ᴗ'), u"ᴗᴗ"); + QCOMPARE(str.size(), 2); + QCOMPARE(str.assign(0, u'x').assign(5, QLatin1Char('d')), u"ddddd"); + QCOMPARE(str.size(), 5); + QCOMPARE(str.assign(3, u'x'), u"xxx"); + QCOMPARE(str.size(), 3); + } + // Test chaining + { + QString str; + QCOMPARE(str.assign(300, u'T').assign({"[̲̅$̲̅(̲̅5̲̅)̲̅$̲̅]"}), u"[̲̅$̲̅(̲̅5̲̅)̲̅$̲̅]"); + QCOMPARE(str.size(), 19); + QCOMPARE(str.assign("data").assign(QByteArrayView::fromArray( + {std::byte('T'), std::byte('T'), std::byte('T')})), u"TTT"); + QCOMPARE(str.size(), 3); + QCOMPARE(str.assign("data").assign("\0data"), u"\0data"); + QCOMPARE(str.size(), 0); + } +} + +void tst_QString::assign_shared() +{ + { + QString str = "DATA"_L1; + QVERIFY(str.isDetached()); + auto strCopy = str; + QVERIFY(!str.isDetached()); + QVERIFY(!strCopy.isDetached()); + QVERIFY(str.isSharedWith(strCopy)); + QVERIFY(strCopy.isSharedWith(str)); + + str.assign(4, u'D'); + QVERIFY(str.isDetached()); + QVERIFY(strCopy.isDetached()); + QVERIFY(!str.isSharedWith(strCopy)); + QVERIFY(!strCopy.isSharedWith(str)); + QCOMPARE(str, u"DDDD"); + QCOMPARE(strCopy, u"DATA"); + } +} + +void tst_QString::assign_uses_prepend_buffer() +{ + const auto capBegin = [](const QString &s) { + return s.begin() - s.d.freeSpaceAtBegin(); + }; + const auto capEnd = [](const QString &s) { + return s.end() + s.d.freeSpaceAtEnd(); + }; + // QString &assign(QAnyStringView) + { + QString withFreeSpaceAtBegin; + for (int i = 0; i < 100 && withFreeSpaceAtBegin.d.freeSpaceAtBegin() < 2; ++i) + withFreeSpaceAtBegin.prepend(u'd'); + QCOMPARE_GT(withFreeSpaceAtBegin.d.freeSpaceAtBegin(), 1); + + const auto oldCapBegin = capBegin(withFreeSpaceAtBegin); + const auto oldCapEnd = capEnd(withFreeSpaceAtBegin); + + QString test(withFreeSpaceAtBegin.d.freeSpaceAtBegin(), u'ȍ'); + withFreeSpaceAtBegin.assign(test); + + QCOMPARE_EQ(withFreeSpaceAtBegin.d.freeSpaceAtBegin(), 0); // we used the prepend buffer + QCOMPARE_EQ(capBegin(withFreeSpaceAtBegin), oldCapBegin); + QCOMPARE_EQ(capEnd(withFreeSpaceAtBegin), oldCapEnd); + QCOMPARE(withFreeSpaceAtBegin, test); + } +} + void tst_QString::operator_pluseq_special_cases() { QString a; |