summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qbytearray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qbytearray.cpp')
-rw-r--r--src/corelib/tools/qbytearray.cpp262
1 files changed, 111 insertions, 151 deletions
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index db22a774f4..31cf65b78d 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -57,7 +57,7 @@
#include <string.h>
#include <stdlib.h>
-#define IS_RAW_DATA(d) ((d)->offset != 0)
+#define IS_RAW_DATA(d) ((d)->offset != sizeof(QByteArrayData))
QT_BEGIN_NAMESPACE
@@ -69,24 +69,25 @@ int qFindByteArray(
int qAllocMore(int alloc, int extra)
{
- if (alloc == 0 && extra == 0)
- return 0;
- const int page = 1 << 12;
- int nalloc;
- alloc += extra;
- if (alloc < 1<<6) {
- nalloc = (1<<3) + ((alloc >>3) << 3);
- } else {
- // don't do anything if the loop will overflow signed int.
- if (alloc >= INT_MAX/2)
- return INT_MAX;
- nalloc = (alloc < page) ? 1 << 3 : page;
- while (nalloc < alloc) {
- if (nalloc <= 0)
- return INT_MAX;
- nalloc *= 2;
- }
- }
+ Q_ASSERT(alloc >= 0 && extra >= 0);
+ Q_ASSERT(alloc < (1 << 30) - extra);
+
+ unsigned nalloc = alloc + extra;
+
+ // Round up to next power of 2
+
+ // Assuming container is growing, always overshoot
+ //--nalloc;
+
+ nalloc |= nalloc >> 1;
+ nalloc |= nalloc >> 2;
+ nalloc |= nalloc >> 4;
+ nalloc |= nalloc >> 8;
+ nalloc |= nalloc >> 16;
+ ++nalloc;
+
+ Q_ASSERT(nalloc > unsigned(alloc + extra));
+
return nalloc - extra;
}
@@ -130,7 +131,7 @@ char *qstrcpy(char *dst, const char *src)
if (!src)
return 0;
#if defined(_MSC_VER) && _MSC_VER >= 1400
- int len = qstrlen(src);
+ int len = strlen(src);
// This is actually not secure!!! It will be fixed
// properly in a later release!
if (len >= 0 && strcpy_s(dst, len+1, src) == 0)
@@ -554,7 +555,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
}
d.take(); // realloc was successful
d.reset(p);
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
int res = ::uncompress((uchar*)d->data(), &len,
(uchar*)data+4, nbytes-4);
@@ -576,14 +577,17 @@ QByteArray qUncompress(const uchar* data, int nbytes)
d.take(); // realloc was successful
d.reset(p);
}
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = len;
- d->alloc = len;
+ d->alloc = uint(len) + 1u;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
d->data()[len] = 0;
- return QByteArray(d.take(), 0, 0);
+ {
+ QByteArrayDataPtr dataPtr = { reinterpret_cast<QByteArrayData *>(d.take()) };
+ return QByteArray(dataPtr);
+ }
case Z_MEM_ERROR:
qWarning("qUncompress: Z_MEM_ERROR: Not enough memory");
@@ -614,11 +618,6 @@ static inline char qToLower(char c)
return c;
}
-const QConstByteArrayData<1> QByteArray::shared_null = { { Q_REFCOUNT_INITIALIZER(-1),
- 0, 0, 0, { 0 } }, { 0 } };
-const QConstByteArrayData<1> QByteArray::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1),
- 0, 0, 0, { 0 } }, { 0 } };
-
/*!
\class QByteArray
\brief The QByteArray class provides an array of bytes.
@@ -895,7 +894,7 @@ QByteArray &QByteArray::operator=(const QByteArray & other)
{
other.d->ref.ref();
if (!d->ref.deref())
- free(d);
+ Data::deallocate(d);
d = other.d;
return *this;
}
@@ -911,20 +910,21 @@ QByteArray &QByteArray::operator=(const char *str)
{
Data *x;
if (!str) {
- x = const_cast<Data *>(&shared_null.ba);
+ x = Data::sharedNull();
} else if (!*str) {
- x = const_cast<Data *>(&shared_empty.ba);
+ x = Data::allocate(0);
} else {
- int len = qstrlen(str);
- if (d->ref != 1 || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1))
- realloc(len);
+ int len = strlen(str);
+ if (d->ref.isShared() || uint(len) + 1u > d->alloc
+ || (len < d->size && uint(len) + 1u < uint(d->alloc >> 1)))
+ reallocData(uint(len) + 1u, d->detachFlags());
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();
if (!d->ref.deref())
- free(d);
+ Data::deallocate(d);
d = x;
return *this;
}
@@ -1301,38 +1301,16 @@ void QByteArray::chop(int n)
\sa isEmpty()
*/
-/*! \fn QByteArray::QByteArray(const char *str)
-
- Constructs a byte array initialized with the string \a str.
-
- QByteArray makes a deep copy of the string data.
-*/
-
-QByteArray::QByteArray(const char *str)
-{
- if (!str) {
- d = const_cast<Data *>(&shared_null.ba);
- } else if (!*str) {
- d = const_cast<Data *>(&shared_empty.ba);
- } else {
- int len = qstrlen(str);
- d = static_cast<Data *>(malloc(sizeof(Data) + len + 1));
- Q_CHECK_PTR(d);
- d->ref = 1;
- d->size = len;
- d->alloc = len;
- d->capacityReserved = false;
- d->offset = 0;
- memcpy(d->data(), str, len+1); // include null terminator
- }
-}
-
/*!
Constructs a byte array containing the first \a size bytes of
array \a data.
If \a data is 0, a null byte array is constructed.
+ If \a size is negative, \a data is assumed to point to a nul-terminated
+ string and its length is determined dynamically. The terminating
+ nul-character is not considered part of the byte array.
+
QByteArray makes a deep copy of the string data.
\sa fromRawData()
@@ -1341,19 +1319,19 @@ QByteArray::QByteArray(const char *str)
QByteArray::QByteArray(const char *data, int size)
{
if (!data) {
- d = const_cast<Data *>(&shared_null.ba);
- } else if (size <= 0) {
- d = const_cast<Data *>(&shared_empty.ba);
+ d = Data::sharedNull();
} else {
- d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
- Q_CHECK_PTR(d);
- d->ref = 1;
- d->size = size;
- d->alloc = size;
- d->capacityReserved = false;
- d->offset = 0;
- memcpy(d->data(), data, size);
- d->data()[size] = '\0';
+ if (size < 0)
+ size = strlen(data);
+ if (!size) {
+ d = Data::allocate(0);
+ } else {
+ d = Data::allocate(uint(size) + 1u);
+ Q_CHECK_PTR(d);
+ d->size = size;
+ memcpy(d->data(), data, size);
+ d->data()[size] = '\0';
+ }
}
}
@@ -1367,15 +1345,11 @@ QByteArray::QByteArray(const char *data, int size)
QByteArray::QByteArray(int size, char ch)
{
if (size <= 0) {
- d = const_cast<Data *>(&shared_null.ba);
+ d = Data::allocate(0);
} else {
- d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
+ d = Data::allocate(uint(size) + 1u);
Q_CHECK_PTR(d);
- d->ref = 1;
d->size = size;
- d->alloc = size;
- d->capacityReserved = false;
- d->offset = 0;
memset(d->data(), ch, size);
d->data()[size] = '\0';
}
@@ -1389,13 +1363,9 @@ QByteArray::QByteArray(int size, char ch)
QByteArray::QByteArray(int size, Qt::Initialization)
{
- d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
+ d = Data::allocate(uint(size) + 1u);
Q_CHECK_PTR(d);
- d->ref = 1;
d->size = size;
- d->alloc = size;
- d->capacityReserved = false;
- d->offset = 0;
d->data()[size] = '\0';
}
@@ -1411,23 +1381,22 @@ QByteArray::QByteArray(int size, Qt::Initialization)
\sa size(), truncate()
*/
-
void QByteArray::resize(int size)
{
if (size < 0)
size = 0;
- if (d->offset && d->ref == 1 && size < d->size) {
+ if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) {
d->size = size;
return;
}
if (size == 0 && !d->capacityReserved) {
- Data *x = const_cast<Data *>(&shared_empty.ba);
+ Data *x = Data::allocate(0);
if (!d->ref.deref())
- free(d);
+ Data::deallocate(d);
d = x;
- } else if (d == &shared_null.ba || d == &shared_empty.ba) {
+ } else if (d->size == 0 && d->ref.isStatic()) {
//
// Optimize the idiom:
// QByteArray a;
@@ -1436,20 +1405,17 @@ 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 = Data::allocate(uint(size) + 1u);
Q_CHECK_PTR(x);
- x->ref = 1;
x->size = size;
- x->alloc = size;
- x->capacityReserved = false;
- x->offset = 0;
x->data()[size] = '\0';
d = x;
} else {
- if (d->ref != 1 || size > int(d->alloc)
- || (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
- realloc(qAllocMore(size, sizeof(Data)));
- if (int(d->alloc) >= size) {
+ 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, d->detachFlags() | Data::Grow);
+ if (d->alloc) {
d->size = size;
d->data()[size] = '\0';
}
@@ -1475,26 +1441,24 @@ QByteArray &QByteArray::fill(char ch, int size)
return *this;
}
-void QByteArray::realloc(int alloc)
+void QByteArray::reallocData(uint alloc, Data::AllocationOptions options)
{
- if (d->ref != 1 || d->offset) {
- Data *x = static_cast<Data *>(malloc(sizeof(Data) + alloc + 1));
+ if (d->ref.isShared() || IS_RAW_DATA(d)) {
+ Data *x = Data::allocate(alloc, options);
Q_CHECK_PTR(x);
- x->ref = 1;
- x->size = qMin(alloc, d->size);
- x->alloc = alloc;
- x->capacityReserved = d->capacityReserved;
- x->offset = 0;
+ x->size = qMin(int(alloc) - 1, d->size);
::memcpy(x->data(), d->data(), x->size);
x->data()[x->size] = '\0';
if (!d->ref.deref())
- free(d);
+ Data::deallocate(d);
d = x;
} else {
- Data *x = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc + 1));
+ if (options & Data::Grow)
+ alloc = qAllocMore(alloc, sizeof(Data));
+ Data *x = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc));
Q_CHECK_PTR(x);
x->alloc = alloc;
- x->offset = 0;
+ x->capacityReserved = (options & Data::CapacityReserved) ? 1 : 0;
d = x;
}
}
@@ -1516,7 +1480,7 @@ void QByteArray::expand(int i)
QByteArray QByteArray::nulTerminated() const
{
// is this fromRawData?
- if (!d->offset)
+ if (!IS_RAW_DATA(d))
return *this; // no, then we're sure we're zero terminated
QByteArray copy(*this);
@@ -1547,9 +1511,9 @@ QByteArray QByteArray::nulTerminated() const
QByteArray &QByteArray::prepend(const QByteArray &ba)
{
- if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
+ if (d->size == 0 && d->ref.isStatic() && !IS_RAW_DATA(ba.d)) {
*this = ba;
- } else if (ba.d != &shared_null.ba) {
+ } else if (ba.d->size != 0) {
QByteArray tmp = *this;
*this = ba;
append(tmp);
@@ -1578,8 +1542,8 @@ QByteArray &QByteArray::prepend(const char *str)
QByteArray &QByteArray::prepend(const char *str, int len)
{
if (str) {
- if (d->ref != 1 || d->size + len > int(d->alloc))
- realloc(qAllocMore(d->size + len, sizeof(Data)));
+ if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc)
+ reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::Grow);
memmove(d->data()+len, d->data(), d->size);
memcpy(d->data(), str, len);
d->size += len;
@@ -1596,8 +1560,8 @@ QByteArray &QByteArray::prepend(const char *str, int len)
QByteArray &QByteArray::prepend(char ch)
{
- if (d->ref != 1 || d->size + 1 > int(d->alloc))
- realloc(qAllocMore(d->size + 1, sizeof(Data)));
+ if (d->ref.isShared() || uint(d->size) + 2u > d->alloc)
+ reallocData(uint(d->size) + 2u, d->detachFlags() | Data::Grow);
memmove(d->data()+1, d->data(), d->size);
d->data()[0] = ch;
++d->size;
@@ -1631,11 +1595,11 @@ QByteArray &QByteArray::prepend(char ch)
QByteArray &QByteArray::append(const QByteArray &ba)
{
- if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
+ if (d->size == 0 && d->ref.isStatic() && !IS_RAW_DATA(ba.d)) {
*this = ba;
- } else if (ba.d != &shared_null.ba) {
- if (d->ref != 1 || d->size + ba.d->size > int(d->alloc))
- realloc(qAllocMore(d->size + ba.d->size, sizeof(Data)));
+ } else if (ba.d->size != 0) {
+ if (d->ref.isShared() || uint(d->size + ba.d->size) + 1u > d->alloc)
+ reallocData(uint(d->size + ba.d->size) + 1u, d->detachFlags() | Data::Grow);
memcpy(d->data() + d->size, ba.d->data(), ba.d->size);
d->size += ba.d->size;
d->data()[d->size] = '\0';
@@ -1667,9 +1631,9 @@ QByteArray &QByteArray::append(const QByteArray &ba)
QByteArray& QByteArray::append(const char *str)
{
if (str) {
- int len = qstrlen(str);
- if (d->ref != 1 || d->size + len > int(d->alloc))
- realloc(qAllocMore(d->size + len, sizeof(Data)));
+ int len = strlen(str);
+ if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc)
+ reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::Grow);
memcpy(d->data() + d->size, str, len + 1); // include null terminator
d->size += len;
}
@@ -1693,8 +1657,8 @@ QByteArray &QByteArray::append(const char *str, int len)
if (len < 0)
len = qstrlen(str);
if (str && len) {
- if (d->ref != 1 || d->size + len > int(d->alloc))
- realloc(qAllocMore(d->size + len, sizeof(Data)));
+ if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc)
+ reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::Grow);
memcpy(d->data() + d->size, str, len); // include null terminator
d->size += len;
d->data()[d->size] = '\0';
@@ -1710,8 +1674,8 @@ QByteArray &QByteArray::append(const char *str, int len)
QByteArray& QByteArray::append(char ch)
{
- if (d->ref != 1 || d->size + 1 > int(d->alloc))
- realloc(qAllocMore(d->size + 1, sizeof(Data)));
+ if (d->ref.isShared() || uint(d->size) + 2u > d->alloc)
+ reallocData(uint(d->size) + 2u, d->detachFlags() | Data::Grow);
d->data()[d->size++] = ch;
d->data()[d->size] = '\0';
return *this;
@@ -2219,7 +2183,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);
@@ -2551,7 +2515,7 @@ bool QByteArray::startsWith(const char *str) const
{
if (!str || !*str)
return true;
- int len = qstrlen(str);
+ int len = strlen(str);
if (d->size < len)
return false;
return qstrncmp(d->data(), str, len) == 0;
@@ -2596,7 +2560,7 @@ bool QByteArray::endsWith(const char *str) const
{
if (!str || !*str)
return true;
- int len = qstrlen(str);
+ int len = strlen(str);
if (d->size < len)
return false;
return qstrncmp(d->data() + d->size - len, str, len) == 0;
@@ -2674,7 +2638,7 @@ QByteArray QByteArray::right(int len) const
QByteArray QByteArray::mid(int pos, int len) const
{
- if (d == &shared_null.ba || d == &shared_empty.ba || pos > d->size)
+ if ((d->size == 0 && d->ref.isStatic()) || pos > d->size)
return QByteArray();
if (len < 0)
len = d->size - pos;
@@ -2744,9 +2708,8 @@ QByteArray QByteArray::toUpper() const
void QByteArray::clear()
{
if (!d->ref.deref())
- free(d);
- d = const_cast<Data *>(&shared_null.ba);
- d->ref.ref();
+ Data::deallocate(d);
+ d = Data::sharedNull();
}
#if !defined(QT_NO_DATASTREAM) || (defined(QT_BOOTSTRAPPED) && !defined(QT_BUILD_QMAKE))
@@ -3188,7 +3151,8 @@ QByteArray QByteArray::trimmed() const
}
int l = end - start + 1;
if (l <= 0) {
- return QByteArray(const_cast<Data *>(&shared_empty.ba), 0, 0);
+ QByteArrayDataPtr empty = { reinterpret_cast<QByteArrayData *>(Data::allocate(0)) };
+ return QByteArray(empty);
}
return QByteArray(s+start, l);
}
@@ -3267,7 +3231,7 @@ QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const
return result;
}
-bool QByteArray::isNull() const { return d == &shared_null.ba; }
+bool QByteArray::isNull() const { return d == QArrayData::sharedNull(); }
/*!
@@ -3895,19 +3859,15 @@ QByteArray QByteArray::fromRawData(const char *data, int size)
{
Data *x;
if (!data) {
- x = const_cast<Data *>(&shared_null.ba);
+ x = Data::sharedNull();
} else if (!size) {
- x = const_cast<Data *>(&shared_empty.ba);
+ x = Data::allocate(0);
} else {
- x = static_cast<Data *>(malloc(sizeof(Data) + 1));
+ x = Data::fromRawData(data, size);
Q_CHECK_PTR(x);
- x->ref = 1;
- x->size = size;
- x->alloc = 0;
- x->capacityReserved = false;
- x->offset = data - (x->d + sizeof(qptrdiff));
}
- return QByteArray(x, 0, 0);
+ QByteArrayDataPtr dataPtr = { reinterpret_cast<QByteArrayData *>(x) };
+ return QByteArray(dataPtr);
}
/*!
@@ -3926,14 +3886,14 @@ QByteArray QByteArray::fromRawData(const char *data, int size)
*/
QByteArray &QByteArray::setRawData(const char *data, uint size)
{
- if (d->ref != 1 || d->alloc) {
+ if (d->ref.isShared() || d->alloc) {
*this = fromRawData(data, size);
} else {
if (data) {
d->size = size;
- d->offset = data - (d->d + sizeof(qptrdiff));
+ d->offset = data - reinterpret_cast<char *>(d);
} else {
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
d->size = 0;
*d->data() = 0;
}