Make QByteArray and QString keep track of terminating null

In conceptual terms, this change increments the Data::alloc member by
one for all strings allocated and maintained by these classes. Instances
initialized with fromRawData retain 0 as the member value, so they are
treated as immutable.

This brings QByteArray and QString closer to QVector, making it possible
for them to reference and share the same data in memory, in the future.
It also brings them closer to QArrayData.

In practical terms all comparisons to the alloc member were changed to
take into account that it also tracks the terminating null character.

Aside from the increment in the alloc member, there should be no user
visible changes.

Change-Id: I618f49022a9b1845754500c8f8706c72a68b9c7d
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
João Abecasis 2012-04-04 15:36:09 +02:00 committed by Qt by Nokia
parent 77fd8fd997
commit 2ac4c463af
4 changed files with 49 additions and 46 deletions

View File

@ -579,7 +579,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
}
d->ref.initializeOwned();
d->size = len;
d->alloc = len;
d->alloc = uint(len) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QByteArrayData);
d->data()[len] = 0;
@ -918,10 +918,11 @@ QByteArray &QByteArray::operator=(const char *str)
x = shared_empty.data_ptr();
} else {
int len = strlen(str);
if (d->ref.isShared() || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1))
if (d->ref.isShared() || uint(len) + 1u > d->alloc
|| (len < d->size && uint(len) + 1u < uint(d->alloc >> 1)))
reallocData(uint(len) + 1u);
x = d;
memcpy(x->data(), str, len + 1); // include null terminator
memcpy(x->data(), str, uint(len) + 1u); // include null terminator
x->size = len;
}
x->ref.ref();
@ -1328,11 +1329,11 @@ QByteArray::QByteArray(const char *data, int size)
if (!size) {
d = shared_empty.data_ptr();
} else {
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
d = static_cast<Data *>(::malloc(sizeof(Data) + uint(size) + 1u));
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = size;
d->alloc = size;
d->alloc = uint(size) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QByteArrayData);
memcpy(d->data(), data, size);
@ -1353,11 +1354,11 @@ QByteArray::QByteArray(int size, char ch)
if (size <= 0) {
d = shared_empty.data_ptr();
} else {
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
d = static_cast<Data *>(::malloc(sizeof(Data) + uint(size) + 1u));
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = size;
d->alloc = size;
d->alloc = uint(size) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QByteArrayData);
memset(d->data(), ch, size);
@ -1373,11 +1374,11 @@ QByteArray::QByteArray(int size, char ch)
QByteArray::QByteArray(int size, Qt::Initialization)
{
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
d = static_cast<Data *>(::malloc(sizeof(Data) + uint(size) + 1u));
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = size;
d->alloc = size;
d->alloc = uint(size) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QByteArrayData);
d->data()[size] = '\0';
@ -1420,18 +1421,19 @@ void QByteArray::resize(int size)
// which is used in place of the Qt 3 idiom:
// QByteArray a(sz);
//
Data *x = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
Data *x = static_cast<Data *>(::malloc(sizeof(Data) + uint(size) + 1u));
Q_CHECK_PTR(x);
x->ref.initializeOwned();
x->size = size;
x->alloc = size;
x->alloc = uint(size) + 1u;
x->capacityReserved = false;
x->offset = sizeof(QByteArrayData);
x->data()[size] = '\0';
d = x;
} else {
if (d->ref.isShared() || size > int(d->alloc)
|| (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
if (d->ref.isShared() || uint(size) + 1u > d->alloc
|| (!d->capacityReserved && size < d->size
&& uint(size) + 1u < uint(d->alloc >> 1)))
reallocData(uint(size) + 1u, true);
if (d->alloc) {
d->size = size;
@ -1469,7 +1471,7 @@ void QByteArray::reallocData(uint alloc, bool grow)
Q_CHECK_PTR(x);
x->ref.initializeOwned();
x->size = qMin(int(alloc) - 1, d->size);
x->alloc = alloc - 1u;
x->alloc = alloc;
x->capacityReserved = d->capacityReserved;
x->offset = sizeof(QByteArrayData);
::memcpy(x->data(), d->data(), x->size);
@ -1480,7 +1482,7 @@ void QByteArray::reallocData(uint alloc, bool grow)
} else {
Data *x = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc));
Q_CHECK_PTR(x);
x->alloc = alloc - 1u;
x->alloc = alloc;
x->offset = sizeof(QByteArrayData);
d = x;
}
@ -1565,7 +1567,7 @@ QByteArray &QByteArray::prepend(const char *str)
QByteArray &QByteArray::prepend(const char *str, int len)
{
if (str) {
if (d->ref.isShared() || d->size + len > int(d->alloc))
if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc)
reallocData(uint(d->size + len) + 1u, true);
memmove(d->data()+len, d->data(), d->size);
memcpy(d->data(), str, len);
@ -1583,7 +1585,7 @@ QByteArray &QByteArray::prepend(const char *str, int len)
QByteArray &QByteArray::prepend(char ch)
{
if (d->ref.isShared() || d->size + 1 > int(d->alloc))
if (d->ref.isShared() || uint(d->size) + 2u > d->alloc)
reallocData(uint(d->size) + 2u, true);
memmove(d->data()+1, d->data(), d->size);
d->data()[0] = ch;
@ -1621,7 +1623,7 @@ QByteArray &QByteArray::append(const QByteArray &ba)
if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
*this = ba;
} else if (ba.d != &shared_null.ba) {
if (d->ref.isShared() || d->size + ba.d->size > int(d->alloc))
if (d->ref.isShared() || uint(d->size + ba.d->size) + 1u > d->alloc)
reallocData(uint(d->size + ba.d->size) + 1u, true);
memcpy(d->data() + d->size, ba.d->data(), ba.d->size);
d->size += ba.d->size;
@ -1655,7 +1657,7 @@ QByteArray& QByteArray::append(const char *str)
{
if (str) {
int len = strlen(str);
if (d->ref.isShared() || d->size + len > int(d->alloc))
if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc)
reallocData(uint(d->size + len) + 1u, true);
memcpy(d->data() + d->size, str, len + 1); // include null terminator
d->size += len;
@ -1680,7 +1682,7 @@ QByteArray &QByteArray::append(const char *str, int len)
if (len < 0)
len = qstrlen(str);
if (str && len) {
if (d->ref.isShared() || d->size + len > int(d->alloc))
if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc)
reallocData(uint(d->size + len) + 1u, true);
memcpy(d->data() + d->size, str, len); // include null terminator
d->size += len;
@ -1697,7 +1699,7 @@ QByteArray &QByteArray::append(const char *str, int len)
QByteArray& QByteArray::append(char ch)
{
if (d->ref.isShared() || d->size + 1 > int(d->alloc))
if (d->ref.isShared() || uint(d->size) + 2u > d->alloc)
reallocData(uint(d->size) + 2u, true);
d->data()[d->size++] = ch;
d->data()[d->size] = '\0';
@ -2206,7 +2208,7 @@ QByteArray QByteArray::repeated(int times) const
QByteArray result;
result.reserve(resultSize);
if (int(result.d->alloc) != resultSize)
if (result.d->alloc != uint(resultSize) + 1u)
return QByteArray(); // not enough memory
memcpy(result.d->data(), d->data(), d->size);

View File

@ -452,11 +452,11 @@ inline QByteArray::QByteArray(const QByteArray &a) : d(a.d)
{ d->ref.ref(); }
inline int QByteArray::capacity() const
{ return d->alloc; }
{ return d->alloc ? d->alloc - 1 : 0; }
inline void QByteArray::reserve(int asize)
{
if (d->ref.isShared() || asize > int(d->alloc))
if (d->ref.isShared() || uint(asize) + 1u > d->alloc)
reallocData(uint(asize) + 1u);
if (!d->capacityReserved) {
@ -467,7 +467,7 @@ inline void QByteArray::reserve(int asize)
inline void QByteArray::squeeze()
{
if (d->ref.isShared() || d->size < int(d->alloc))
if (d->ref.isShared() || uint(d->size) + 1u < d->alloc)
reallocData(uint(d->size) + 1u);
if (d->capacityReserved) {

View File

@ -1049,11 +1049,11 @@ QString::QString(const QChar *unicode, int size)
if (!size) {
d = shared_empty.data_ptr();
} else {
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
d = (Data*) ::malloc(sizeof(Data) + (uint(size) + 1u) * sizeof(QChar));
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = size;
d->alloc = (uint) size;
d->alloc = uint(size) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QStringData);
memcpy(d->data(), unicode, size * sizeof(QChar));
@ -1073,11 +1073,11 @@ QString::QString(int size, QChar ch)
if (size <= 0) {
d = shared_empty.data_ptr();
} else {
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
d = (Data*) ::malloc(sizeof(Data) + (uint(size) + 1u) * sizeof(QChar));
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = size;
d->alloc = (uint) size;
d->alloc = uint(size) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QStringData);
d->data()[size] = '\0';
@ -1097,11 +1097,11 @@ QString::QString(int size, QChar ch)
*/
QString::QString(int size, Qt::Initialization)
{
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
d = (Data*) ::malloc(sizeof(Data) + (uint(size) + 1u) * sizeof(QChar));
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = size;
d->alloc = (uint) size;
d->alloc = uint(size) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QStringData);
d->data()[size] = '\0';
@ -1123,7 +1123,7 @@ QString::QString(QChar ch)
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = 1;
d->alloc = 1;
d->alloc = 2u;
d->capacityReserved = false;
d->offset = sizeof(QStringData);
d->data()[0] = ch.unicode();
@ -1234,8 +1234,9 @@ void QString::resize(int size)
QString::free(d);
d = x;
} else {
if (d->ref.isShared() || size > int(d->alloc) ||
(!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
if (d->ref.isShared() || uint(size) + 1u > d->alloc
|| (!d->capacityReserved && size < d->size
&& uint(size) + 1u < uint(d->alloc >> 1)))
reallocData(uint(size) + 1u, true);
if (d->alloc) {
d->size = size;
@ -1304,7 +1305,7 @@ void QString::reallocData(uint alloc, bool grow)
Q_CHECK_PTR(x);
x->ref.initializeOwned();
x->size = qMin(int(alloc) - 1, d->size);
x->alloc = alloc - 1u;
x->alloc = alloc;
x->capacityReserved = d->capacityReserved;
x->offset = sizeof(QStringData);
::memcpy(x->data(), d->data(), x->size * sizeof(QChar));
@ -1316,7 +1317,7 @@ void QString::reallocData(uint alloc, bool grow)
Data *p = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc * sizeof(QChar)));
Q_CHECK_PTR(p);
d = p;
d->alloc = alloc - 1u;
d->alloc = alloc;
d->offset = sizeof(QStringData);
}
}
@ -1524,7 +1525,7 @@ QString &QString::append(const QString &str)
if (d == &shared_null.str) {
operator=(str);
} else {
if (d->ref.isShared() || d->size + str.d->size > int(d->alloc))
if (d->ref.isShared() || uint(d->size + str.d->size) + 1u > d->alloc)
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;
@ -1544,7 +1545,7 @@ QString &QString::append(const QLatin1String &str)
const uchar *s = (const uchar *)str.latin1();
if (s) {
int len = str.size();
if (d->ref.isShared() || d->size + len > int(d->alloc))
if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc)
reallocData(uint(d->size + len) + 1u, true);
ushort *i = d->data() + d->size;
while ((*i++ = *s++))
@ -1587,7 +1588,7 @@ QString &QString::append(const QLatin1String &str)
*/
QString &QString::append(QChar ch)
{
if (d->ref.isShared() || d->size + 1 > int(d->alloc))
if (d->ref.isShared() || uint(d->size) + 2u > d->alloc)
reallocData(uint(d->size) + 2u, true);
d->data()[d->size++] = ch.unicode();
d->data()[d->size] = '\0';
@ -4056,11 +4057,11 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size)
} else {
if (size < 0)
size = qstrlen(str);
d = static_cast<Data *>(::malloc(sizeof(Data) + (size+1) * sizeof(QChar)));
d = static_cast<Data *>(::malloc(sizeof(Data) + (uint(size) + 1u) * sizeof(QChar)));
Q_CHECK_PTR(d);
d->ref.initializeOwned();
d->size = size;
d->alloc = (uint) size;
d->alloc = uint(size) + 1u;
d->capacityReserved = false;
d->offset = sizeof(QStringData);
d->data()[size] = '\0';
@ -6502,7 +6503,7 @@ QString QString::repeated(int times) const
QString result;
result.reserve(resultSize);
if (int(result.d->alloc) != resultSize)
if (result.d->alloc != uint(resultSize) + 1u)
return QString(); // not enough memory
memcpy(result.d->data(), d->data(), d->size * sizeof(ushort));

View File

@ -369,7 +369,7 @@ public:
inline QString &prepend(const QLatin1String &s) { return insert(0, s); }
inline QString &operator+=(QChar c) {
if (d->ref.isShared() || d->size + 1 > int(d->alloc))
if (d->ref.isShared() || uint(d->size) + 2u > d->alloc)
reallocData(uint(d->size) + 2u, true);
d->data()[d->size++] = c.unicode();
d->data()[d->size] = '\0';
@ -754,7 +754,7 @@ inline void QString::clear()
inline QString::QString(const QString &other) : d(other.d)
{ Q_ASSERT(&other != this); d->ref.ref(); }
inline int QString::capacity() const
{ return d->alloc; }
{ return d->alloc ? d->alloc - 1 : 0; }
inline QString &QString::setNum(short n, int base)
{ return setNum(qlonglong(n), base); }
inline QString &QString::setNum(ushort n, int base)
@ -906,7 +906,7 @@ inline QString::~QString() { if (!d->ref.deref()) free(d); }
inline void QString::reserve(int asize)
{
if (d->ref.isShared() || asize > int(d->alloc))
if (d->ref.isShared() || uint(asize) + 1u > d->alloc)
reallocData(uint(asize) + 1u);
if (!d->capacityReserved) {
@ -917,7 +917,7 @@ inline void QString::reserve(int asize)
inline void QString::squeeze()
{
if (d->ref.isShared() || d->size < int(d->alloc))
if (d->ref.isShared() || uint(d->size) + 1u < d->alloc)
reallocData(uint(d->size) + 1u);
if (d->capacityReserved) {