diff options
author | Andrei Golubev <andrei.golubev@qt.io> | 2020-08-27 22:10:53 +0200 |
---|---|---|
committer | Andrei Golubev <andrei.golubev@qt.io> | 2020-09-10 17:31:23 +0200 |
commit | ec7e680c5007345c34542a57bd2ac344fb112063 (patch) | |
tree | d246b9bb323acaf844a650dae6929d27fa68f386 /src | |
parent | 04d78df344c341b6a13d4cbe0162ed20e828c88a (diff) |
Remove '\0' space reservation logic in QString
Changed QString to use implicit element reserved by QArrayData
Task-number: QTBUG-84320
Change-Id: If517500b3f0e71bb8d2989c64815a634aa8dd554
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/text/qstring.cpp | 50 | ||||
-rw-r--r-- | src/corelib/text/qstring.h | 25 |
2 files changed, 43 insertions, 32 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index dd1b57dbf3..263dd0f302 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -2232,7 +2232,7 @@ QString::QString(const QChar *unicode, qsizetype size) if (!size) { d = DataPointer::fromRawData(&_empty, 0); } else { - d = DataPointer(Data::allocate(size + 1), size); + d = DataPointer(Data::allocate(size), size); memcpy(d.data(), unicode, size * sizeof(QChar)); d.data()[size] = '\0'; } @@ -2250,7 +2250,7 @@ QString::QString(qsizetype size, QChar ch) if (size <= 0) { d = DataPointer::fromRawData(&_empty, 0); } else { - d = DataPointer(Data::allocate(size + 1), size); + d = DataPointer(Data::allocate(size), size); d.data()[size] = '\0'; char16_t *i = d.data() + size; char16_t *b = d.data(); @@ -2268,8 +2268,12 @@ QString::QString(qsizetype size, QChar ch) */ QString::QString(qsizetype size, Qt::Initialization) { - d = DataPointer(Data::allocate(size + 1), size); - d.data()[size] = '\0'; + if (size <= 0) { + d = DataPointer::fromRawData(&_empty, 0); + } else { + d = DataPointer(Data::allocate(size), size); + d.data()[size] = '\0'; + } } /*! \fn QString::QString(QLatin1String str) @@ -2284,7 +2288,7 @@ QString::QString(qsizetype size, Qt::Initialization) */ QString::QString(QChar ch) { - d = DataPointer(Data::allocate(2), 1); + d = DataPointer(Data::allocate(1), 1); d.data()[0] = ch.unicode(); d.data()[1] = '\0'; } @@ -2380,7 +2384,7 @@ void QString::resize(qsizetype size) const auto capacityAtEnd = capacity() - d.freeSpaceAtBegin(); if (d->needsDetach() || size > capacityAtEnd) - reallocData(size_t(size) + 1u, d->detachFlags() | Data::GrowsForward); + reallocData(size_t(size), d->detachFlags() | Data::GrowsForward); d.size = size; if (d->allocatedCapacity()) d.data()[size] = 0; @@ -2460,13 +2464,18 @@ void QString::resize(qsizetype size, QChar fillChar) void QString::reallocData(size_t alloc, Data::ArrayOptions allocOptions) { + if (!alloc) { + d = DataPointer::fromRawData(&_empty, 0); + return; + } + // there's a case of slow reallocate path where we need to memmove the data // before a call to ::realloc(), meaning that there's an extra "heavy" // operation. just prefer ::malloc() branch in this case const bool slowReallocatePath = d.freeSpaceAtBegin() > 0; if (d->needsDetach() || slowReallocatePath) { - DataPointer dd(Data::allocate(alloc, allocOptions), qMin(qsizetype(alloc) - 1, d.size)); + DataPointer dd(Data::allocate(alloc, allocOptions), qMin(qsizetype(alloc), d.size)); if (dd.size > 0) ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar)); dd.data()[dd.size] = 0; @@ -2478,8 +2487,11 @@ void QString::reallocData(size_t alloc, Data::ArrayOptions allocOptions) void QString::reallocGrowData(size_t alloc, Data::ArrayOptions options) { + if (!alloc) // expected to always allocate + alloc = 1; + if (d->needsDetach()) { - const auto newSize = qMin(qsizetype(alloc) - 1, d.size); + const auto newSize = qMin(qsizetype(alloc), d.size); DataPointer dd(DataPointer::allocateGrow(d, alloc, newSize, options)); dd->copyAppend(d.data(), d.data() + newSize); dd.data()[dd.size] = 0; @@ -2695,7 +2707,7 @@ QString& QString::insert(qsizetype i, const QChar *unicode, qsizetype size) // ### optimize me if (d->needsDetach() || newSize > capacity() || shouldGrow) - reallocGrowData(newSize + 1, flags); + reallocGrowData(newSize, flags); if (i > oldSize) // set spaces in the uninitialized gap d->copyAppend(i - oldSize, u' '); @@ -2729,7 +2741,7 @@ QString& QString::insert(qsizetype i, QChar ch) // ### optimize me if (d->needsDetach() || newSize > capacity() || shouldGrow) - reallocGrowData(newSize + 1, flags); + reallocGrowData(newSize, flags); if (i > oldSize) // set spaces in the uninitialized gap d->copyAppend(i - oldSize, u' '); @@ -2765,7 +2777,7 @@ QString &QString::append(const QString &str) } else { const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), str.d.size); if (d->needsDetach() || size() + str.size() > capacity() || shouldGrow) - reallocGrowData(uint(size() + str.size()) + 1u, + reallocGrowData(uint(size() + str.size()), d->detachFlags() | Data::GrowsForward); d->copyAppend(str.d.data(), str.d.data() + str.d.size); d.data()[d.size] = '\0'; @@ -2785,7 +2797,7 @@ QString &QString::append(const QChar *str, qsizetype len) if (str && len > 0) { const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), len); if (d->needsDetach() || size() + len > capacity() || shouldGrow) - reallocGrowData(uint(size() + len) + 1u, d->detachFlags() | Data::GrowsForward); + reallocGrowData(uint(size() + len), d->detachFlags() | Data::GrowsForward); static_assert(sizeof(QChar) == sizeof(char16_t), "Unexpected difference in sizes"); // the following should be safe as QChar uses char16_t as underlying data const char16_t *char16String = reinterpret_cast<const char16_t *>(str); @@ -2807,7 +2819,7 @@ QString &QString::append(QLatin1String str) qsizetype len = str.size(); const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), len); if (d->needsDetach() || size() + len > capacity() || shouldGrow) - reallocGrowData(size_t(size() + len) + 1u, d->detachFlags() | Data::GrowsForward); + reallocGrowData(size_t(size() + len), d->detachFlags() | Data::GrowsForward); if (d.freeSpaceAtBegin() == 0) { // fast path char16_t *i = d.data() + d.size; @@ -2860,7 +2872,7 @@ QString &QString::append(QChar ch) { const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), 1); if (d->needsDetach() || size() + 1 > capacity() || shouldGrow) - reallocGrowData(d.size + 2u, d->detachFlags() | Data::GrowsForward); + reallocGrowData(d.size + 1u, d->detachFlags() | Data::GrowsForward); d->copyAppend(1, ch.unicode()); d.data()[d.size] = '\0'; return *this; @@ -2963,8 +2975,9 @@ QString &QString::remove(qsizetype pos, qsizetype len) } else if (len > 0) { detach(); memmove(d.data() + pos, d.data() + pos + len, - (d.size - pos - len + 1) * sizeof(QChar)); + (d.size - pos - len) * sizeof(QChar)); d.size -= len; + d.data()[d.size] = '\0'; } return *this; } @@ -3998,7 +4011,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) if (!iterator.hasNext()) // no matches at all return *this; - reallocData(size_t(d.size) + 1u, d->detachFlags()); + reallocData(size_t(d.size), d->detachFlags()); qsizetype numCaptures = re.captureCount(); @@ -5105,10 +5118,9 @@ QString::DataPointer QString::fromLatin1_helper(const char *str, qsizetype size) } else { if (size < 0) size = qstrlen(str); - d = DataPointer(Data::allocate(size + 1), size); + d = DataPointer(Data::allocate(size), size); d.data()[size] = '\0'; char16_t *dst = d.data(); - qt_from_latin1(dst, str, size_t(size)); } return d; @@ -6089,7 +6101,7 @@ const ushort *QString::utf16() const { if (!d->isMutable()) { // ensure '\0'-termination for ::fromRawData strings - const_cast<QString*>(this)->reallocData(size_t(d.size) + 1u, d->detachFlags()); + const_cast<QString*>(this)->reallocData(size_t(d.size), d->detachFlags()); } return reinterpret_cast<const ushort *>(d.data()); } diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index d86d659e75..62826d67e2 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1094,15 +1094,14 @@ inline QChar *QString::data() inline const QChar *QString::constData() const { return data(); } inline void QString::detach() -{ if (d->needsDetach()) reallocData(d.size + 1u, d->detachFlags()); } +{ if (d->needsDetach()) reallocData(d.size, d->detachFlags()); } inline bool QString::isDetached() const { return !d->isShared(); } inline void QString::clear() { if (!isNull()) *this = QString(); } inline QString::QString(const QString &other) noexcept : d(other.d) { } -inline qsizetype QString::capacity() const -{ const auto realCapacity = d->constAllocatedCapacity(); return realCapacity ? int(realCapacity) - 1 : 0; } +inline qsizetype QString::capacity() const { return qsizetype(d->constAllocatedCapacity()); } inline QString &QString::setNum(short n, int base) { return setNum(qlonglong(n), base); } inline QString &QString::setNum(ushort n, int base) @@ -1167,22 +1166,22 @@ inline QString::~QString() {} inline void QString::reserve(qsizetype asize) { - if (d->needsDetach() || asize >= capacity() - d.freeSpaceAtBegin()) - reallocData(uint(qMax(asize, size())) + 1u, d->detachFlags()); - - // we're not shared anymore, for sure - d->setFlag(Data::CapacityReserved); + if (d->needsDetach() || asize >= capacity() - d.freeSpaceAtBegin()) { + reallocData(size_t(qMax(asize, size())), d->detachFlags() | Data::CapacityReserved); + } else { + d->setFlag(Data::CapacityReserved); + } } inline void QString::squeeze() { if ((d->flags() & Data::CapacityReserved) == 0) return; - if (d->needsDetach() || int(d.size) < capacity()) - reallocData(uint(d.size) + 1u, d->detachFlags()); - - // we're not shared anymore, for sure - d->clearFlag(Data::CapacityReserved); + if (d->needsDetach() || int(d.size) < capacity()) { + reallocData(size_t(d.size), d->detachFlags() & ~Data::CapacityReserved); + } else { + d->clearFlag(Data::CapacityReserved); + } } inline QString &QString::setUtf16(const ushort *autf16, qsizetype asize) |