diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/text/qbytearray.h | 8 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 34 | ||||
-rw-r--r-- | src/corelib/tools/qarraydatapointer.h | 22 |
3 files changed, 43 insertions, 21 deletions
diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 8989eb27a6..dbbbd2f178 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -473,10 +473,10 @@ public: bool isNull() const noexcept; inline DataPointer &data_ptr() { return d; } - explicit inline QByteArray(const DataPointer &dd) - : d(dd) - { - } +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + explicit inline QByteArray(const DataPointer &dd) : d(dd) {} +#endif + explicit inline QByteArray(DataPointer &&dd) : d(std::move(dd)) {} private: void reallocData(qsizetype alloc, QArrayData::AllocationOption option); diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 23927b0e84..57bed1240f 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -5269,6 +5269,7 @@ QByteArray QtPrivate::convertToLatin1(QStringView string) return qt_convert_to_latin1(string); } +Q_NEVER_INLINE static QByteArray qt_convert_to_latin1(QStringView string) { if (Q_UNLIKELY(string.isNull())) @@ -5290,27 +5291,26 @@ QByteArray QString::toLatin1_helper_inplace(QString &s) // We can return our own buffer to the caller. // Conversion to Latin-1 always shrinks the buffer by half. - const char16_t *data = s.d.data(); - qsizetype length = s.d.size; - - // Move the d pointer over to the bytearray. - // Kids, avert your eyes. Don't try this at home. + // This relies on the fact that we use QArrayData for everything behind the scenes - // this relies on the fact that we use QArrayData for everything behind the scenes which has the same layout - static_assert(sizeof(QByteArray::DataPointer) == sizeof(QString::DataPointer), "sizes have to be equal"); - QByteArray::DataPointer ba_d(reinterpret_cast<QByteArray::Data *>(s.d.d_ptr()), reinterpret_cast<char *>(s.d.data()), length); - ba_d.ref(); - s.clear(); + // First, do the in-place conversion. Since isDetached() == true, the data + // was allocated by QArrayData, so the null terminator must be there. + qsizetype length = s.size(); + char16_t *sdata = s.d->data(); + Q_ASSERT(sdata[length] == u'\0'); + qt_to_latin1(reinterpret_cast<uchar *>(sdata), sdata, length + 1); - char *ddata = ba_d.data(); + // Move the internals over to the byte array. + // Kids, avert your eyes. Don't try this at home. + auto ba_d = std::move(s.d).reinterpreted<char>(); - // multiply the allocated capacity by sizeof(char16_t) - ba_d.d_ptr()->alloc *= sizeof(char16_t); + // Some sanity checks + Q_ASSERT(ba_d.d->allocatedCapacity() >= ba_d.size); + Q_ASSERT(s.isNull()); + Q_ASSERT(s.isEmpty()); + Q_ASSERT(s.constData() == QString().constData()); - // do the in-place conversion - qt_to_latin1(reinterpret_cast<uchar *>(ddata), data, length); - ddata[length] = '\0'; - return QByteArray(ba_d); + return QByteArray(std::move(ba_d)); } /*! diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index 4d83b890cc..dda3cf13eb 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -168,6 +168,28 @@ public: /*! \internal + Reinterprets the data of this QArrayDataPointer to type X. It's the + caller's responsibility to ensure that the data contents are valid and + properly aligned, particularly if T and X are not trivial types (i.e, + don't do that). The current size is kept and the allocated capacity is + updated to account for the difference in the element type's size. + + This is used in QString::fromLatin1 to perform in-place conversion of + QString to QByteArray. + */ + template <typename X> QArrayDataPointer<X> reinterpreted() && + { + if (sizeof(T) != sizeof(X)) { + Q_ASSERT(!d->isShared()); + d->alloc = d->alloc * sizeof(T) / sizeof(X); + } + auto od = reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d, nullptr)); + auto optr = reinterpret_cast<X *>(std::exchange(ptr, nullptr)); + return { od, optr, std::exchange(size, 0) }; + } + + /*! \internal + Detaches this (optionally) and grows to accommodate the free space for \a n elements at the required side. The side is determined from \a pos. |