Inline the size and data pointer members in QString

I'd have preferred to use QArrayDataPointer<ushort> for QString, but
that option wasn't the best one. QArrayDataPointer try to do some
operations using QArrayDataOps and that would expand to unnecessary
code. What's more, the existing code expected to be able to modify and
access the d pointer.

Instead, this commit introduces QStringPrivate (named differently from
QStringData to catch potential users), which contains the three
members. This POD class is also used in QJsonValue to store the
"inlined" QString. QHashedString in qtdeclarative will need a similar
solution.

Change-Id: I33f072158e6e2cd031d4d2ffc81f4a8dbaf4e616
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Thiago Macieira 2012-06-19 17:31:00 +02:00 committed by Lars Knoll
parent b42a2b3c33
commit 746ab4bbd6
7 changed files with 313 additions and 303 deletions

View File

@ -66,7 +66,7 @@ QBinaryJsonValue::QBinaryJsonValue(QBinaryJsonPrivate::MutableData *data,
case QJsonValue::String: {
QString s = v.toString(parent);
stringData = s.data_ptr();
stringData->ref();
stringData.d->ref();
break;
}
case QJsonValue::Array:
@ -80,9 +80,10 @@ QBinaryJsonValue::QBinaryJsonValue(QBinaryJsonPrivate::MutableData *data,
}
QBinaryJsonValue::QBinaryJsonValue(QString string)
: stringData(*reinterpret_cast<QStringData **>(&string)), t(QJsonValue::String)
: d(nullptr), t(QJsonValue::String)
{
stringData->ref();
stringData = *(QStringPrivate *)(&string);
stringData.d->ref();
}
QBinaryJsonValue::QBinaryJsonValue(const QBinaryJsonArray &a)
@ -101,8 +102,8 @@ QBinaryJsonValue::QBinaryJsonValue(const QBinaryJsonObject &o)
QBinaryJsonValue::~QBinaryJsonValue()
{
if (t == QJsonValue::String && stringData && !stringData->deref())
free(stringData);
if (t == QJsonValue::String && !stringData.d->deref())
QTypedArrayData<ushort>::deallocate(stringData.d);
if (d && !d->ref.deref())
delete d;
@ -134,9 +135,8 @@ QString QBinaryJsonValue::toString() const
{
if (t != QJsonValue::String)
return QString();
stringData->ref(); // the constructor below doesn't add a ref.
QStringDataPtr holder = { stringData };
return QString(holder);
stringData.d->ref(); // the constructor below doesn't add a ref.
return QString(stringData);
}
void QBinaryJsonValue::detach()

View File

@ -85,18 +85,17 @@ public:
~QBinaryJsonValue();
QBinaryJsonValue(QBinaryJsonValue &&other) noexcept
: ui(other.ui),
: stringData(other.stringData),
d(other.d),
t(other.t)
{
other.ui = 0;
other.d = nullptr;
other.t = QJsonValue::Null;
}
QBinaryJsonValue &operator =(QBinaryJsonValue &&other) noexcept
{
qSwap(ui, other.ui);
qSwap(stringData, other.stringData);
qSwap(d, other.d);
qSwap(t, other.t);
return *this;
@ -122,7 +121,7 @@ private:
quint64 ui;
bool b;
double dbl;
QStringData *stringData;
QStringPrivate stringData;
const QBinaryJsonPrivate::Base *base;
};
QBinaryJsonPrivate::MutableData *d = nullptr; // needed for Objects and Arrays

View File

@ -100,7 +100,7 @@
#define ULLONG_MAX quint64_C(18446744073709551615)
#endif
#define IS_RAW_DATA(d) ((d)->flags & QArrayData::RawDataType)
#define IS_RAW_DATA(d) ((d.d)->flags & QArrayData::RawDataType)
QT_BEGIN_NAMESPACE
@ -2100,8 +2100,10 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
*/
QString::QString(const QChar *unicode, int size)
{
if (!unicode) {
d = Data::sharedNull();
if (!unicode) {
d.d = Data::sharedNull();
d.b = Data::sharedNullData();
d.size = 0;
} else {
if (size < 0) {
size = 0;
@ -2109,13 +2111,18 @@ QString::QString(const QChar *unicode, int size)
++size;
}
if (!size) {
d = Data::allocate(0).first;
QPair<Data *, ushort *> pair = Data::allocate(0);
d.d = pair.first;
d.b = pair.second;
d.size = 0;
} else {
d = Data::allocate(size + 1).first;
Q_CHECK_PTR(d);
d->size = size;
memcpy(d->data(), unicode, size * sizeof(QChar));
d->data()[size] = '\0';
QPair<Data *, ushort *> pair = Data::allocate(size + 1);
d.d = pair.first;
d.b = pair.second;
d.size = size;
Q_CHECK_PTR(d.d);
memcpy(d.b, unicode, size * sizeof(QChar));
d.b[size] = '\0';
}
}
}
@ -2128,15 +2135,20 @@ QString::QString(const QChar *unicode, int size)
*/
QString::QString(int size, QChar ch)
{
if (size <= 0) {
d = Data::allocate(0).first;
if (size <= 0) {
QPair<Data *, ushort *> pair = Data::allocate(0);
d.d = pair.first;
d.b = pair.second;
d.size = 0;
} else {
d = Data::allocate(size + 1).first;
Q_CHECK_PTR(d);
d->size = size;
d->data()[size] = '\0';
ushort *i = d->data() + size;
ushort *b = d->data();
QPair<Data *, ushort *> pair = Data::allocate(size + 1);
d.d = pair.first;
d.b = pair.second;
d.size = size;
Q_CHECK_PTR(d.d);
d.b[size] = '\0';
ushort *i = d.b + size;
ushort *b = d.b;
const ushort value = ch.unicode();
while (i != b)
*--i = value;
@ -2151,10 +2163,12 @@ QString::QString(int size, QChar ch)
*/
QString::QString(int size, Qt::Initialization)
{
d = Data::allocate(size + 1).first;
Q_CHECK_PTR(d);
d->size = size;
d->data()[size] = '\0';
QPair<Data *, ushort *> pair = Data::allocate(size + 1);
d.d = pair.first;
d.b = pair.second;
d.size = size;
Q_CHECK_PTR(d.d);
d.b[size] = '\0';
}
/*! \fn QString::QString(QLatin1String str)
@ -2169,11 +2183,13 @@ QString::QString(int size, Qt::Initialization)
*/
QString::QString(QChar ch)
{
d = Data::allocate(2).first;
Q_CHECK_PTR(d);
d->size = 1;
d->data()[0] = ch.unicode();
d->data()[1] = '\0';
QPair<Data *, ushort *> pair = Data::allocate(2);
d.d = pair.first;
d.b = pair.second;
d.size = 1;
Q_CHECK_PTR(d.d);
d.b[0] = ch.unicode();
d.b[1] = '\0';
}
/*! \fn QString::QString(const QByteArray &ba)
@ -2195,7 +2211,7 @@ QString::QString(QChar ch)
\internal
*/
/*! \fn QString::QString(QStringDataPtr)
/*! \fn QString::QString(QStringPrivate)
\internal
*/
@ -2265,16 +2281,16 @@ void QString::resize(int size)
if (size < 0)
size = 0;
if (!d->isShared() && !d->isMutable() && size < d->size) {
d->size = size;
if (!d.d->isShared() && !d.d->isMutable() && size < int(d.size)) {
d.size = size;
return;
}
if (d->needsDetach() || size > capacity())
if (d.d->needsDetach() || size > capacity())
reallocData(uint(size) + 1u, true);
if (d->isMutable()) {
d->size = size;
d->data()[size] = '\0';
if (d.d->isMutable()) {
d.size = size;
d.b[size] = '\0';
}
}
@ -2294,7 +2310,7 @@ void QString::resize(int size, QChar fillChar)
resize(size);
const int difference = length() - oldSize;
if (difference > 0)
std::fill_n(d->begin() + oldSize, difference, fillChar.unicode());
std::fill_n(d.b + oldSize, difference, fillChar.unicode());
}
/*! \fn int QString::capacity() const
@ -2349,30 +2365,33 @@ void QString::resize(int size, QChar fillChar)
void QString::reallocData(uint alloc, bool grow)
{
auto allocOptions = d->detachFlags();
auto allocOptions = d.d->detachFlags();
if (grow)
allocOptions |= QArrayData::GrowsForward;
if (d->needsDetach()) {
Data *x = Data::allocate(alloc, allocOptions).first;
Q_CHECK_PTR(x);
x->size = qMin(int(alloc) - 1, d->size);
::memcpy(x->data(), d->data(), x->size * sizeof(QChar));
x->data()[x->size] = 0;
if (!d->deref())
Data::deallocate(d);
d = x;
if (d.d->needsDetach()) {
QPair<Data *, ushort *> pair = Data::allocate(alloc, allocOptions);
Q_CHECK_PTR(pair.first);
d.size = qMin(alloc - 1, d.size);
::memcpy(pair.second, d.b, d.size * sizeof(QChar));
pair.second[d.size] = 0;
if (!d.d->deref())
Data::deallocate(d.d);
d.d = pair.first;
d.b = pair.second;
} else {
Data *p = Data::reallocateUnaligned(d, d->data(), alloc, allocOptions).first;
Q_CHECK_PTR(p);
d = p;
QPair<Data *, ushort *> pair =
Data::reallocateUnaligned(static_cast<Data *>(d.d), d.b, alloc, allocOptions);
Q_CHECK_PTR(pair.first);
d.d = pair.first;
d.b = pair.second;
}
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void QString::expand(int i)
{
resize(qMax(i + 1, d->size), QLatin1Char(' '));
resize(qMax(i + 1, size()), QLatin1Char(' '));
}
#endif
@ -2391,9 +2410,9 @@ void QString::expand(int i)
QString &QString::operator=(const QString &other) noexcept
{
other.d->ref();
if (!d->deref())
Data::deallocate(d);
other.d.d->ref();
if (!d.d->deref())
Data::deallocate(d.d);
d = other.d;
return *this;
}
@ -2415,9 +2434,9 @@ QString &QString::operator=(const QString &other) noexcept
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());
d.size = other.size();
d.b[other.size()] = 0;
qt_from_latin1(d.b, other.latin1(), other.size());
} else {
*this = fromLatin1(other.latin1(), other.size());
}
@ -2480,10 +2499,9 @@ QString &QString::operator=(QChar 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;
d.b[0] = ch.unicode();
d.b[1] = 0;
d.size = 1;
} else {
operator=(QString(ch));
}
@ -2569,13 +2587,13 @@ QString &QString::insert(int i, QLatin1String str)
return *this;
int len = str.size();
if (Q_UNLIKELY(i > d->size))
if (Q_UNLIKELY(i > size()))
resize(i + len, QLatin1Char(' '));
else
resize(d->size + len);
resize(size() + len);
::memmove(d->data() + i + len, d->data() + i, (d->size - i - len) * sizeof(QChar));
qt_from_latin1(d->data() + i, s, uint(len));
::memmove(d.b + i + len, d.b + i, (d.size - i - len) * sizeof(QChar));
qt_from_latin1(d.b + i, s, uint(len));
return *this;
}
@ -2592,7 +2610,7 @@ QString& QString::insert(int i, const QChar *unicode, int size)
return *this;
const ushort *s = (const ushort *)unicode;
if (s >= d->data() && s < d->data() + d->size) {
if (s >= d.b && s < d.b + d.size) {
// Part of me - take a copy
ushort *tmp = static_cast<ushort *>(::malloc(size * sizeof(QChar)));
Q_CHECK_PTR(tmp);
@ -2602,13 +2620,13 @@ QString& QString::insert(int i, const QChar *unicode, int size)
return *this;
}
if (Q_UNLIKELY(i > d->size))
if (Q_UNLIKELY(i > int(d.size)))
resize(i + size, QLatin1Char(' '));
else
resize(d->size + size);
resize(d.size + size);
::memmove(d->data() + i + size, d->data() + i, (d->size - i - size) * sizeof(QChar));
memcpy(d->data() + i, s, size * sizeof(QChar));
::memmove(d.b + i + size, d.b + i, (d.size - i - size) * sizeof(QChar));
memcpy(d.b + i, s, size * sizeof(QChar));
return *this;
}
@ -2622,15 +2640,15 @@ QString& QString::insert(int i, const QChar *unicode, int size)
QString& QString::insert(int i, QChar ch)
{
if (i < 0)
i += d->size;
i += d.size;
if (i < 0)
return *this;
if (Q_UNLIKELY(i > d->size))
if (Q_UNLIKELY(i > size()))
resize(i + 1, QLatin1Char(' '));
else
resize(d->size + 1);
::memmove(d->data() + i + 1, d->data() + i, (d->size - i - 1) * sizeof(QChar));
d->data()[i] = ch.unicode();
resize(d.size + 1);
::memmove(d.b + i + 1, d.b + i, (d.size - i - 1) * sizeof(QChar));
d.b[i] = ch.unicode();
return *this;
}
@ -2654,15 +2672,15 @@ QString& QString::insert(int i, QChar ch)
*/
QString &QString::append(const QString &str)
{
if (str.d != Data::sharedNull()) {
if (d == Data::sharedNull()) {
if (!str.isNull()) {
if (isNull()) {
operator=(str);
} else {
if (d->needsDetach() || d->size + str.d->size > capacity())
reallocData(uint(d->size + str.d->size) + 1u, true);
memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar));
d->size += str.d->size;
d->data()[d->size] = '\0';
if (d.d->needsDetach() || size() + str.size() > capacity())
reallocData(uint(size() + str.size()) + 1u, true);
memcpy(d.b + d.size, str.d.b, str.d.size * sizeof(QChar));
d.size += str.d.size;
d.b[d.size] = '\0';
}
}
return *this;
@ -2677,11 +2695,11 @@ QString &QString::append(const QString &str)
QString &QString::append(const QChar *str, int len)
{
if (str && len > 0) {
if (d->needsDetach() || uint(d->size + len) + 1u > d->allocatedCapacity())
reallocData(uint(d->size + len) + 1u, true);
memcpy(d->data() + d->size, str, len * sizeof(QChar));
d->size += len;
d->data()[d->size] = '\0';
if (d.d->needsDetach() || size() + len > capacity())
reallocData(uint(size() + len) + 1u, true);
memcpy(d.b + d.size, str, len * sizeof(QChar));
d.size += len;
d.b[d.size] = '\0';
}
return *this;
}
@ -2696,12 +2714,12 @@ QString &QString::append(QLatin1String str)
const char *s = str.latin1();
if (s) {
int len = str.size();
if (d->needsDetach() || d->size + len > capacity())
reallocData(uint(d->size + len) + 1u, true);
ushort *i = d->data() + d->size;
if (d.d->needsDetach() || size() + len > capacity())
reallocData(uint(size() + len) + 1u, true);
ushort *i = d.b + d.size;
qt_from_latin1(i, s, uint(len));
i[len] = '\0';
d->size += len;
d.size += len;
}
return *this;
}
@ -2743,10 +2761,10 @@ QString &QString::append(QLatin1String str)
*/
QString &QString::append(QChar ch)
{
if (d->needsDetach() || d->size + 1 > capacity())
reallocData(uint(d->size) + 2u, true);
d->data()[d->size++] = ch.unicode();
d->data()[d->size] = '\0';
if (d.d->needsDetach() || size() + 1 > capacity())
reallocData(uint(d.size) + 2u, true);
d.b[d.size++] = ch.unicode();
d.b[d.size] = '\0';
return *this;
}
@ -2839,16 +2857,16 @@ QString &QString::append(QChar ch)
QString &QString::remove(int pos, int len)
{
if (pos < 0) // count from end of string
pos += d->size;
if (uint(pos) >= uint(d->size)) {
pos += size();
if (uint(pos) >= uint(size())) {
// range problems
} else if (len >= d->size - pos) {
} else if (len >= size() - pos) {
resize(pos); // truncate
} else if (len > 0) {
detach();
memmove(d->data() + pos, d->data() + pos + len,
(d->size - pos - len + 1) * sizeof(ushort));
d->size -= len;
memmove(d.b + pos, d.b + pos + len,
(d.size - pos - len + 1) * sizeof(ushort));
d.size -= len;
}
return *this;
}
@ -2993,10 +3011,10 @@ QString &QString::replace(int pos, int len, const QString &after)
*/
QString &QString::replace(int pos, int len, const QChar *unicode, int size)
{
if (uint(pos) > uint(d->size))
if (uint(pos) > uint(this->size()))
return *this;
if (len > d->size - pos)
len = d->size - pos;
if (len > this->size() - pos)
len = this->size() - pos;
uint index = pos;
replace_helper(&index, 1, len, unicode, size);
@ -3060,10 +3078,10 @@ bool pointsIntoRange(const QChar *ptr, const ushort *base, int len)
*/
void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen)
{
// Copy after if it lies inside our own d->data() 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).
QChar *afterBuffer = nullptr;
if (pointsIntoRange(after, d->data(), d->size)) // Use copy in place of vulnerable original:
if (pointsIntoRange(after, d.b, d.size)) // Use copy in place of vulnerable original:
after = afterBuffer = textCopy(after, alen);
QT_TRY {
@ -3071,36 +3089,36 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
// replace in place
detach();
for (int i = 0; i < nIndices; ++i)
memcpy(d->data() + indices[i], after, alen * sizeof(QChar));
memcpy(d.b + indices[i], after, alen * sizeof(QChar));
} else if (alen < blen) {
// replace from front
detach();
uint to = indices[0];
if (alen)
memcpy(d->data()+to, after, alen*sizeof(QChar));
memcpy(d.b+to, after, alen*sizeof(QChar));
to += alen;
uint movestart = indices[0] + blen;
for (int i = 1; i < nIndices; ++i) {
int msize = indices[i] - movestart;
if (msize > 0) {
memmove(d->data() + to, d->data() + movestart, msize * sizeof(QChar));
memmove(d.b + to, d.b + movestart, msize * sizeof(QChar));
to += msize;
}
if (alen) {
memcpy(d->data() + to, after, alen * sizeof(QChar));
memcpy(d.b + to, after, alen * sizeof(QChar));
to += alen;
}
movestart = indices[i] + blen;
}
int msize = d->size - movestart;
int msize = d.size - movestart;
if (msize > 0)
memmove(d->data() + to, d->data() + movestart, msize * sizeof(QChar));
resize(d->size - nIndices*(blen-alen));
memmove(d.b + to, d.b + movestart, msize * sizeof(QChar));
resize(d.size - nIndices*(blen-alen));
} else {
// replace from back
int adjust = nIndices*(alen-blen);
int newLen = d->size + adjust;
int moveend = d->size;
int newLen = d.size + adjust;
int moveend = d.size;
resize(newLen);
while (nIndices) {
@ -3108,9 +3126,9 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
int movestart = indices[nIndices] + blen;
int insertstart = indices[nIndices] + nIndices*(alen-blen);
int moveto = insertstart + alen;
memmove(d->data() + moveto, d->data() + movestart,
memmove(d.b + moveto, d.b + movestart,
(moveend - movestart)*sizeof(QChar));
memcpy(d->data() + insertstart, after, alen * sizeof(QChar));
memcpy(d.b + insertstart, after, alen * sizeof(QChar));
moveend = movestart-blen;
}
}
@ -3136,7 +3154,7 @@ QString &QString::replace(const QChar *before, int blen,
const QChar *after, int alen,
Qt::CaseSensitivity cs)
{
if (d->size == 0) {
if (d.size == 0) {
if (blen)
return *this;
} else {
@ -3171,10 +3189,10 @@ QString &QString::replace(const QChar *before, int blen,
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.
*/
if (!afterBuffer && pointsIntoRange(after, d->data(), d->size))
if (!afterBuffer && pointsIntoRange(after, d.b, d.size))
after = afterBuffer = textCopy(after, alen);
if (!beforeBuffer && pointsIntoRange(before, d->data(), d->size)) {
if (!beforeBuffer && pointsIntoRange(before, d.b, d.size)) {
beforeBuffer = textCopy(before, blen);
matcher = QStringMatcher(beforeBuffer, blen, cs);
}
@ -3203,13 +3221,13 @@ QString &QString::replace(const QChar *before, int blen,
*/
QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs)
{
if (after.d->size == 0)
if (after.size() == 0)
return remove(ch, cs);
if (after.d->size == 1)
if (after.size() == 1)
return replace(ch, after.front(), cs);
if (d->size == 0)
if (size() == 0)
return *this;
ushort cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode());
@ -3219,14 +3237,14 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
uint indices[1024];
uint pos = 0;
if (cs == Qt::CaseSensitive) {
while (pos < 1024 && index < d->size) {
if (d->data()[index] == cc)
while (pos < 1024 && index < size()) {
if (d.b[index] == cc)
indices[pos++] = index;
index++;
}
} else {
while (pos < 1024 && index < d->size) {
if (QChar::toCaseFolded(d->data()[index]) == cc)
while (pos < 1024 && index < size()) {
if (QChar::toCaseFolded(d.b[index]) == cc)
indices[pos++] = index;
index++;
}
@ -3234,12 +3252,12 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
if (!pos) // Nothing to replace
break;
replace_helper(indices, pos, 1, after.constData(), after.d->size);
replace_helper(indices, pos, 1, after.constData(), after.size());
if (Q_LIKELY(index == -1)) // Nothing left to replace
break;
// The call to replace_helper just moved what index points at:
index += pos*(after.d->size - 1);
index += pos*(after.size() - 1);
}
return *this;
}
@ -3254,13 +3272,13 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
*/
QString& QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs)
{
if (d->size) {
if (d.size) {
const int idx = indexOf(before, 0, cs);
if (idx != -1) {
detach();
const ushort a = after.unicode();
ushort *i = d->data();
const ushort *e = i + d->size;
ushort *i = d.b;
ushort *const e = i + d.size;
i += idx;
*i = a;
if (cs == Qt::CaseSensitive) {
@ -3321,7 +3339,7 @@ QString &QString::replace(QLatin1String before, const QString &after, Qt::CaseSe
int blen = before.size();
QVarLengthArray<ushort> b(blen);
qt_from_latin1(b.data(), before.latin1(), blen);
return replace((const QChar *)b.data(), blen, after.constData(), after.d->size, cs);
return replace((const QChar *)b.data(), blen, after.constData(), after.d.size, cs);
}
/*!
@ -3341,7 +3359,7 @@ QString &QString::replace(const QString &before, QLatin1String after, Qt::CaseSe
int alen = after.size();
QVarLengthArray<ushort> a(alen);
qt_from_latin1(a.data(), after.latin1(), alen);
return replace(before.constData(), before.d->size, (const QChar *)a.data(), alen, cs);
return replace(before.constData(), before.d.size, (const QChar *)a.data(), alen, cs);
}
/*!
@ -3377,7 +3395,7 @@ QString &QString::replace(QChar c, QLatin1String after, Qt::CaseSensitivity cs)
*/
bool operator==(const QString &s1, const QString &s2) noexcept
{
if (s1.d->size != s2.d->size)
if (s1.d.size != s2.d.size)
return false;
return qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0;
@ -3390,7 +3408,7 @@ bool operator==(const QString &s1, const QString &s2) noexcept
*/
bool QString::operator==(QLatin1String other) const noexcept
{
if (d->size != other.size())
if (size() != other.size())
return false;
return qt_compare_strings(*this, other, Qt::CaseSensitive) == 0;
@ -3936,7 +3954,7 @@ QString& QString::replace(const QRegExp &rx, const QString &after)
if (isEmpty() && rx2.indexIn(*this) == -1)
return *this;
reallocData(uint(d->size) + 1u);
reallocData(uint(d.size) + 1u);
int index = 0;
int numCaptures = rx2.captureCount();
@ -4035,8 +4053,8 @@ QString& QString::replace(const QRegExp &rx, const QString &after)
}
if (!pos)
break;
replacements[pos].pos = d->size;
int newlen = d->size + adjust;
replacements[pos].pos = d.size;
int newlen = d.size + adjust;
// to continue searching at the right position after we did
// the first round of replacements
@ -4051,14 +4069,14 @@ QString& QString::replace(const QRegExp &rx, const QString &after)
while (i < pos) {
int copyend = replacements[i].pos;
int size = copyend - copystart;
memcpy(static_cast<void*>(uc), static_cast<const void *>(d->data() + copystart), size * sizeof(QChar));
memcpy(static_cast<void*>(uc), static_cast<const void *>(d.b + copystart), size * sizeof(QChar));
uc += size;
memcpy(static_cast<void *>(uc), static_cast<const void *>(after.d->data()), al * sizeof(QChar));
memcpy(static_cast<void *>(uc), static_cast<const void *>(after.d.b), al * sizeof(QChar));
uc += al;
copystart = copyend + replacements[i].length;
i++;
}
memcpy(static_cast<void *>(uc), static_cast<const void *>(d->data() + copystart), (d->size - copystart) * sizeof(QChar));
memcpy(static_cast<void *>(uc), static_cast<const void *>(d.b + copystart), (d.size - copystart) * sizeof(QChar));
newstring.resize(newlen);
*this = newstring;
caretMode = QRegExp::CaretWontMatch;
@ -4098,7 +4116,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
if (!iterator.hasNext()) // no matches at all
return *this;
reallocData(uint(d->size) + 1u);
reallocData(uint(d.size) + 1u);
int numCaptures = re.captureCount();
@ -4850,9 +4868,9 @@ QString QString::section(const QRegularExpression &re, int start, int end, Secti
*/
QString QString::left(int n) const
{
if (uint(n) >= uint(d->size))
if (uint(n) >= uint(size()))
return *this;
return QString((const QChar*) d->data(), n);
return QString((const QChar*) d.b, n);
}
/*!
@ -4868,9 +4886,9 @@ QString QString::left(int n) const
*/
QString QString::right(int n) const
{
if (uint(n) >= uint(d->size))
if (uint(n) >= uint(size()))
return *this;
return QString((const QChar*) d->data() + d->size - n, n);
return QString(constData() + size() - n, n);
}
/*!
@ -4893,18 +4911,19 @@ QString QString::right(int n) const
QString QString::mid(int position, int n) const
{
using namespace QtPrivate;
switch (QContainerImplHelper::mid(d->size, &position, &n)) {
switch (QContainerImplHelper::mid(size(), &position, &n)) {
case QContainerImplHelper::Null:
return QString();
case QContainerImplHelper::Empty:
{
QStringDataPtr empty = { Data::allocate(0).first };
QPair<Data *, ushort *> pair = Data::allocate(0);
QStringPrivate empty = { pair.first, pair.second, 0 };
return QString(empty);
}
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
return QString((const QChar*)d->data() + position, n);
return QString(constData() + position, n);
}
Q_UNREACHABLE();
return QString();
@ -5151,7 +5170,7 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
// Swap the d pointers.
// Kids, avert your eyes. Don't try this at home.
QArrayData *ba_d = s.d;
QArrayData *ba_d = s.d.d;
// multiply the allocated capacity by sizeof(ushort)
ba_d->alloc *= sizeof(ushort);
@ -5348,31 +5367,38 @@ QVector<uint> QtPrivate::convertToUcs4(QStringView string)
return qt_convert_to_ucs4(string);
}
QString::Data *QString::fromLatin1_helper(const char *str, int size)
QStringPrivate QString::fromLatin1_helper(const char *str, int size)
{
Data *d;
QStringPrivate d;
if (!str) {
d = Data::sharedNull();
d.d = Data::sharedNull();
d.b = Data::sharedNullData();
d.size = 0;
} else if (size == 0 || (!*str && size < 0)) {
d = Data::allocate(0).first;
QPair<Data *, ushort *> pair = Data::allocate(0);
d.d = pair.first;
d.b = pair.second;
d.size = 0;
} else {
if (size < 0)
size = qstrlen(str);
d = Data::allocate(size + 1).first;
Q_CHECK_PTR(d);
d->size = size;
d->data()[size] = '\0';
ushort *dst = d->data();
QPair<Data *, ushort *> pair = Data::allocate(size + 1);
d.d = pair.first;
d.b = pair.second;
d.size = size;
Q_CHECK_PTR(d.d);
d.b[size] = '\0';
ushort *dst = d.b;
qt_from_latin1(dst, str, uint(size));
}
return d;
}
QString::Data *QString::fromAscii_helper(const char *str, int size)
QStringPrivate QString::fromAscii_helper(const char *str, int size)
{
QString s = fromUtf8(str, size);
s.d->ref();
s.d.d->ref();
return s.d;
}
@ -5418,7 +5444,8 @@ QString QString::fromLocal8Bit_helper(const char *str, int size)
if (!str)
return QString();
if (size == 0 || (!*str && size < 0)) {
QStringDataPtr empty = { Data::allocate(0).first };
QPair<Data *, ushort *> pair = Data::allocate(0);
QStringPrivate empty = { pair.first, pair.second, 0 };
return QString(empty);
}
#if QT_CONFIG(textcodec)
@ -5588,7 +5615,7 @@ QString& QString::setUnicode(const QChar *unicode, int size)
{
resize(size);
if (unicode && size)
memcpy(d->data(), unicode, size * sizeof(QChar));
memcpy(d.b, unicode, size * sizeof(QChar));
return *this;
}
@ -5821,7 +5848,7 @@ QString QString::trimmed_helper(QString &str)
void QString::truncate(int pos)
{
if (pos < d->size)
if (pos < size())
resize(pos);
}
@ -5843,7 +5870,7 @@ void QString::truncate(int pos)
void QString::chop(int n)
{
if (n > 0)
resize(d->size - n);
resize(d.size - n);
}
/*!
@ -5860,10 +5887,10 @@ void QString::chop(int n)
QString& QString::fill(QChar ch, int size)
{
resize(size < 0 ? d->size : size);
if (d->size) {
QChar *i = (QChar*)d->data() + d->size;
QChar *b = (QChar*)d->data();
resize(size < 0 ? d.size : size);
if (d.size) {
QChar *i = (QChar*)d.b + d.size;
QChar *b = (QChar*)d.b;
while (i != b)
*--i = ch;
}
@ -6444,11 +6471,11 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
const ushort *QString::utf16() const
{
if (!d->isMutable()) {
if (!d.d->isMutable()) {
// 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->data();
return d.b;
}
/*!
@ -6477,8 +6504,8 @@ QString QString::leftJustified(int width, QChar fill, bool truncate) const
if (padlen > 0) {
result.resize(len+padlen);
if (len)
memcpy(result.d->data(), d->data(), sizeof(QChar)*len);
QChar *uc = (QChar*)result.d->data() + len;
memcpy(result.d.b, d.b, sizeof(QChar)*len);
QChar *uc = (QChar*)result.d.b + len;
while (padlen--)
* uc++ = fill;
} else {
@ -6515,11 +6542,11 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const
int padlen = width - len;
if (padlen > 0) {
result.resize(len+padlen);
QChar *uc = (QChar*)result.d->data();
QChar *uc = (QChar*)result.d.b;
while (padlen--)
* uc++ = fill;
if (len)
memcpy(static_cast<void *>(uc), static_cast<const void *>(d->data()), sizeof(QChar)*len);
memcpy(static_cast<void *>(uc), static_cast<const void *>(d.b), sizeof(QChar)*len);
} else {
if (truncate)
result = left(width);
@ -7928,7 +7955,7 @@ QVector<QStringRef> QString::splitRef(const QRegularExpression &re, SplitBehavio
*/
QString QString::repeated(int times) const
{
if (d->size == 0)
if (d.size == 0)
return *this;
if (times <= 1) {
@ -7937,27 +7964,27 @@ QString QString::repeated(int times) const
return QString();
}
const int resultSize = times * d->size;
const int resultSize = times * d.size;
QString result;
result.reserve(resultSize);
if (result.capacity() != resultSize)
return QString(); // not enough memory
memcpy(result.d->data(), d->data(), d->size * sizeof(ushort));
memcpy(result.d.b, d.b, d.size * sizeof(ushort));
int sizeSoFar = d->size;
ushort *end = result.d->data() + sizeSoFar;
int sizeSoFar = d.size;
ushort *end = result.d.b + sizeSoFar;
const int halfResultSize = resultSize >> 1;
while (sizeSoFar <= halfResultSize) {
memcpy(end, result.d->data(), sizeSoFar * sizeof(ushort));
memcpy(end, result.d.b, sizeSoFar * sizeof(ushort));
end += sizeSoFar;
sizeSoFar <<= 1;
}
memcpy(end, result.d->data(), (resultSize - sizeSoFar) * sizeof(ushort));
result.d->data()[resultSize] = '\0';
result.d->size = resultSize;
memcpy(end, result.d.b, (resultSize - sizeSoFar) * sizeof(ushort));
result.d.b[resultSize] = '\0';
result.d.size = resultSize;
return result;
}
@ -8957,8 +8984,8 @@ QString QtPrivate::argToQString(QLatin1String pattern, size_t n, const ArgBase *
*/
bool QString::isSimpleText() const
{
const ushort *p = d->data();
const ushort * const end = p + d->size;
const ushort *p = d.b;
const ushort * const end = p + d.size;
while (p < end) {
ushort uc = *p;
// sort out regions of complex text formatting
@ -9107,17 +9134,21 @@ bool QString::isRightToLeft() const
*/
QString QString::fromRawData(const QChar *unicode, int size)
{
Data *x;
QStringPrivate x;
x.size = size;
if (!unicode) {
x = Data::sharedNull();
x.d = Data::sharedNull();
x.b = Data::sharedNullData();
} else if (!size) {
x = Data::allocate(0).first;
QPair<Data *, ushort *> pair = Data::allocate(0);
x.d = pair.first;
x.b = pair.second;
} else {
x = Data::fromRawData(reinterpret_cast<const ushort *>(unicode), size).ptr;
Q_CHECK_PTR(x);
x.b = const_cast<ushort *>(reinterpret_cast<const ushort *>(unicode));
x.d = Data::fromRawData(x.b, size).ptr;
Q_CHECK_PTR(x.d);
}
QStringDataPtr dataPtr = { x };
return QString(dataPtr);
return QString(x);
}
/*!
@ -9138,11 +9169,11 @@ QString &QString::setRawData(const QChar *unicode, int size)
{
if (!unicode || !size) {
clear();
} else if (d->isShared() || !IS_RAW_DATA(d)) {
} else if (d.d->isShared() || !IS_RAW_DATA(d)) {
*this = fromRawData(unicode, size);
} else {
d->size = size;
d->offset = reinterpret_cast<const char *>(unicode) - reinterpret_cast<char *>(d);
d.size = size;
d.b = const_cast<ushort *>(reinterpret_cast<const ushort *>(unicode));
}
return *this;
}

View File

@ -48,7 +48,7 @@
#include <QtCore/qchar.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qrefcount.h>
#include <QtCore/qarraydata.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qstringliteral.h>
#include <QtCore/qstringalgorithms.h>
@ -246,9 +246,8 @@ qsizetype QStringView::lastIndexOf(QLatin1String s, qsizetype from, Qt::CaseSens
class Q_CORE_EXPORT QString
{
typedef QTypedArrayData<ushort> Data;
public:
typedef QStringData Data;
inline QString() noexcept;
explicit QString(const QChar *unicode, int size = -1);
QString(QChar c);
@ -259,12 +258,13 @@ public:
QString &operator=(QChar c);
QString &operator=(const QString &) noexcept;
QString &operator=(QLatin1String latin1);
inline QString(QString && other) noexcept : d(other.d) { other.d = Data::sharedNull(); }
inline QString(QString &&other) noexcept : d(std::move(other.d))
{ other.d.d = Data::sharedNull(); other.d.b = Data::sharedNullData(); other.d.size = 0; }
inline QString &operator=(QString &&other) noexcept
{ qSwap(d, other.d); return *this; }
inline void swap(QString &other) noexcept { qSwap(d, other.d); }
inline int size() const { return d->size; }
inline int count() const { return d->size; }
inline int size() const { return d.size; }
inline int count() const { return d.size; }
inline int length() const;
inline bool isEmpty() const;
void resize(int size);
@ -285,7 +285,7 @@ public:
inline void detach();
inline bool isDetached() const;
inline bool isSharedWith(const QString &other) const { return d == other.d; }
inline bool isSharedWith(const QString &other) const { return d.d == other.d.d; }
void clear();
inline const QChar at(int i) const;
@ -540,10 +540,10 @@ public:
inline QString &prepend(QLatin1String s) { return insert(0, s); }
inline QString &operator+=(QChar c) {
if (d->needsDetach() || d->size + 1 > capacity())
reallocData(uint(d->size) + 2u, true);
d->data()[d->size++] = c.unicode();
d->data()[d->size] = '\0';
if (d.d->needsDetach() || int(d.size + 1) > capacity())
reallocData(uint(d.size) + 2u, true);
d.b[d.size++] = c.unicode();
d.b[d.size] = '\0';
return *this;
}
@ -656,8 +656,7 @@ public:
// note - this are all inline so we can benefit from strlen() compile time optimizations
static inline QString fromLatin1(const char *str, int size = -1)
{
QStringDataPtr dataPtr = { fromLatin1_helper(str, (str && size == -1) ? int(strlen(str)) : size) };
return QString(dataPtr);
return QString(fromLatin1_helper(str, (str && size == -1) ? int(strlen(str)) : size));
}
static inline QString fromUtf8(const char *str, int size = -1)
{
@ -908,17 +907,17 @@ public:
struct Null { };
QT_DEPRECATED_X("use QString()")
static const Null null;
inline QString(const Null &): d(Data::sharedNull()) {}
inline QString(const Null &) { d.d = Data::sharedNull(); d.b = Data::sharedNullData(); d.size = 0; }
inline QString &operator=(const Null &) { *this = QString(); return *this; }
#endif
inline bool isNull() const { return d == Data::sharedNull(); }
inline bool isNull() const { return d.d == Data::sharedNull(); }
bool isSimpleText() const;
bool isRightToLeft() const;
QString(int size, Qt::Initialization);
Q_DECL_CONSTEXPR inline QString(QStringDataPtr dd) : d(dd.ptr) {}
explicit QString(QStringPrivate dd) : d(dd) {}
private:
#if defined(QT_NO_CAST_FROM_ASCII)
@ -930,7 +929,7 @@ private:
QString &operator=(const QByteArray &a);
#endif
Data *d;
QStringPrivate d;
friend inline bool operator==(QChar, const QString &) noexcept;
friend inline bool operator< (QChar, const QString &) noexcept;
@ -968,8 +967,8 @@ private:
static QString trimmed_helper(QString &str);
static QString simplified_helper(const QString &str);
static QString simplified_helper(QString &str);
static Data *fromLatin1_helper(const char *str, int size = -1);
static Data *fromAscii_helper(const char *str, int size = -1);
static QStringPrivate fromLatin1_helper(const char *str, int size = -1);
static QStringPrivate fromAscii_helper(const char *str, int size = -1);
static QString fromUtf8_helper(const char *str, int size);
static QString fromLocal8Bit_helper(const char *, int size);
static QByteArray toLatin1_helper(const QString &);
@ -1005,7 +1004,7 @@ private:
}
public:
typedef Data * DataPtr;
typedef QStringPrivate DataPtr;
inline DataPtr &data_ptr() { return d; }
};
@ -1021,31 +1020,31 @@ QString QStringView::toString() const
inline QString::QString(QLatin1String aLatin1) : d(fromLatin1_helper(aLatin1.latin1(), aLatin1.size()))
{ }
inline int QString::length() const
{ return d->size; }
{ return d.size; }
inline const QChar QString::at(int i) const
{ Q_ASSERT(uint(i) < uint(size())); return QChar(d->data()[i]); }
{ Q_ASSERT(uint(i) < uint(size())); return QChar(d.b[i]); }
inline const QChar QString::operator[](int i) const
{ Q_ASSERT(uint(i) < uint(size())); return QChar(d->data()[i]); }
{ Q_ASSERT(uint(i) < uint(size())); return QChar(d.b[i]); }
inline bool QString::isEmpty() const
{ return d->size == 0; }
{ return d.size == 0; }
inline const QChar *QString::unicode() const
{ return reinterpret_cast<const QChar*>(d->data()); }
{ return reinterpret_cast<const QChar*>(d.b); }
inline const QChar *QString::data() const
{ return reinterpret_cast<const QChar*>(d->data()); }
{ return reinterpret_cast<const QChar*>(d.b); }
inline QChar *QString::data()
{ detach(); return reinterpret_cast<QChar*>(d->data()); }
{ detach(); return reinterpret_cast<QChar*>(d.b); }
inline const QChar *QString::constData() const
{ return reinterpret_cast<const QChar*>(d->data()); }
{ return reinterpret_cast<const QChar*>(d.b); }
inline void QString::detach()
{ if (d->needsDetach()) reallocData(uint(d->size) + 1u); }
{ if (d.d->needsDetach()) reallocData(d.size + 1u); }
inline bool QString::isDetached() const
{ return !d->isShared(); }
{ return !d.d->isShared(); }
inline void QString::clear()
{ if (!isNull()) *this = QString(); }
inline QString::QString(const QString &other) noexcept : d(other.d)
{ Q_ASSERT(&other != this); d->ref(); }
{ Q_ASSERT(&other != this); d.d->ref(); }
inline int QString::capacity() const
{ int realCapacity = d->constAllocatedCapacity(); return realCapacity ? realCapacity - 1 : 0; }
{ int realCapacity = d.d->constAllocatedCapacity(); return realCapacity ? realCapacity - 1 : 0; }
inline QString &QString::setNum(short n, int base)
{ return setNum(qlonglong(n), base); }
inline QString &QString::setNum(ushort n, int base)
@ -1150,8 +1149,8 @@ public:
inline operator QChar() const
{
using namespace QtPrivate::DeprecatedRefClassBehavior;
if (Q_LIKELY(i < s.d->size))
return QChar(s.d->data()[i]);
if (Q_LIKELY(i < s.size()))
return QChar(s.constData()[i]);
#ifdef QT_DEBUG
warn(WarningType::OutOfRange, EmittingClass::QCharRef);
#endif
@ -1160,7 +1159,7 @@ public:
inline QCharRef &operator=(QChar c)
{
using namespace QtPrivate::DeprecatedRefClassBehavior;
if (Q_UNLIKELY(i >= s.d->size)) {
if (Q_UNLIKELY(i >= s.size())) {
#ifdef QT_DEBUG
warn(WarningType::OutOfRange, EmittingClass::QCharRef);
#endif
@ -1172,7 +1171,7 @@ public:
#endif
s.detach();
}
s.d->data()[i] = c.unicode();
s.d.b[i] = c.unicode();
return *this;
}
@ -1254,27 +1253,27 @@ inline void QCharRef::setRow(uchar arow) { QChar(*this).setRow(arow); }
inline void QCharRef::setCell(uchar acell) { QChar(*this).setCell(acell); }
inline QString::QString() noexcept : d(Data::sharedNull()) {}
inline QString::~QString() { if (!d->deref()) Data::deallocate(d); }
inline QString::QString() noexcept { d.d = Data::sharedNull(); d.b = Data::sharedNullData(); d.size = 0; }
inline QString::~QString() { if (!d.d->deref()) Data::deallocate(d.d); }
inline void QString::reserve(int asize)
{
if (d->needsDetach() || asize >= capacity())
if (d.d->needsDetach() || asize >= capacity())
reallocData(qMax(asize, size()) + 1u);
// we're not shared anymore, for sure
d->flags |= Data::CapacityReserved;
d.d->flags |= Data::CapacityReserved;
}
inline void QString::squeeze()
{
if ((d->flags & Data::CapacityReserved) == 0)
if ((d.d->flags & Data::CapacityReserved) == 0)
return;
if (d->needsDetach() || d->size < capacity())
reallocData(uint(d->size) + 1u);
if (d.d->needsDetach() || int(d.size) < capacity())
reallocData(uint(d.size) + 1u);
// we're not shared anymore, for sure
d->flags &= ~Data::CapacityReserved;
d.d->flags &= ~Data::CapacityReserved;
}
inline QString &QString::setUtf16(const ushort *autf16, int asize)
@ -1284,21 +1283,21 @@ inline QCharRef QString::operator[](int i)
inline QCharRef QString::front() { return operator[](0); }
inline QCharRef QString::back() { return operator[](size() - 1); }
inline QString::iterator QString::begin()
{ detach(); return reinterpret_cast<QChar*>(d->data()); }
{ detach(); return reinterpret_cast<QChar*>(d.b); }
inline QString::const_iterator QString::begin() const
{ return reinterpret_cast<const QChar*>(d->data()); }
{ return reinterpret_cast<const QChar*>(d.b); }
inline QString::const_iterator QString::cbegin() const
{ return reinterpret_cast<const QChar*>(d->data()); }
{ return reinterpret_cast<const QChar*>(d.b); }
inline QString::const_iterator QString::constBegin() const
{ return reinterpret_cast<const QChar*>(d->data()); }
{ return reinterpret_cast<const QChar*>(d.b); }
inline QString::iterator QString::end()
{ detach(); return reinterpret_cast<QChar*>(d->data() + d->size); }
{ detach(); return reinterpret_cast<QChar*>(d.b + d.size); }
inline QString::const_iterator QString::end() const
{ return reinterpret_cast<const QChar*>(d->data() + d->size); }
{ return reinterpret_cast<const QChar*>(d.b + d.size); }
inline QString::const_iterator QString::cend() const
{ return reinterpret_cast<const QChar*>(d->data() + d->size); }
{ return reinterpret_cast<const QChar*>(d.b + d.size); }
inline QString::const_iterator QString::constEnd() const
{ return reinterpret_cast<const QChar*>(d->data() + d->size); }
{ return reinterpret_cast<const QChar*>(d.b + d.size); }
#if QT_STRINGVIEW_LEVEL < 2
inline bool QString::contains(const QString &s, Qt::CaseSensitivity cs) const
{ return indexOf(s, 0, cs) != -1; }
@ -1525,7 +1524,8 @@ inline QString QString::fromStdU32String(const std::u32string &s)
inline std::u32string QString::toStdU32String() const
{
std::u32string u32str(length(), char32_t(0));
int len = toUcs4_helper(d->data(), length(), reinterpret_cast<uint*>(&u32str[0]));
int len = toUcs4_helper(reinterpret_cast<const ushort *>(constData()), length(),
reinterpret_cast<uint*>(&u32str[0]));
u32str.resize(len);
return u32str;
}
@ -1657,7 +1657,7 @@ public:
inline const QChar *unicode() const
{
if (!m_string)
return reinterpret_cast<const QChar *>(QString::Data::sharedNull()->data());
return reinterpret_cast<const QChar *>(QString::Data::sharedNullData());
return m_string->unicode() + m_position;
}
inline const QChar *data() const { return unicode(); }

View File

@ -49,8 +49,6 @@
QT_BEGIN_NAMESPACE
typedef QTypedArrayData<ushort> QStringData;
// all our supported compilers support Unicode string literals,
// even if their Q_COMPILER_UNICODE_STRING has been revoked due
// to lacking stdlib support. But QStringLiteral only needs the
@ -65,43 +63,27 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
#define QStringLiteral(str) \
([]() noexcept -> QString { \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QStaticStringData<Size> qstring_literal = { \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
QT_UNICODE_LITERAL(str) }; \
QStringDataPtr holder = { qstring_literal.data_ptr() }; \
const QString qstring_literal_temp(holder); \
return qstring_literal_temp; \
static const QArrayData qstring_literal = { \
Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, Size, 0, sizeof(QArrayData) \
}; \
QStringPrivate holder = { \
const_cast<QArrayData *>(&qstring_literal), \
reinterpret_cast<ushort *>(const_cast<qunicodechar *>(QT_UNICODE_LITERAL(str))), \
Size \
}; \
return QString(holder); \
}()) \
/**/
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
{ Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, size, 0, offset } \
/**/
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QStringData)) \
/**/
#if QT_DEPRECATED_SINCE(5, 14)
# define QStringViewLiteral(str) QStringView(QT_UNICODE_LITERAL(str), QtPrivate::Deprecated)
#endif
template <int N>
struct QStaticStringData
struct QStringPrivate
{
QArrayData str;
qunicodechar data[N + 1];
QStringData *data_ptr() const
{
Q_ASSERT(str.isStatic());
return const_cast<QStringData *>(static_cast<const QStringData*>(&str));
}
};
struct QStringDataPtr
{
QStringData *ptr;
QArrayData *d;
ushort *b;
uint size;
};
QT_END_NAMESPACE

View File

@ -608,8 +608,7 @@ QString verifyZeroTermination(const QString &str)
QString::DataPtr strDataPtr = const_cast<QString &>(str).data_ptr();
// Skip if isStatic() or fromRawData(), as those offer no guarantees
if (strDataPtr->isStatic()
|| strDataPtr->offset != QString().data_ptr()->offset)
if (strDataPtr.d->isStatic() || !strDataPtr.d->isMutable())
return str;
int strSize = str.size();
@ -620,7 +619,7 @@ QString verifyZeroTermination(const QString &str)
.arg(strTerminator.unicode(), 4, 16, QChar('0'));
// Skip mutating checks on shared strings
if (strDataPtr->isShared())
if (strDataPtr.d->isShared())
return str;
const QChar *strData = str.constData();
@ -4070,12 +4069,12 @@ void tst_QString::setRawData()
QVERIFY(cstr == QString(ptr, 1));
// This actually tests the recycling of the shared data object
QString::DataPtr csd = cstr.data_ptr();
void *csd = cstr.data_ptr().d;
cstr.setRawData(ptr2, 1);
QVERIFY(cstr.isDetached());
QVERIFY(cstr.constData() == ptr2);
QVERIFY(cstr == QString(ptr2, 1));
QVERIFY(cstr.data_ptr() == csd);
QVERIFY(cstr.data_ptr().d == csd);
// This tests the discarding of the shared data object
cstr = "foo";
@ -4083,12 +4082,12 @@ void tst_QString::setRawData()
QVERIFY(cstr.constData() != ptr2);
// Another test of the fallback
csd = cstr.data_ptr();
csd = cstr.data_ptr().d;
cstr.setRawData(ptr2, 1);
QVERIFY(cstr.isDetached());
QVERIFY(cstr.constData() == ptr2);
QVERIFY(cstr == QString(ptr2, 1));
QVERIFY(cstr.data_ptr() != csd);
QVERIFY(cstr.data_ptr().d != csd);
}
void tst_QString::fromStdString()
@ -6637,8 +6636,7 @@ void tst_QString::literals()
QVERIFY(str.length() == 4);
QVERIFY(str == QLatin1String("abcd"));
QVERIFY(str.data_ptr()->isStatic());
QVERIFY(str.data_ptr()->offset == sizeof(QStringData));
QVERIFY(str.data_ptr().d->isStatic());
const QChar *s = str.constData();
QString str2 = str;

View File

@ -126,9 +126,9 @@ void tst_toolsupport::offsets_data()
#ifdef Q_PROCESSOR_X86
// x86 32-bit has weird alignment rules. Refer to QtPrivate::AlignOf in
// qglobal.h for more details.
data << 176 << 272;
data << 184 << 288;
#else
data << 180 << 272;
data << 188 << 288;
#endif
}
#endif