Convert QString to use QArrayDataPointer

We're now using the same infrastructure for QVector,
QString and QByteArray.

This should also make it easier to remove the shared null
in a follow-up change.

Change-Id: I3aae9cf7912845cfca8e8150e9e82aa3673e3756
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Vitaly Fanaskov <vitaly.fanaskov@qt.io>
This commit is contained in:
Lars Knoll 2019-11-14 13:46:12 +01:00
parent 0915a08b33
commit 287ace562e
7 changed files with 157 additions and 227 deletions

View File

@ -63,12 +63,9 @@ QBinaryJsonValue::QBinaryJsonValue(QBinaryJsonPrivate::MutableData *data,
case QJsonValue::Double: case QJsonValue::Double:
dbl = v.toDouble(parent); dbl = v.toDouble(parent);
break; break;
case QJsonValue::String: { case QJsonValue::String:
QString s = v.toString(parent); stringData = v.toString(parent);
stringData = s.data_ptr();
stringData.d->ref();
break; break;
}
case QJsonValue::Array: case QJsonValue::Array:
case QJsonValue::Object: case QJsonValue::Object:
d = data; d = data;
@ -82,8 +79,7 @@ QBinaryJsonValue::QBinaryJsonValue(QBinaryJsonPrivate::MutableData *data,
QBinaryJsonValue::QBinaryJsonValue(QString string) QBinaryJsonValue::QBinaryJsonValue(QString string)
: d(nullptr), t(QJsonValue::String) : d(nullptr), t(QJsonValue::String)
{ {
stringData = string.data_ptr(); stringData = std::move(string);
stringData.d->ref();
} }
QBinaryJsonValue::QBinaryJsonValue(const QBinaryJsonArray &a) QBinaryJsonValue::QBinaryJsonValue(const QBinaryJsonArray &a)
@ -102,9 +98,6 @@ QBinaryJsonValue::QBinaryJsonValue(const QBinaryJsonObject &o)
QBinaryJsonValue::~QBinaryJsonValue() QBinaryJsonValue::~QBinaryJsonValue()
{ {
if (t == QJsonValue::String && !stringData.d->deref())
QTypedArrayData<ushort>::deallocate(stringData.d);
if (d && !d->ref.deref()) if (d && !d->ref.deref())
delete d; delete d;
} }
@ -135,8 +128,7 @@ QString QBinaryJsonValue::toString() const
{ {
if (t != QJsonValue::String) if (t != QJsonValue::String)
return QString(); return QString();
stringData.d->ref(); // the constructor below doesn't add a ref. return stringData;
return QString(stringData);
} }
void QBinaryJsonValue::detach() void QBinaryJsonValue::detach()

View File

@ -85,10 +85,12 @@ public:
~QBinaryJsonValue(); ~QBinaryJsonValue();
QBinaryJsonValue(QBinaryJsonValue &&other) noexcept QBinaryJsonValue(QBinaryJsonValue &&other) noexcept
: stringData(other.stringData), : ui(other.ui),
stringData(std::move(other.stringData)),
d(other.d), d(other.d),
t(other.t) t(other.t)
{ {
other.ui = 0;
other.d = nullptr; other.d = nullptr;
other.t = QJsonValue::Null; other.t = QJsonValue::Null;
} }
@ -96,6 +98,7 @@ public:
QBinaryJsonValue &operator =(QBinaryJsonValue &&other) noexcept QBinaryJsonValue &operator =(QBinaryJsonValue &&other) noexcept
{ {
qSwap(stringData, other.stringData); qSwap(stringData, other.stringData);
qSwap(ui, other.ui);
qSwap(d, other.d); qSwap(d, other.d);
qSwap(t, other.t); qSwap(t, other.t);
return *this; return *this;
@ -121,9 +124,9 @@ private:
quint64 ui; quint64 ui;
bool b; bool b;
double dbl; double dbl;
QString::DataPointer stringData;
const QBinaryJsonPrivate::Base *base; const QBinaryJsonPrivate::Base *base;
}; };
QString stringData;
QBinaryJsonPrivate::MutableData *d = nullptr; // needed for Objects and Arrays QBinaryJsonPrivate::MutableData *d = nullptr; // needed for Objects and Arrays
QJsonValue::Type t = QJsonValue::Null; QJsonValue::Type t = QJsonValue::Null;
}; };

View File

@ -2082,9 +2082,7 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
QString::QString(const QChar *unicode, int size) QString::QString(const QChar *unicode, int size)
{ {
if (!unicode) { if (!unicode) {
d.d = Data::sharedNull(); d.clear();
d.b = Data::sharedNullData();
d.size = 0;
} else { } else {
if (size < 0) { if (size < 0) {
size = 0; size = 0;
@ -2092,18 +2090,11 @@ QString::QString(const QChar *unicode, int size)
++size; ++size;
} }
if (!size) { if (!size) {
QPair<Data *, ushort *> pair = Data::allocate(0); d = DataPointer(Data::allocate(0), 0);
d.d = pair.first;
d.b = pair.second;
d.size = 0;
} else { } else {
QPair<Data *, ushort *> pair = Data::allocate(size + 1); d = DataPointer(Data::allocate(size + 1), size);
d.d = pair.first; memcpy(d.data(), unicode, size * sizeof(QChar));
d.b = pair.second; d.data()[size] = '\0';
d.size = size;
Q_CHECK_PTR(d.d);
memcpy(d.b, unicode, size * sizeof(QChar));
d.b[size] = '\0';
} }
} }
} }
@ -2117,19 +2108,12 @@ QString::QString(const QChar *unicode, int size)
QString::QString(int size, QChar ch) QString::QString(int size, QChar ch)
{ {
if (size <= 0) { if (size <= 0) {
QPair<Data *, ushort *> pair = Data::allocate(0); d = DataPointer(Data::allocate(0), 0);
d.d = pair.first;
d.b = pair.second;
d.size = 0;
} else { } else {
QPair<Data *, ushort *> pair = Data::allocate(size + 1); d = DataPointer(Data::allocate(size + 1), size);
d.d = pair.first; d.data()[size] = '\0';
d.b = pair.second; ushort *i = d.data() + size;
d.size = size; ushort *b = d.data();
Q_CHECK_PTR(d.d);
d.b[size] = '\0';
ushort *i = d.b + size;
ushort *b = d.b;
const ushort value = ch.unicode(); const ushort value = ch.unicode();
while (i != b) while (i != b)
*--i = value; *--i = value;
@ -2144,12 +2128,8 @@ QString::QString(int size, QChar ch)
*/ */
QString::QString(int size, Qt::Initialization) QString::QString(int size, Qt::Initialization)
{ {
QPair<Data *, ushort *> pair = Data::allocate(size + 1); d = DataPointer(Data::allocate(size + 1), size);
d.d = pair.first; d.data()[size] = '\0';
d.b = pair.second;
d.size = size;
Q_CHECK_PTR(d.d);
d.b[size] = '\0';
} }
/*! \fn QString::QString(QLatin1String str) /*! \fn QString::QString(QLatin1String str)
@ -2164,13 +2144,9 @@ QString::QString(int size, Qt::Initialization)
*/ */
QString::QString(QChar ch) QString::QString(QChar ch)
{ {
QPair<Data *, ushort *> pair = Data::allocate(2); d = DataPointer(Data::allocate(2), 1);
d.d = pair.first; d.data()[0] = ch.unicode();
d.b = pair.second; d.data()[1] = '\0';
d.size = 1;
Q_CHECK_PTR(d.d);
d.b[0] = ch.unicode();
d.b[1] = '\0';
} }
/*! \fn QString::QString(const QByteArray &ba) /*! \fn QString::QString(const QByteArray &ba)
@ -2262,16 +2238,16 @@ void QString::resize(int size)
if (size < 0) if (size < 0)
size = 0; size = 0;
if (!d.d->isShared() && !d.d->isMutable() && size < int(d.size)) { if (!d->isShared() && !d->isMutable() && size < int(d.size)) {
d.size = size; d.size = size;
return; return;
} }
if (d.d->needsDetach() || size > capacity()) if (d->needsDetach() || size > capacity())
reallocData(uint(size) + 1u, true); reallocData(uint(size) + 1u, true);
d.size = size; d.size = size;
if (d.d->isMutable()) { if (d->isMutable()) {
d.b[size] = '\0'; d.data()[size] = '\0';
} }
} }
@ -2291,7 +2267,7 @@ void QString::resize(int size, QChar fillChar)
resize(size); resize(size);
const int difference = length() - oldSize; const int difference = length() - oldSize;
if (difference > 0) if (difference > 0)
std::fill_n(d.b + oldSize, difference, fillChar.unicode()); std::fill_n(d.data() + oldSize, difference, fillChar.unicode());
} }
/*! \fn int QString::capacity() const /*! \fn int QString::capacity() const
@ -2346,26 +2322,17 @@ void QString::resize(int size, QChar fillChar)
void QString::reallocData(uint alloc, bool grow) void QString::reallocData(uint alloc, bool grow)
{ {
auto allocOptions = d.d->detachFlags(); auto allocOptions = d->detachFlags();
if (grow) if (grow)
allocOptions |= QArrayData::GrowsForward; allocOptions |= QArrayData::GrowsForward;
if (d.d->needsDetach()) { if (d->needsDetach()) {
QPair<Data *, ushort *> pair = Data::allocate(alloc, allocOptions); DataPointer dd(Data::allocate(alloc, allocOptions), qMin(int(alloc) - 1, d.size));
Q_CHECK_PTR(pair.first); ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar));
d.size = qMin(alloc - 1, d.size); dd.data()[dd.size] = 0;
::memcpy(pair.second, d.b, d.size * sizeof(QChar)); d = dd;
pair.second[d.size] = 0;
if (!d.d->deref())
Data::deallocate(d.d);
d.d = pair.first;
d.b = pair.second;
} else { } else {
QPair<Data *, ushort *> pair = d.reallocate(alloc, allocOptions);
Data::reallocateUnaligned(static_cast<Data *>(d.d), d.b, alloc, allocOptions);
Q_CHECK_PTR(pair.first);
d.d = pair.first;
d.b = pair.second;
} }
} }
@ -2391,9 +2358,6 @@ void QString::expand(int i)
QString &QString::operator=(const QString &other) noexcept QString &QString::operator=(const QString &other) noexcept
{ {
other.d.d->ref();
if (!d.d->deref())
Data::deallocate(d.d);
d = other.d; d = other.d;
return *this; return *this;
} }
@ -2416,8 +2380,8 @@ QString &QString::operator=(QLatin1String other)
{ {
if (isDetached() && other.size() <= capacity()) { // assumes d->alloc == 0 -> !isDetached() (sharedNull) if (isDetached() && other.size() <= capacity()) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
d.size = other.size(); d.size = other.size();
d.b[other.size()] = 0; d.data()[other.size()] = 0;
qt_from_latin1(d.b, other.latin1(), other.size()); qt_from_latin1(d.data(), other.latin1(), other.size());
} else { } else {
*this = fromLatin1(other.latin1(), other.size()); *this = fromLatin1(other.latin1(), other.size());
} }
@ -2480,8 +2444,8 @@ QString &QString::operator=(QChar ch)
{ {
if (isDetached() && capacity() >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull) if (isDetached() && capacity() >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
// re-use existing capacity: // re-use existing capacity:
d.b[0] = ch.unicode(); d.data()[0] = ch.unicode();
d.b[1] = 0; d.data()[1] = 0;
d.size = 1; d.size = 1;
} else { } else {
operator=(QString(ch)); operator=(QString(ch));
@ -2573,8 +2537,8 @@ QString &QString::insert(int i, QLatin1String str)
else else
resize(size() + len); resize(size() + len);
::memmove(d.b + i + len, d.b + i, (d.size - i - len) * sizeof(QChar)); ::memmove(d.data() + i + len, d.data() + i, (d.size - i - len) * sizeof(QChar));
qt_from_latin1(d.b + i, s, uint(len)); qt_from_latin1(d.data() + i, s, uint(len));
return *this; return *this;
} }
@ -2591,7 +2555,7 @@ QString& QString::insert(int i, const QChar *unicode, int size)
return *this; return *this;
const ushort *s = (const ushort *)unicode; const ushort *s = (const ushort *)unicode;
if (s >= d.b && s < d.b + d.size) { if (s >= d.data() && s < d.data() + d.size) {
// Part of me - take a copy // Part of me - take a copy
ushort *tmp = static_cast<ushort *>(::malloc(size * sizeof(QChar))); ushort *tmp = static_cast<ushort *>(::malloc(size * sizeof(QChar)));
Q_CHECK_PTR(tmp); Q_CHECK_PTR(tmp);
@ -2606,8 +2570,8 @@ QString& QString::insert(int i, const QChar *unicode, int size)
else else
resize(d.size + size); resize(d.size + size);
::memmove(d.b + i + size, d.b + i, (d.size - i - size) * sizeof(QChar)); ::memmove(d.data() + i + size, d.data() + i, (d.size - i - size) * sizeof(QChar));
memcpy(d.b + i, s, size * sizeof(QChar)); memcpy(d.data() + i, s, size * sizeof(QChar));
return *this; return *this;
} }
@ -2628,8 +2592,8 @@ QString& QString::insert(int i, QChar ch)
resize(i + 1, QLatin1Char(' ')); resize(i + 1, QLatin1Char(' '));
else else
resize(d.size + 1); resize(d.size + 1);
::memmove(d.b + i + 1, d.b + i, (d.size - i - 1) * sizeof(QChar)); ::memmove(d.data() + i + 1, d.data() + i, (d.size - i - 1) * sizeof(QChar));
d.b[i] = ch.unicode(); d.data()[i] = ch.unicode();
return *this; return *this;
} }
@ -2657,11 +2621,11 @@ QString &QString::append(const QString &str)
if (isNull()) { if (isNull()) {
operator=(str); operator=(str);
} else { } else {
if (d.d->needsDetach() || size() + str.size() > capacity()) if (d->needsDetach() || size() + str.size() > capacity())
reallocData(uint(size() + str.size()) + 1u, true); reallocData(uint(size() + str.size()) + 1u, true);
memcpy(d.b + d.size, str.d.b, str.d.size * sizeof(QChar)); memcpy(d.data() + d.size, str.d.data(), str.d.size * sizeof(QChar));
d.size += str.d.size; d.size += str.d.size;
d.b[d.size] = '\0'; d.data()[d.size] = '\0';
} }
} }
return *this; return *this;
@ -2676,11 +2640,11 @@ QString &QString::append(const QString &str)
QString &QString::append(const QChar *str, int len) QString &QString::append(const QChar *str, int len)
{ {
if (str && len > 0) { if (str && len > 0) {
if (d.d->needsDetach() || size() + len > capacity()) if (d->needsDetach() || size() + len > capacity())
reallocData(uint(size() + len) + 1u, true); reallocData(uint(size() + len) + 1u, true);
memcpy(d.b + d.size, str, len * sizeof(QChar)); memcpy(d.data() + d.size, str, len * sizeof(QChar));
d.size += len; d.size += len;
d.b[d.size] = '\0'; d.data()[d.size] = '\0';
} }
return *this; return *this;
} }
@ -2695,9 +2659,9 @@ QString &QString::append(QLatin1String str)
const char *s = str.latin1(); const char *s = str.latin1();
if (s) { if (s) {
int len = str.size(); int len = str.size();
if (d.d->needsDetach() || size() + len > capacity()) if (d->needsDetach() || size() + len > capacity())
reallocData(uint(size() + len) + 1u, true); reallocData(uint(size() + len) + 1u, true);
ushort *i = d.b + d.size; ushort *i = d.data() + d.size;
qt_from_latin1(i, s, uint(len)); qt_from_latin1(i, s, uint(len));
i[len] = '\0'; i[len] = '\0';
d.size += len; d.size += len;
@ -2742,10 +2706,10 @@ QString &QString::append(QLatin1String str)
*/ */
QString &QString::append(QChar ch) QString &QString::append(QChar ch)
{ {
if (d.d->needsDetach() || size() + 1 > capacity()) if (d->needsDetach() || size() + 1 > capacity())
reallocData(uint(d.size) + 2u, true); reallocData(uint(d.size) + 2u, true);
d.b[d.size++] = ch.unicode(); d.data()[d.size++] = ch.unicode();
d.b[d.size] = '\0'; d.data()[d.size] = '\0';
return *this; return *this;
} }
@ -2845,7 +2809,7 @@ QString &QString::remove(int pos, int len)
resize(pos); // truncate resize(pos); // truncate
} else if (len > 0) { } else if (len > 0) {
detach(); detach();
memmove(d.b + pos, d.b + pos + len, memmove(d.data() + pos, d.data() + pos + len,
(d.size - pos - len + 1) * sizeof(ushort)); (d.size - pos - len + 1) * sizeof(ushort));
d.size -= len; d.size -= len;
} }
@ -3062,7 +3026,7 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
// Copy after if it lies inside our own d.b area (which we could // Copy after if it lies inside our own d.b area (which we could
// possibly invalidate via a realloc or modify by replacement). // possibly invalidate via a realloc or modify by replacement).
QChar *afterBuffer = nullptr; QChar *afterBuffer = nullptr;
if (pointsIntoRange(after, d.b, d.size)) // Use copy in place of vulnerable original: if (pointsIntoRange(after, d.data(), d.size)) // Use copy in place of vulnerable original:
after = afterBuffer = textCopy(after, alen); after = afterBuffer = textCopy(after, alen);
QT_TRY { QT_TRY {
@ -3070,30 +3034,30 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
// replace in place // replace in place
detach(); detach();
for (int i = 0; i < nIndices; ++i) for (int i = 0; i < nIndices; ++i)
memcpy(d.b + indices[i], after, alen * sizeof(QChar)); memcpy(d.data() + indices[i], after, alen * sizeof(QChar));
} else if (alen < blen) { } else if (alen < blen) {
// replace from front // replace from front
detach(); detach();
uint to = indices[0]; uint to = indices[0];
if (alen) if (alen)
memcpy(d.b+to, after, alen*sizeof(QChar)); memcpy(d.data()+to, after, alen*sizeof(QChar));
to += alen; to += alen;
uint movestart = indices[0] + blen; uint movestart = indices[0] + blen;
for (int i = 1; i < nIndices; ++i) { for (int i = 1; i < nIndices; ++i) {
int msize = indices[i] - movestart; int msize = indices[i] - movestart;
if (msize > 0) { if (msize > 0) {
memmove(d.b + to, d.b + movestart, msize * sizeof(QChar)); memmove(d.data() + to, d.data() + movestart, msize * sizeof(QChar));
to += msize; to += msize;
} }
if (alen) { if (alen) {
memcpy(d.b + to, after, alen * sizeof(QChar)); memcpy(d.data() + to, after, alen * sizeof(QChar));
to += alen; to += alen;
} }
movestart = indices[i] + blen; movestart = indices[i] + blen;
} }
int msize = d.size - movestart; int msize = d.size - movestart;
if (msize > 0) if (msize > 0)
memmove(d.b + to, d.b + movestart, msize * sizeof(QChar)); memmove(d.data() + to, d.data() + movestart, msize * sizeof(QChar));
resize(d.size - nIndices*(blen-alen)); resize(d.size - nIndices*(blen-alen));
} else { } else {
// replace from back // replace from back
@ -3107,9 +3071,9 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
int movestart = indices[nIndices] + blen; int movestart = indices[nIndices] + blen;
int insertstart = indices[nIndices] + nIndices*(alen-blen); int insertstart = indices[nIndices] + nIndices*(alen-blen);
int moveto = insertstart + alen; int moveto = insertstart + alen;
memmove(d.b + moveto, d.b + movestart, memmove(d.data() + moveto, d.data() + movestart,
(moveend - movestart)*sizeof(QChar)); (moveend - movestart)*sizeof(QChar));
memcpy(d.b + insertstart, after, alen * sizeof(QChar)); memcpy(d.data() + insertstart, after, alen * sizeof(QChar));
moveend = movestart-blen; moveend = movestart-blen;
} }
} }
@ -3170,10 +3134,10 @@ QString &QString::replace(const QChar *before, int blen,
We're about to change data, that before and after might point We're about to change data, that before and after might point
into, and we'll need that data for our next batch of indices. into, and we'll need that data for our next batch of indices.
*/ */
if (!afterBuffer && pointsIntoRange(after, d.b, d.size)) if (!afterBuffer && pointsIntoRange(after, d.data(), d.size))
after = afterBuffer = textCopy(after, alen); after = afterBuffer = textCopy(after, alen);
if (!beforeBuffer && pointsIntoRange(before, d.b, d.size)) { if (!beforeBuffer && pointsIntoRange(before, d.data(), d.size)) {
beforeBuffer = textCopy(before, blen); beforeBuffer = textCopy(before, blen);
matcher = QStringMatcher(beforeBuffer, blen, cs); matcher = QStringMatcher(beforeBuffer, blen, cs);
} }
@ -3219,13 +3183,13 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
uint pos = 0; uint pos = 0;
if (cs == Qt::CaseSensitive) { if (cs == Qt::CaseSensitive) {
while (pos < 1024 && index < size()) { while (pos < 1024 && index < size()) {
if (d.b[index] == cc) if (d.data()[index] == cc)
indices[pos++] = index; indices[pos++] = index;
index++; index++;
} }
} else { } else {
while (pos < 1024 && index < size()) { while (pos < 1024 && index < size()) {
if (QChar::toCaseFolded(d.b[index]) == cc) if (QChar::toCaseFolded(d.data()[index]) == cc)
indices[pos++] = index; indices[pos++] = index;
index++; index++;
} }
@ -3258,7 +3222,7 @@ QString& QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs)
if (idx != -1) { if (idx != -1) {
detach(); detach();
const ushort a = after.unicode(); const ushort a = after.unicode();
ushort *i = d.b; ushort *i = d.data();
ushort *const e = i + d.size; ushort *const e = i + d.size;
i += idx; i += idx;
*i = a; *i = a;
@ -4050,14 +4014,14 @@ QString& QString::replace(const QRegExp &rx, const QString &after)
while (i < pos) { while (i < pos) {
int copyend = replacements[i].pos; int copyend = replacements[i].pos;
int size = copyend - copystart; int size = copyend - copystart;
memcpy(static_cast<void*>(uc), static_cast<const void *>(d.b + copystart), size * sizeof(QChar)); memcpy(static_cast<void*>(uc), static_cast<const void *>(d.data() + copystart), size * sizeof(QChar));
uc += size; uc += size;
memcpy(static_cast<void *>(uc), static_cast<const void *>(after.d.b), al * sizeof(QChar)); memcpy(static_cast<void *>(uc), static_cast<const void *>(after.d.data()), al * sizeof(QChar));
uc += al; uc += al;
copystart = copyend + replacements[i].length; copystart = copyend + replacements[i].length;
i++; i++;
} }
memcpy(static_cast<void *>(uc), static_cast<const void *>(d.b + copystart), (d.size - copystart) * sizeof(QChar)); memcpy(static_cast<void *>(uc), static_cast<const void *>(d.data() + copystart), (d.size - copystart) * sizeof(QChar));
newstring.resize(newlen); newstring.resize(newlen);
*this = newstring; *this = newstring;
caretMode = QRegExp::CaretWontMatch; caretMode = QRegExp::CaretWontMatch;
@ -4851,7 +4815,7 @@ QString QString::left(int n) const
{ {
if (uint(n) >= uint(size())) if (uint(n) >= uint(size()))
return *this; return *this;
return QString((const QChar*) d.b, n); return QString((const QChar*) d.data(), n);
} }
/*! /*!
@ -5146,22 +5110,22 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
// We can return our own buffer to the caller. // We can return our own buffer to the caller.
// Conversion to Latin-1 always shrinks the buffer by half. // Conversion to Latin-1 always shrinks the buffer by half.
const ushort *data = reinterpret_cast<const ushort *>(s.constData()); const ushort *data = s.d.data();
uint length = s.size(); int length = s.d.size;
// Swap the d pointers. // Move the d pointer over to the bytearray.
// Kids, avert your eyes. Don't try this at home. // Kids, avert your eyes. Don't try this at home.
auto *dd = static_cast<QTypedArrayData<char> *>(s.d.d); // this relies on the fact that we use QArrayData for everything behind the scenes which has the same layout
char *ddata = reinterpret_cast<char *>(s.d.b); 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();
QByteArray::DataPointer ba_d = { dd, ddata, length }; char *ddata = ba_d.data();
// multiply the allocated capacity by sizeof(ushort) // multiply the allocated capacity by sizeof(ushort)
dd->alloc *= sizeof(ushort); ba_d.d_ptr()->alloc *= sizeof(ushort);
// reset ourselves to QString()
s.d = QString().d;
// do the in-place conversion // do the in-place conversion
qt_to_latin1(reinterpret_cast<uchar *>(ddata), data, length); qt_to_latin1(reinterpret_cast<uchar *>(ddata), data, length);
@ -5352,37 +5316,21 @@ QString::DataPointer QString::fromLatin1_helper(const char *str, int size)
{ {
DataPointer d; DataPointer d;
if (!str) { if (!str) {
d.d = Data::sharedNull(); // nothing to do
d.b = Data::sharedNullData();
d.size = 0;
} else if (size == 0 || (!*str && size < 0)) { } else if (size == 0 || (!*str && size < 0)) {
QPair<Data *, ushort *> pair = Data::allocate(0); d = DataPointer(Data::allocate(0), 0);
d.d = pair.first;
d.b = pair.second;
d.size = 0;
} else { } else {
if (size < 0) if (size < 0)
size = qstrlen(str); size = qstrlen(str);
QPair<Data *, ushort *> pair = Data::allocate(size + 1); d = DataPointer(Data::allocate(size + 1), size);
d.d = pair.first; d.data()[size] = '\0';
d.b = pair.second; ushort *dst = d.data();
d.size = size;
Q_CHECK_PTR(d.d);
d.b[size] = '\0';
ushort *dst = d.b;
qt_from_latin1(dst, str, uint(size)); qt_from_latin1(dst, str, uint(size));
} }
return d; return d;
} }
QString::DataPointer QString::fromAscii_helper(const char *str, int size)
{
QString s = fromUtf8(str, size);
s.d.d->ref();
return s.d;
}
/*! \fn QString QString::fromLatin1(const char *str, int size) /*! \fn QString QString::fromLatin1(const char *str, int size)
Returns a QString initialized with the first \a size characters Returns a QString initialized with the first \a size characters
of the Latin-1 string \a str. of the Latin-1 string \a str.
@ -5596,7 +5544,7 @@ QString& QString::setUnicode(const QChar *unicode, int size)
{ {
resize(size); resize(size);
if (unicode && size) if (unicode && size)
memcpy(d.b, unicode, size * sizeof(QChar)); memcpy(d.data(), unicode, size * sizeof(QChar));
return *this; return *this;
} }
@ -5856,8 +5804,8 @@ QString& QString::fill(QChar ch, int size)
{ {
resize(size < 0 ? d.size : size); resize(size < 0 ? d.size : size);
if (d.size) { if (d.size) {
QChar *i = (QChar*)d.b + d.size; QChar *i = (QChar*)d.data() + d.size;
QChar *b = (QChar*)d.b; QChar *b = (QChar*)d.data();
while (i != b) while (i != b)
*--i = ch; *--i = ch;
} }
@ -6438,11 +6386,11 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
const ushort *QString::utf16() const const ushort *QString::utf16() const
{ {
if (!d.d->isMutable()) { if (!d->isMutable()) {
// ensure '\0'-termination for ::fromRawData strings // ensure '\0'-termination for ::fromRawData strings
const_cast<QString*>(this)->reallocData(uint(d.size) + 1u); const_cast<QString*>(this)->reallocData(uint(d.size) + 1u);
} }
return d.b; return d.data();
} }
/*! /*!
@ -6471,8 +6419,8 @@ QString QString::leftJustified(int width, QChar fill, bool truncate) const
if (padlen > 0) { if (padlen > 0) {
result.resize(len+padlen); result.resize(len+padlen);
if (len) if (len)
memcpy(result.d.b, d.b, sizeof(QChar)*len); memcpy(result.d.data(), d.data(), sizeof(QChar)*len);
QChar *uc = (QChar*)result.d.b + len; QChar *uc = (QChar*)result.d.data() + len;
while (padlen--) while (padlen--)
* uc++ = fill; * uc++ = fill;
} else { } else {
@ -6509,11 +6457,11 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const
int padlen = width - len; int padlen = width - len;
if (padlen > 0) { if (padlen > 0) {
result.resize(len+padlen); result.resize(len+padlen);
QChar *uc = (QChar*)result.d.b; QChar *uc = (QChar*)result.d.data();
while (padlen--) while (padlen--)
* uc++ = fill; * uc++ = fill;
if (len) if (len)
memcpy(static_cast<void *>(uc), static_cast<const void *>(d.b), sizeof(QChar)*len); memcpy(static_cast<void *>(uc), static_cast<const void *>(d.data()), sizeof(QChar)*len);
} else { } else {
if (truncate) if (truncate)
result = left(width); result = left(width);
@ -7938,19 +7886,19 @@ QString QString::repeated(int times) const
if (result.capacity() != resultSize) if (result.capacity() != resultSize)
return QString(); // not enough memory return QString(); // not enough memory
memcpy(result.d.b, d.b, d.size * sizeof(ushort)); memcpy(result.d.data(), d.data(), d.size * sizeof(ushort));
int sizeSoFar = d.size; int sizeSoFar = d.size;
ushort *end = result.d.b + sizeSoFar; ushort *end = result.d.data() + sizeSoFar;
const int halfResultSize = resultSize >> 1; const int halfResultSize = resultSize >> 1;
while (sizeSoFar <= halfResultSize) { while (sizeSoFar <= halfResultSize) {
memcpy(end, result.d.b, sizeSoFar * sizeof(ushort)); memcpy(end, result.d.data(), sizeSoFar * sizeof(ushort));
end += sizeSoFar; end += sizeSoFar;
sizeSoFar <<= 1; sizeSoFar <<= 1;
} }
memcpy(end, result.d.b, (resultSize - sizeSoFar) * sizeof(ushort)); memcpy(end, result.d.data(), (resultSize - sizeSoFar) * sizeof(ushort));
result.d.b[resultSize] = '\0'; result.d.data()[resultSize] = '\0';
result.d.size = resultSize; result.d.size = resultSize;
return result; return result;
} }
@ -8951,7 +8899,7 @@ QString QtPrivate::argToQString(QLatin1String pattern, size_t n, const ArgBase *
*/ */
bool QString::isSimpleText() const bool QString::isSimpleText() const
{ {
const ushort *p = d.b; const ushort *p = d.data();
const ushort * const end = p + d.size; const ushort * const end = p + d.size;
while (p < end) { while (p < end) {
ushort uc = *p; ushort uc = *p;
@ -9102,18 +9050,11 @@ bool QString::isRightToLeft() const
QString QString::fromRawData(const QChar *unicode, int size) QString QString::fromRawData(const QChar *unicode, int size)
{ {
QString::DataPointer x; QString::DataPointer x;
x.size = size;
if (!unicode) { if (!unicode) {
x.d = Data::sharedNull();
x.b = Data::sharedNullData();
} else if (!size) { } else if (!size) {
QPair<Data *, ushort *> pair = Data::allocate(0); x = DataPointer(Data::allocate(0), 0);
x.d = pair.first;
x.b = pair.second;
} else { } else {
x.b = const_cast<ushort *>(reinterpret_cast<const ushort *>(unicode)); x = Data::fromRawData(reinterpret_cast<const ushort *>(unicode), size);
x.d = Data::fromRawData(x.b, size).ptr;
Q_CHECK_PTR(x.d);
} }
return QString(x); return QString(x);
} }
@ -9136,12 +9077,8 @@ QString &QString::setRawData(const QChar *unicode, int size)
{ {
if (!unicode || !size) { if (!unicode || !size) {
clear(); clear();
} else if (d.d->isShared() || !IS_RAW_DATA(d)) {
*this = fromRawData(unicode, size);
} else {
d.size = size;
d.b = const_cast<ushort *>(reinterpret_cast<const ushort *>(unicode));
} }
*this = fromRawData(unicode, size);
return *this; return *this;
} }

View File

@ -259,8 +259,8 @@ public:
QString &operator=(QChar c); QString &operator=(QChar c);
QString &operator=(const QString &) noexcept; QString &operator=(const QString &) noexcept;
QString &operator=(QLatin1String latin1); QString &operator=(QLatin1String latin1);
inline QString(QString &&other) noexcept : d(std::move(other.d)) inline QString(QString &&other) noexcept
{ other.d.d = Data::sharedNull(); other.d.b = Data::sharedNullData(); other.d.size = 0; } { qSwap(d, other.d); }
inline QString &operator=(QString &&other) noexcept inline QString &operator=(QString &&other) noexcept
{ qSwap(d, other.d); return *this; } { qSwap(d, other.d); return *this; }
inline void swap(QString &other) noexcept { qSwap(d, other.d); } inline void swap(QString &other) noexcept { qSwap(d, other.d); }
@ -286,7 +286,7 @@ public:
inline void detach(); inline void detach();
inline bool isDetached() const; inline bool isDetached() const;
inline bool isSharedWith(const QString &other) const { return d.d == other.d.d; } inline bool isSharedWith(const QString &other) const { return d.isSharedWith(other.d); }
void clear(); void clear();
inline const QChar at(int i) const; inline const QChar at(int i) const;
@ -541,10 +541,10 @@ public:
inline QString &prepend(QLatin1String s) { return insert(0, s); } inline QString &prepend(QLatin1String s) { return insert(0, s); }
inline QString &operator+=(QChar c) { inline QString &operator+=(QChar c) {
if (d.d->needsDetach() || int(d.size + 1) > capacity()) if (d->needsDetach() || int(d.size + 1) > capacity())
reallocData(uint(d.size) + 2u, true); reallocData(uint(d.size) + 2u, true);
d.b[d.size++] = c.unicode(); d->data()[d.size++] = c.unicode();
d.b[d.size] = '\0'; d->data()[d.size] = '\0';
return *this; return *this;
} }
@ -789,10 +789,10 @@ public:
#endif #endif
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) #if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline QT_ASCII_CAST_WARN QString(const char *ch) inline QT_ASCII_CAST_WARN QString(const char *ch)
: d(fromAscii_helper(ch, ch ? int(strlen(ch)) : -1)) : QString(fromUtf8(ch))
{} {}
inline QT_ASCII_CAST_WARN QString(const QByteArray &a) inline QT_ASCII_CAST_WARN QString(const QByteArray &a)
: d(fromAscii_helper(a.constData(), qstrnlen(a.constData(), a.size()))) : QString(fromUtf8(a))
{} {}
inline QT_ASCII_CAST_WARN QString &operator=(const char *ch) inline QT_ASCII_CAST_WARN QString &operator=(const char *ch)
{ return (*this = fromUtf8(ch)); } { return (*this = fromUtf8(ch)); }
@ -908,10 +908,10 @@ public:
struct Null { }; struct Null { };
QT_DEPRECATED_X("use QString()") QT_DEPRECATED_X("use QString()")
static const Null null; static const Null null;
inline QString(const Null &) { d.d = Data::sharedNull(); d.b = Data::sharedNullData(); d.size = 0; } inline QString(const Null &) {}
inline QString &operator=(const Null &) { *this = QString(); return *this; } inline QString &operator=(const Null &) { *this = QString(); return *this; }
#endif #endif
inline bool isNull() const { return d.d == Data::sharedNull(); } inline bool isNull() const { return d->isNull(); }
bool isSimpleText() const; bool isSimpleText() const;
@ -969,7 +969,6 @@ private:
static QString simplified_helper(const QString &str); static QString simplified_helper(const QString &str);
static QString simplified_helper(QString &str); static QString simplified_helper(QString &str);
static DataPointer fromLatin1_helper(const char *str, int size = -1); static DataPointer fromLatin1_helper(const char *str, int size = -1);
static DataPointer fromAscii_helper(const char *str, int size = -1);
static QString fromUtf8_helper(const char *str, int size); static QString fromUtf8_helper(const char *str, int size);
static QString fromLocal8Bit_helper(const char *, int size); static QString fromLocal8Bit_helper(const char *, int size);
static QByteArray toLatin1_helper(const QString &); static QByteArray toLatin1_helper(const QString &);
@ -1021,29 +1020,29 @@ inline QString::QString(QLatin1String aLatin1) : d(fromLatin1_helper(aLatin1.lat
inline int QString::length() const inline int QString::length() const
{ return int(d.size); } { return int(d.size); }
inline const QChar QString::at(int i) const inline const QChar QString::at(int i) const
{ Q_ASSERT(uint(i) < uint(size())); return QChar(d.b[i]); } { Q_ASSERT(uint(i) < uint(size())); return QChar(d.data()[i]); }
inline const QChar QString::operator[](int i) const inline const QChar QString::operator[](int i) const
{ Q_ASSERT(uint(i) < uint(size())); return QChar(d.b[i]); } { Q_ASSERT(uint(i) < uint(size())); return QChar(d.data()[i]); }
inline bool QString::isEmpty() const inline bool QString::isEmpty() const
{ return d.size == 0; } { return d.size == 0; }
inline const QChar *QString::unicode() const inline const QChar *QString::unicode() const
{ return reinterpret_cast<const QChar*>(d.b); } { return reinterpret_cast<const QChar*>(d.data()); }
inline const QChar *QString::data() const inline const QChar *QString::data() const
{ return reinterpret_cast<const QChar*>(d.b); } { return reinterpret_cast<const QChar*>(d.data()); }
inline QChar *QString::data() inline QChar *QString::data()
{ detach(); return reinterpret_cast<QChar*>(d.b); } { detach(); return reinterpret_cast<QChar*>(d.data()); }
inline const QChar *QString::constData() const inline const QChar *QString::constData() const
{ return reinterpret_cast<const QChar*>(d.b); } { return reinterpret_cast<const QChar*>(d.data()); }
inline void QString::detach() inline void QString::detach()
{ if (d.d->needsDetach()) reallocData(d.size + 1u); } { if (d->needsDetach()) reallocData(d.size + 1u); }
inline bool QString::isDetached() const inline bool QString::isDetached() const
{ return !d.d->isShared(); } { return !d->isShared(); }
inline void QString::clear() inline void QString::clear()
{ if (!isNull()) *this = QString(); } { if (!isNull()) *this = QString(); }
inline QString::QString(const QString &other) noexcept : d(other.d) inline QString::QString(const QString &other) noexcept : d(other.d)
{ Q_ASSERT(&other != this); d.d->ref(); } { }
inline int QString::capacity() const inline int QString::capacity() const
{ int realCapacity = d.d->constAllocatedCapacity(); return realCapacity ? realCapacity - 1 : 0; } { int realCapacity = d->constAllocatedCapacity(); return realCapacity ? realCapacity - 1 : 0; }
inline QString &QString::setNum(short n, int base) inline QString &QString::setNum(short n, int base)
{ return setNum(qlonglong(n), base); } { return setNum(qlonglong(n), base); }
inline QString &QString::setNum(ushort n, int base) inline QString &QString::setNum(ushort n, int base)
@ -1130,27 +1129,27 @@ inline QString QString::fromWCharArray(const wchar_t *string, int size)
: fromUcs4(reinterpret_cast<const uint *>(string), size); : fromUcs4(reinterpret_cast<const uint *>(string), size);
} }
inline QString::QString() noexcept { d.d = Data::sharedNull(); d.b = Data::sharedNullData(); d.size = 0; } inline QString::QString() noexcept {}
inline QString::~QString() { if (!d.d->deref()) Data::deallocate(d.d); } inline QString::~QString() {}
inline void QString::reserve(int asize) inline void QString::reserve(int asize)
{ {
if (d.d->needsDetach() || asize >= capacity()) if (d->needsDetach() || asize >= capacity())
reallocData(uint(qMax(asize, size())) + 1u); reallocData(uint(qMax(asize, size())) + 1u);
// we're not shared anymore, for sure // we're not shared anymore, for sure
d.d->flags |= Data::CapacityReserved; d->flags() |= Data::CapacityReserved;
} }
inline void QString::squeeze() inline void QString::squeeze()
{ {
if ((d.d->flags & Data::CapacityReserved) == 0) if ((d->flags() & Data::CapacityReserved) == 0)
return; return;
if (d.d->needsDetach() || int(d.size) < capacity()) if (d->needsDetach() || int(d.size) < capacity())
reallocData(uint(d.size) + 1u); reallocData(uint(d.size) + 1u);
// we're not shared anymore, for sure // we're not shared anymore, for sure
d.d->flags &= uint(~Data::CapacityReserved); d->flags() &= uint(~Data::CapacityReserved);
} }
inline QString &QString::setUtf16(const ushort *autf16, int asize) inline QString &QString::setUtf16(const ushort *autf16, int asize)
@ -1160,21 +1159,21 @@ inline QChar &QString::operator[](int i)
inline QChar &QString::front() { return operator[](0); } inline QChar &QString::front() { return operator[](0); }
inline QChar &QString::back() { return operator[](size() - 1); } inline QChar &QString::back() { return operator[](size() - 1); }
inline QString::iterator QString::begin() inline QString::iterator QString::begin()
{ detach(); return reinterpret_cast<QChar*>(d.b); } { detach(); return reinterpret_cast<QChar*>(d.data()); }
inline QString::const_iterator QString::begin() const inline QString::const_iterator QString::begin() const
{ return reinterpret_cast<const QChar*>(d.b); } { return reinterpret_cast<const QChar*>(d.data()); }
inline QString::const_iterator QString::cbegin() const inline QString::const_iterator QString::cbegin() const
{ return reinterpret_cast<const QChar*>(d.b); } { return reinterpret_cast<const QChar*>(d.data()); }
inline QString::const_iterator QString::constBegin() const inline QString::const_iterator QString::constBegin() const
{ return reinterpret_cast<const QChar*>(d.b); } { return reinterpret_cast<const QChar*>(d.data()); }
inline QString::iterator QString::end() inline QString::iterator QString::end()
{ detach(); return reinterpret_cast<QChar*>(d.b + d.size); } { detach(); return reinterpret_cast<QChar*>(d.data() + d.size); }
inline QString::const_iterator QString::end() const inline QString::const_iterator QString::end() const
{ return reinterpret_cast<const QChar*>(d.b + d.size); } { return reinterpret_cast<const QChar*>(d.data() + d.size); }
inline QString::const_iterator QString::cend() const inline QString::const_iterator QString::cend() const
{ return reinterpret_cast<const QChar*>(d.b + d.size); } { return reinterpret_cast<const QChar*>(d.data() + d.size); }
inline QString::const_iterator QString::constEnd() const inline QString::const_iterator QString::constEnd() const
{ return reinterpret_cast<const QChar*>(d.b + d.size); } { return reinterpret_cast<const QChar*>(d.data() + d.size); }
#if QT_STRINGVIEW_LEVEL < 2 #if QT_STRINGVIEW_LEVEL < 2
inline bool QString::contains(const QString &s, Qt::CaseSensitivity cs) const inline bool QString::contains(const QString &s, Qt::CaseSensitivity cs) const
{ return indexOf(s, 0, cs) != -1; } { return indexOf(s, 0, cs) != -1; }

View File

@ -42,6 +42,7 @@
#define QSTRINGLITERAL_H #define QSTRINGLITERAL_H
#include <QtCore/qarraydata.h> #include <QtCore/qarraydata.h>
#include <QtCore/qarraydatapointer.h>
#if 0 #if 0
#pragma qt_class(QStringLiteral) #pragma qt_class(QStringLiteral)
@ -67,7 +68,7 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 \ Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 \
}; \ }; \
QStringPrivate holder = { \ QStringPrivate holder = { \
const_cast<QArrayData *>(&qstring_literal), \ static_cast<QTypedArrayData<ushort> *>(const_cast<QArrayData *>(&qstring_literal)), \
reinterpret_cast<ushort *>(const_cast<qunicodechar *>(QT_UNICODE_LITERAL(str))), \ reinterpret_cast<ushort *>(const_cast<qunicodechar *>(QT_UNICODE_LITERAL(str))), \
Size \ Size \
}; \ }; \
@ -79,12 +80,7 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
# define QStringViewLiteral(str) QStringView(QT_UNICODE_LITERAL(str), QtPrivate::Deprecated) # define QStringViewLiteral(str) QStringView(QT_UNICODE_LITERAL(str), QtPrivate::Deprecated)
#endif #endif
struct QStringPrivate using QStringPrivate = QArrayDataPointer<ushort>;
{
QArrayData *d;
ushort *b;
uint size;
};
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -191,6 +191,7 @@ public:
bool isMutable() const noexcept { return d->isMutable(); } bool isMutable() const noexcept { return d->isMutable(); }
bool isStatic() const noexcept { return d->isStatic(); } bool isStatic() const noexcept { return d->isStatic(); }
bool isShared() const noexcept { return d->isShared(); } bool isShared() const noexcept { return d->isShared(); }
bool isSharedWith(const QArrayDataPointer &other) const noexcept { return d && d == other.d; }
bool needsDetach() const noexcept { return d->needsDetach(); } bool needsDetach() const noexcept { return d->needsDetach(); }
size_t detachCapacity(size_t newSize) const noexcept { return d->detachCapacity(newSize); } size_t detachCapacity(size_t newSize) const noexcept { return d->detachCapacity(newSize); }
typename Data::ArrayOptions &flags() noexcept { return reinterpret_cast<typename Data::ArrayOptions &>(d->flags); } typename Data::ArrayOptions &flags() noexcept { return reinterpret_cast<typename Data::ArrayOptions &>(d->flags); }
@ -204,6 +205,7 @@ public:
d = pair.first; d = pair.first;
ptr = pair.second; ptr = pair.second;
} }
Data *d_ptr() { return d; }
private: private:
Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const

View File

@ -608,7 +608,7 @@ QString verifyZeroTermination(const QString &str)
QString::DataPointer strDataPtr = const_cast<QString &>(str).data_ptr(); QString::DataPointer strDataPtr = const_cast<QString &>(str).data_ptr();
// Skip if isStatic() or fromRawData(), as those offer no guarantees // Skip if isStatic() or fromRawData(), as those offer no guarantees
if (strDataPtr.d->isStatic() || !strDataPtr.d->isMutable()) if (strDataPtr->isStatic() || !strDataPtr->isMutable())
return str; return str;
int strSize = str.size(); int strSize = str.size();
@ -619,7 +619,7 @@ QString verifyZeroTermination(const QString &str)
.arg(strTerminator.unicode(), 4, 16, QChar('0')); .arg(strTerminator.unicode(), 4, 16, QChar('0'));
// Skip mutating checks on shared strings // Skip mutating checks on shared strings
if (strDataPtr.d->isShared()) if (strDataPtr->isShared())
return str; return str;
const QChar *strData = str.constData(); const QChar *strData = str.constData();
@ -4046,13 +4046,14 @@ void tst_QString::setRawData()
QVERIFY(cstr.constData() == ptr); QVERIFY(cstr.constData() == ptr);
QVERIFY(cstr == QString(ptr, 1)); QVERIFY(cstr == QString(ptr, 1));
QSKIP("This is currently not working.");
// This actually tests the recycling of the shared data object // This actually tests the recycling of the shared data object
void *csd = cstr.data_ptr().d; QString::DataPointer csd = cstr.data_ptr();
cstr.setRawData(ptr2, 1); cstr.setRawData(ptr2, 1);
QVERIFY(cstr.isDetached()); QVERIFY(cstr.isDetached());
QVERIFY(cstr.constData() == ptr2); QVERIFY(cstr.constData() == ptr2);
QVERIFY(cstr == QString(ptr2, 1)); QVERIFY(cstr == QString(ptr2, 1));
QVERIFY(cstr.data_ptr().d == csd); QVERIFY(cstr.data_ptr() == csd);
// This tests the discarding of the shared data object // This tests the discarding of the shared data object
cstr = "foo"; cstr = "foo";
@ -4060,12 +4061,12 @@ void tst_QString::setRawData()
QVERIFY(cstr.constData() != ptr2); QVERIFY(cstr.constData() != ptr2);
// Another test of the fallback // Another test of the fallback
csd = cstr.data_ptr().d; csd = cstr.data_ptr();
cstr.setRawData(ptr2, 1); cstr.setRawData(ptr2, 1);
QVERIFY(cstr.isDetached()); QVERIFY(cstr.isDetached());
QVERIFY(cstr.constData() == ptr2); QVERIFY(cstr.constData() == ptr2);
QVERIFY(cstr == QString(ptr2, 1)); QVERIFY(cstr == QString(ptr2, 1));
QVERIFY(cstr.data_ptr().d != csd); QVERIFY(cstr.data_ptr() != csd);
} }
void tst_QString::fromStdString() void tst_QString::fromStdString()
@ -6614,7 +6615,7 @@ void tst_QString::literals()
QVERIFY(str.length() == 4); QVERIFY(str.length() == 4);
QVERIFY(str == QLatin1String("abcd")); QVERIFY(str == QLatin1String("abcd"));
QVERIFY(str.data_ptr().d->isStatic()); QVERIFY(str.data_ptr()->isStatic());
const QChar *s = str.constData(); const QChar *s = str.constData();
QString str2 = str; QString str2 = str;