From 6de49f4ab6e6c8c6e664f7dd6c8c441bf7685a56 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 11 Oct 2015 15:01:06 +0200 Subject: QString: where possible, re-use existing capacity in op(QChar/QL1S) If the LHS is detached and has existing capacity that is large enough to hold the RHS, re-use the memory instead of allocating a new buffer and throwing away the old. Change-Id: I53d42825da92c264c7301e8e771cba9fb35c321b Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 22 +++++++- src/corelib/tools/qstring.h | 7 +-- tests/auto/corelib/tools/qstring/tst_qstring.cpp | 66 ++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index d1b5327f5c..71d0be1dcf 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1818,6 +1818,17 @@ QString &QString::operator=(const QString &other) Q_DECL_NOTHROW Assigns the Latin-1 string \a str to this string. */ +QString &QString::operator=(QLatin1String other) +{ + if (isDetached() && other.size() <= capacity()) { // assumes d->alloc == 0 → !isDetached() (sharedNull) + d->size = other.size(); + d->data()[other.size()] = 0; + qt_from_latin1(d->data(), other.latin1(), other.size()); + } else { + *this = fromLatin1(other.latin1(), other.size()); + } + return *this; +} /*! \fn QString &QString::operator=(const QByteArray &ba) @@ -1868,7 +1879,16 @@ QString &QString::operator=(const QString &other) Q_DECL_NOTHROW */ QString &QString::operator=(QChar ch) { - return operator=(QString(ch)); + if (isDetached() && capacity() >= 1) { // assumes d->alloc == 0 → !isDetached() (sharedNull) + // re-use existing capacity: + ushort *dat = d->data(); + dat[0] = ch.unicode(); + dat[1] = 0; + d->size = 1; + } else { + operator=(QString(ch)); + } + return *this; } /*! diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index d21708efb9..1d04bcb457 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -221,7 +221,7 @@ public: inline ~QString(); QString &operator=(QChar c); QString &operator=(const QString &) Q_DECL_NOTHROW; - inline QString &operator=(QLatin1String latin1); + QString &operator=(QLatin1String latin1); #ifdef Q_COMPILER_RVALUE_REFS inline QString(QString && other) Q_DECL_NOTHROW : d(other.d) { other.d = Data::sharedNull(); } inline QString &operator=(QString &&other) Q_DECL_NOTHROW @@ -884,11 +884,6 @@ inline void QString::detach() { if (d->ref.isShared() || (d->offset != sizeof(QStringData))) reallocData(uint(d->size) + 1u); } inline bool QString::isDetached() const { return !d->ref.isShared(); } -inline QString &QString::operator=(QLatin1String s) -{ - *this = fromLatin1(s.latin1(), s.size()); - return *this; -} inline void QString::clear() { if (!isNull()) *this = QString(); } inline QString::QString(const QString &other) Q_DECL_NOTHROW : d(other.d) diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index cc9f250be9..907dcf17e1 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -582,6 +582,7 @@ private slots: void compareQLatin1Strings(); void fromQLatin1StringWithLength(); void assignQLatin1String(); + void assignQChar(); void isRightToLeft_data(); void isRightToLeft(); void unicodeStrings(); @@ -6598,6 +6599,71 @@ void tst_QString::assignQLatin1String() QCOMPARE(foo.size(), latin1subfoo.size()); QCOMPARE(foo, QString::fromLatin1("foo")); + // check capacity re-use: + QString s; + QCOMPARE(s.capacity(), 0); + + // assign to null QString: + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), 3); + + // assign to non-null QString with enough capacity: + s = QString::fromLatin1("foofoo"); + const int capacity = s.capacity(); + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), capacity); + + // assign to shared QString (enough capacity, but can't use): + s = QString::fromLatin1("foofoo"); + QString s2 = s; + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), 3); + + // assign to QString with too little capacity: + s = QString::fromLatin1("fo"); + QCOMPARE(s.capacity(), 2); + s = latin1foo; + QCOMPARE(s, QString::fromLatin1("foo")); + QCOMPARE(s.capacity(), 3); + +} + +void tst_QString::assignQChar() +{ + const QChar sp = QLatin1Char(' '); + QString s; + QCOMPARE(s.capacity(), 0); + + // assign to null QString: + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), 1); + + // assign to non-null QString with enough capacity: + s = QLatin1String("foo"); + const int capacity = s.capacity(); + QCOMPARE(capacity, 3); + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), capacity); + + // assign to shared QString (enough capacity, but can't use): + s = QLatin1String("foo"); + QString s2 = s; + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), 1); + + // assign to empty QString: + s = QString(""); + s.detach(); + QCOMPARE(s.capacity(), 0); + s = sp; + QCOMPARE(s, QString(sp)); + QCOMPARE(s.capacity(), 1); } void tst_QString::isRightToLeft_data() -- cgit v1.2.3