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>
This commit is contained in:
Dennis Oberst 2023-05-25 12:51:19 +02:00 committed by Marc Mutz
parent ef1be84551
commit 54d8d8055e
3 changed files with 154 additions and 0 deletions

View File

@ -3309,6 +3309,52 @@ QString &QString::append(QChar ch)
Prepends the character \a ch to this string.
*/
/*!
\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)

View File

@ -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); }

View File

@ -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;