summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/text/qbytearray.h8
-rw-r--r--src/corelib/text/qstring.cpp34
-rw-r--r--src/corelib/tools/qarraydatapointer.h22
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.