From ad35a41739c8e1fb6db62ed37b764448b2e59ece Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 11 Jul 2011 23:16:58 +0200 Subject: Refactor QByteArray to allow for const data Similar refactoring as done for QString. Make shared_null read-only, and add support for compile time generated QByteArrayData. Add support for properly reserving capacity. Change-Id: Ie4c41d4caac7b3b4bb1aef40c1c860a30b82edb8 Reviewed-on: http://codereview.qt.nokia.com/1484 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qbytearray.cpp | 311 +++++++++++++++++++++------------------ src/corelib/tools/qbytearray.h | 132 ++++++++++++----- 2 files changed, 257 insertions(+), 186 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 767b71338f..0c5276f442 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -57,7 +57,7 @@ #include #include -#define IS_RAW_DATA(d) ((d)->data != (d)->array) +#define IS_RAW_DATA(d) ((d)->offset != 0) QT_BEGIN_NAMESPACE @@ -546,7 +546,7 @@ QByteArray qUncompress(const uchar* data, int nbytes) qWarning("qUncompress: Input data is corrupted"); return QByteArray(); } - QByteArray::Data *p = static_cast(qRealloc(d.data(), sizeof(QByteArray::Data) + alloc)); + QByteArray::Data *p = static_cast(qRealloc(d.data(), sizeof(QByteArray::Data) + alloc + 1)); if (!p) { // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS qWarning("qUncompress: could not allocate enough memory to uncompress data"); @@ -554,8 +554,9 @@ QByteArray qUncompress(const uchar* data, int nbytes) } d.take(); // realloc was successful d.reset(p); + d->offset = 0; - int res = ::uncompress((uchar*)d->array, &len, + int res = ::uncompress((uchar*)d->data(), &len, (uchar*)data+4, nbytes-4); switch (res) { @@ -566,7 +567,7 @@ QByteArray qUncompress(const uchar* data, int nbytes) qWarning("qUncompress: Input data is corrupted"); return QByteArray(); } - QByteArray::Data *p = static_cast(qRealloc(d.data(), sizeof(QByteArray::Data) + len)); + QByteArray::Data *p = static_cast(qRealloc(d.data(), sizeof(QByteArray::Data) + len + 1)); if (!p) { // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS qWarning("qUncompress: could not allocate enough memory to uncompress data"); @@ -576,9 +577,11 @@ QByteArray qUncompress(const uchar* data, int nbytes) d.reset(p); } d->ref = 1; - d->alloc = d->size = len; - d->data = d->array; - d->array[len] = 0; + d->size = len; + d->alloc = len; + d->capacityReserved = false; + d->offset = 0; + d->data()[len] = 0; return QByteArray(d.take(), 0, 0); @@ -611,10 +614,10 @@ static inline char qToLower(char c) return c; } -QByteArray::Data QByteArray::shared_null = {Q_BASIC_ATOMIC_INITIALIZER(1), - 0, 0, shared_null.array, {0} }; -QByteArray::Data QByteArray::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), - 0, 0, shared_empty.array, {0} }; +QConstByteArrayData<1> QByteArray::shared_null = { { Q_REFCOUNT_INITIALIZER(-1), + 0, 0, 0, { 0 } }, { 0 } }; +QConstByteArrayData<1> QByteArray::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1), + 0, 0, 0, { 0 } }, { 0 } }; /*! \class QByteArray @@ -896,15 +899,15 @@ QByteArray &QByteArray::operator=(const char *str) { Data *x; if (!str) { - x = &shared_null; + x = const_cast(&shared_null.ba); } else if (!*str) { - x = &shared_empty; + x = const_cast(&shared_empty.ba); } else { int len = qstrlen(str); if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1)) realloc(len); x = d; - memcpy(x->data, str, len + 1); // include null terminator + memcpy(x->data(), str, len + 1); // include null terminator x->size = len; } x->ref.ref(); @@ -1294,19 +1297,20 @@ void QByteArray::chop(int n) QByteArray::QByteArray(const char *str) { if (!str) { - d = &shared_null; + d = const_cast(&shared_null.ba); } else if (!*str) { - d = &shared_empty; + d = const_cast(&shared_empty.ba); } else { int len = qstrlen(str); - d = static_cast(qMalloc(sizeof(Data)+len)); + d = static_cast(qMalloc(sizeof(Data) + len + 1)); Q_CHECK_PTR(d); - d->ref = 0;; - d->alloc = d->size = len; - d->data = d->array; - memcpy(d->array, str, len+1); // include null terminator + d->ref = 1; + d->size = len; + d->alloc = len; + d->capacityReserved = false; + d->offset = 0; + memcpy(d->data(), str, len+1); // include null terminator } - d->ref.ref(); } /*! @@ -1323,19 +1327,20 @@ QByteArray::QByteArray(const char *str) QByteArray::QByteArray(const char *data, int size) { if (!data) { - d = &shared_null; + d = const_cast(&shared_null.ba); } else if (size <= 0) { - d = &shared_empty; + d = const_cast(&shared_empty.ba); } else { - d = static_cast(qMalloc(sizeof(Data) + size)); + d = static_cast(qMalloc(sizeof(Data) + size + 1)); Q_CHECK_PTR(d); - d->ref = 0; - d->alloc = d->size = size; - d->data = d->array; - memcpy(d->array, data, size); - d->array[size] = '\0'; + d->ref = 1; + d->size = size; + d->alloc = size; + d->capacityReserved = false; + d->offset = 0; + memcpy(d->data(), data, size); + d->data()[size] = '\0'; } - d->ref.ref(); } /*! @@ -1348,17 +1353,18 @@ QByteArray::QByteArray(const char *data, int size) QByteArray::QByteArray(int size, char ch) { if (size <= 0) { - d = &shared_null; + d = const_cast(&shared_null.ba); } else { - d = static_cast(qMalloc(sizeof(Data)+size)); + d = static_cast(qMalloc(sizeof(Data) + size + 1)); Q_CHECK_PTR(d); - d->ref = 0; - d->alloc = d->size = size; - d->data = d->array; - d->array[size] = '\0'; - memset(d->array, ch, size); + d->ref = 1; + d->size = size; + d->alloc = size; + d->capacityReserved = false; + d->offset = 0; + memset(d->data(), ch, size); + d->data()[size] = '\0'; } - d->ref.ref(); } /*! @@ -1369,12 +1375,14 @@ QByteArray::QByteArray(int size, char ch) QByteArray::QByteArray(int size, Qt::Initialization) { - d = static_cast(qMalloc(sizeof(Data)+size)); + d = static_cast(qMalloc(sizeof(Data) + size + 1)); Q_CHECK_PTR(d); d->ref = 1; - d->alloc = d->size = size; - d->data = d->array; - d->array[size] = '\0'; + d->size = size; + d->alloc = size; + d->capacityReserved = false; + d->offset = 0; + d->data()[size] = '\0'; } /*! @@ -1392,13 +1400,20 @@ QByteArray::QByteArray(int size, Qt::Initialization) void QByteArray::resize(int size) { - if (size <= 0) { - Data *x = &shared_empty; - x->ref.ref(); + if (size < 0) + size = 0; + + if (d->offset && d->ref == 1 && size < d->size) { + d->size = size; + return; + } + + if (size == 0 && !d->capacityReserved) { + Data *x = const_cast(&shared_empty.ba); if (!d->ref.deref()) qFree(d); d = x; - } else if (d == &shared_null) { + } else if (d == &shared_null.ba || d == &shared_empty.ba) { // // Optimize the idiom: // QByteArray a; @@ -1407,22 +1422,21 @@ void QByteArray::resize(int size) // which is used in place of the Qt 3 idiom: // QByteArray a(sz); // - Data *x = static_cast(qMalloc(sizeof(Data)+size)); + Data *x = static_cast(qMalloc(sizeof(Data) + size + 1)); Q_CHECK_PTR(x); x->ref = 1; - x->alloc = x->size = size; - x->data = x->array; - x->array[size] = '\0'; - (void) d->ref.deref(); // cannot be 0, x points to shared_null + x->size = size; + x->alloc = size; + x->capacityReserved = false; + x->offset = 0; + x->data()[size] = '\0'; d = x; } else { - if (d->ref != 1 || size > d->alloc || (size < d->size && size < d->alloc >> 1)) + if (d->ref != 1 || size > d->alloc || (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) realloc(qAllocMore(size, sizeof(Data))); if (d->alloc >= size) { d->size = size; - if (d->data == d->array) { - d->array[size] = '\0'; - } + d->data()[size] = '\0'; } } } @@ -1442,29 +1456,30 @@ QByteArray &QByteArray::fill(char ch, int size) { resize(size < 0 ? d->size : size); if (d->size) - memset(d->data, ch, d->size); + memset(d->data(), ch, d->size); return *this; } void QByteArray::realloc(int alloc) { - if (d->ref != 1 || d->data != d->array) { - Data *x = static_cast(qMalloc(sizeof(Data) + alloc)); + if (d->ref != 1 || d->offset) { + Data *x = static_cast(qMalloc(sizeof(Data) + alloc + 1)); Q_CHECK_PTR(x); - x->size = qMin(alloc, d->size); - ::memcpy(x->array, d->data, x->size); - x->array[x->size] = '\0'; x->ref = 1; + x->size = qMin(alloc, d->size); x->alloc = alloc; - x->data = x->array; + x->capacityReserved = d->capacityReserved; + x->offset = 0; + ::memcpy(x->data(), d->data(), x->size); + x->data()[x->size] = '\0'; if (!d->ref.deref()) qFree(d); d = x; } else { - Data *x = static_cast(qRealloc(d, sizeof(Data) + alloc)); + Data *x = static_cast(qRealloc(d, sizeof(Data) + alloc + 1)); Q_CHECK_PTR(x); x->alloc = alloc; - x->data = x->array; + x->offset = 0; d = x; } } @@ -1486,7 +1501,7 @@ void QByteArray::expand(int i) QByteArray QByteArray::nulTerminated() const { // is this fromRawData? - if (d->data == d->array) + if (!d->offset) return *this; // no, then we're sure we're zero terminated QByteArray copy(*this); @@ -1517,9 +1532,9 @@ QByteArray QByteArray::nulTerminated() const QByteArray &QByteArray::prepend(const QByteArray &ba) { - if ((d == &shared_null || d == &shared_empty) && !IS_RAW_DATA(ba.d)) { + if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) { *this = ba; - } else if (ba.d != &shared_null) { + } else if (ba.d != &shared_null.ba) { QByteArray tmp = *this; *this = ba; append(tmp); @@ -1550,10 +1565,10 @@ QByteArray &QByteArray::prepend(const char *str, int len) if (str) { if (d->ref != 1 || d->size + len > d->alloc) realloc(qAllocMore(d->size + len, sizeof(Data))); - memmove(d->data+len, d->data, d->size); - memcpy(d->data, str, len); + memmove(d->data()+len, d->data(), d->size); + memcpy(d->data(), str, len); d->size += len; - d->data[d->size] = '\0'; + d->data()[d->size] = '\0'; } return *this; } @@ -1568,10 +1583,10 @@ QByteArray &QByteArray::prepend(char ch) { if (d->ref != 1 || d->size + 1 > d->alloc) realloc(qAllocMore(d->size + 1, sizeof(Data))); - memmove(d->data+1, d->data, d->size); - d->data[0] = ch; + memmove(d->data()+1, d->data(), d->size); + d->data()[0] = ch; ++d->size; - d->data[d->size] = '\0'; + d->data()[d->size] = '\0'; return *this; } @@ -1601,14 +1616,14 @@ QByteArray &QByteArray::prepend(char ch) QByteArray &QByteArray::append(const QByteArray &ba) { - if ((d == &shared_null || d == &shared_empty) && !IS_RAW_DATA(ba.d)) { + if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) { *this = ba; - } else if (ba.d != &shared_null) { + } else if (ba.d != &shared_null.ba) { if (d->ref != 1 || d->size + ba.d->size > d->alloc) realloc(qAllocMore(d->size + ba.d->size, sizeof(Data))); - memcpy(d->data + d->size, ba.d->data, ba.d->size); + memcpy(d->data() + d->size, ba.d->data(), ba.d->size); d->size += ba.d->size; - d->data[d->size] = '\0'; + d->data()[d->size] = '\0'; } return *this; } @@ -1640,7 +1655,7 @@ QByteArray& QByteArray::append(const char *str) int len = qstrlen(str); if (d->ref != 1 || d->size + len > d->alloc) realloc(qAllocMore(d->size + len, sizeof(Data))); - memcpy(d->data + d->size, str, len + 1); // include null terminator + memcpy(d->data() + d->size, str, len + 1); // include null terminator d->size += len; } return *this; @@ -1665,9 +1680,9 @@ QByteArray &QByteArray::append(const char *str, int len) if (str && len) { if (d->ref != 1 || d->size + len > d->alloc) realloc(qAllocMore(d->size + len, sizeof(Data))); - memcpy(d->data + d->size, str, len); // include null terminator + memcpy(d->data() + d->size, str, len); // include null terminator d->size += len; - d->data[d->size] = '\0'; + d->data()[d->size] = '\0'; } return *this; } @@ -1682,8 +1697,8 @@ QByteArray& QByteArray::append(char ch) { if (d->ref != 1 || d->size + 1 > d->alloc) realloc(qAllocMore(d->size + 1, sizeof(Data))); - d->data[d->size++] = ch; - d->data[d->size] = '\0'; + d->data()[d->size++] = ch; + d->data()[d->size] = '\0'; return *this; } @@ -1724,7 +1739,7 @@ static inline QByteArray &qbytearray_insert(QByteArray *ba, QByteArray &QByteArray::insert(int i, const QByteArray &ba) { QByteArray copy(ba); - return qbytearray_insert(this, i, copy.d->data, copy.d->size); + return qbytearray_insert(this, i, copy.d->data(), copy.d->size); } /*! @@ -1812,7 +1827,7 @@ QByteArray &QByteArray::remove(int pos, int len) if (pos + len >= d->size) { resize(pos); } else { - memmove(d->data + pos, d->data + pos + len, d->size - pos - len); + memmove(d->data() + pos, d->data() + pos + len, d->size - pos - len); resize(d->size - len); } return *this; @@ -1832,7 +1847,7 @@ QByteArray &QByteArray::replace(int pos, int len, const QByteArray &after) { if (len == after.d->size && (pos + len <= d->size)) { detach(); - memmove(d->data + pos, after.d->data, len*sizeof(char)); + memmove(d->data() + pos, after.d->data(), len*sizeof(char)); return *this; } else { QByteArray copy(after); @@ -1869,7 +1884,7 @@ QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen) { if (len == alen && (pos + len <= d->size)) { detach(); - memcpy(d->data + pos, after, len*sizeof(char)); + memcpy(d->data() + pos, after, len*sizeof(char)); return *this; } else { remove(pos, len); @@ -1936,13 +1951,13 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after // protect against before or after being part of this const char *a = after; const char *b = before; - if (after >= d->data && after < d->data + d->size) { + if (after >= d->data() && after < d->data() + d->size) { char *copy = (char *)malloc(asize); Q_CHECK_PTR(copy); memcpy(copy, after, asize); a = copy; } - if (before >= d->data && before < d->data + d->size) { + if (before >= d->data() && before < d->data() + d->size) { char *copy = (char *)malloc(bsize); Q_CHECK_PTR(copy); memcpy(copy, before, bsize); @@ -2019,7 +2034,7 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after resize(newlen); len = newlen; } - d = this->d->data; + d = this->d->data(); while(pos) { pos--; @@ -2192,19 +2207,19 @@ QByteArray QByteArray::repeated(int times) const if (result.d->alloc != resultSize) return QByteArray(); // not enough memory - memcpy(result.d->data, d->data, d->size); + memcpy(result.d->data(), d->data(), d->size); int sizeSoFar = d->size; - char *end = result.d->data + sizeSoFar; + char *end = result.d->data() + sizeSoFar; const int halfResultSize = resultSize >> 1; while (sizeSoFar <= halfResultSize) { - memcpy(end, result.d->data, sizeSoFar); + memcpy(end, result.d->data(), sizeSoFar); end += sizeSoFar; sizeSoFar <<= 1; } - memcpy(end, result.d->data, resultSize - sizeSoFar); - result.d->data[resultSize] = '\0'; + memcpy(end, result.d->data(), resultSize - sizeSoFar); + result.d->data()[resultSize] = '\0'; result.d->size = resultSize; return result; } @@ -2231,13 +2246,13 @@ int QByteArray::indexOf(const QByteArray &ba, int from) const if (ol == 0) return from; if (ol == 1) - return indexOf(*ba.d->data, from); + return indexOf(*ba.d->data(), from); const int l = d->size; if (from > d->size || ol + from > l) return -1; - return qFindByteArray(d->data, d->size, from, ba.d->data, ol); + return qFindByteArray(d->data(), d->size, from, ba.d->data(), ol); } /*! \fn int QByteArray::indexOf(const QString &str, int from) const @@ -2279,7 +2294,7 @@ int QByteArray::indexOf(const char *c, int from) const if (ol == 0) return from; - return qFindByteArray(d->data, d->size, from, c, ol); + return qFindByteArray(d->data(), d->size, from, c, ol); } /*! @@ -2300,11 +2315,11 @@ int QByteArray::indexOf(char ch, int from) const if (from < 0) from = qMax(from + d->size, 0); if (from < d->size) { - const char *n = d->data + from - 1; - const char *e = d->data + d->size; + const char *n = d->data() + from - 1; + const char *e = d->data() + d->size; while (++n != e) if (*n == ch) - return n - d->data; + return n - d->data(); } return -1; } @@ -2361,9 +2376,9 @@ int QByteArray::lastIndexOf(const QByteArray &ba, int from) const { const int ol = ba.d->size; if (ol == 1) - return lastIndexOf(*ba.d->data, from); + return lastIndexOf(*ba.d->data(), from); - return lastIndexOfHelper(d->data, d->size, ba.d->data, ol, from); + return lastIndexOfHelper(d->data(), d->size, ba.d->data(), ol, from); } /*! \fn int QByteArray::lastIndexOf(const QString &str, int from) const @@ -2400,7 +2415,7 @@ int QByteArray::lastIndexOf(const char *str, int from) const if (ol == 1) return lastIndexOf(*str, from); - return lastIndexOfHelper(d->data, d->size, str, ol, from); + return lastIndexOfHelper(d->data(), d->size, str, ol, from); } /*! @@ -2424,8 +2439,8 @@ int QByteArray::lastIndexOf(char ch, int from) const else if (from > d->size) from = d->size-1; if (from >= 0) { - const char *b = d->data; - const char *n = d->data + from + 1; + const char *b = d->data(); + const char *n = d->data() + from + 1; while (n-- != b) if (*n == ch) return n - b; @@ -2479,8 +2494,8 @@ int QByteArray::count(const char *str) const int QByteArray::count(char ch) const { int num = 0; - const char *i = d->data + d->size; - const char *b = d->data; + const char *i = d->data() + d->size; + const char *b = d->data(); while (i != b) if (*--i == ch) ++num; @@ -2509,7 +2524,7 @@ bool QByteArray::startsWith(const QByteArray &ba) const return true; if (d->size < ba.d->size) return false; - return memcmp(d->data, ba.d->data, ba.d->size) == 0; + return memcmp(d->data(), ba.d->data(), ba.d->size) == 0; } /*! \overload @@ -2524,7 +2539,7 @@ bool QByteArray::startsWith(const char *str) const int len = qstrlen(str); if (d->size < len) return false; - return qstrncmp(d->data, str, len) == 0; + return qstrncmp(d->data(), str, len) == 0; } /*! \overload @@ -2536,7 +2551,7 @@ bool QByteArray::startsWith(char ch) const { if (d->size == 0) return false; - return d->data[0] == ch; + return d->data()[0] == ch; } /*! @@ -2554,7 +2569,7 @@ bool QByteArray::endsWith(const QByteArray &ba) const return true; if (d->size < ba.d->size) return false; - return memcmp(d->data + d->size - ba.d->size, ba.d->data, ba.d->size) == 0; + return memcmp(d->data() + d->size - ba.d->size, ba.d->data(), ba.d->size) == 0; } /*! \overload @@ -2569,7 +2584,7 @@ bool QByteArray::endsWith(const char *str) const int len = qstrlen(str); if (d->size < len) return false; - return qstrncmp(d->data + d->size - len, str, len) == 0; + return qstrncmp(d->data() + d->size - len, str, len) == 0; } /*! \overload @@ -2581,7 +2596,7 @@ bool QByteArray::endsWith(char ch) const { if (d->size == 0) return false; - return d->data[d->size - 1] == ch; + return d->data()[d->size - 1] == ch; } /*! @@ -2603,7 +2618,7 @@ QByteArray QByteArray::left(int len) const return *this; if (len < 0) len = 0; - return QByteArray(d->data, len); + return QByteArray(d->data(), len); } /*! @@ -2625,7 +2640,7 @@ QByteArray QByteArray::right(int len) const return *this; if (len < 0) len = 0; - return QByteArray(d->data + d->size - len, len); + return QByteArray(d->data() + d->size - len, len); } /*! @@ -2644,7 +2659,7 @@ QByteArray QByteArray::right(int len) const QByteArray QByteArray::mid(int pos, int len) const { - if (d == &shared_null || d == &shared_empty || pos >= d->size) + if (d == &shared_null.ba || d == &shared_empty.ba || pos >= d->size) return QByteArray(); if (len < 0) len = d->size - pos; @@ -2656,7 +2671,7 @@ QByteArray QByteArray::mid(int pos, int len) const len = d->size - pos; if (pos == 0 && len == d->size) return *this; - return QByteArray(d->data + pos, len); + return QByteArray(d->data() + pos, len); } /*! @@ -2715,7 +2730,7 @@ void QByteArray::clear() { if (!d->ref.deref()) qFree(d); - d = &shared_null; + d = const_cast(&shared_null.ba); d->ref.ref(); } @@ -3106,10 +3121,10 @@ QByteArray QByteArray::simplified() const if (d->size == 0) return *this; QByteArray result(d->size, Qt::Uninitialized); - const char *from = d->data; + const char *from = d->data(); const char *fromend = from + d->size; int outc=0; - char *to = result.d->data; + char *to = result.d->data(); for (;;) { while (from!=fromend && isspace(uchar(*from))) from++; @@ -3145,7 +3160,7 @@ QByteArray QByteArray::trimmed() const { if (d->size == 0) return *this; - const char *s = d->data; + const char *s = d->data(); if (!isspace(uchar(*s)) && !isspace(uchar(s[d->size-1]))) return *this; int start = 0; @@ -3158,8 +3173,7 @@ QByteArray QByteArray::trimmed() const } int l = end - start + 1; if (l <= 0) { - shared_empty.ref.ref(); - return QByteArray(&shared_empty, 0, 0); + return QByteArray(const_cast(&shared_empty.ba), 0, 0); } return QByteArray(s+start, l); } @@ -3190,8 +3204,8 @@ QByteArray QByteArray::leftJustified(int width, char fill, bool truncate) const if (padlen > 0) { result.resize(len+padlen); if (len) - memcpy(result.d->data, d->data, len); - memset(result.d->data+len, fill, padlen); + memcpy(result.d->data(), d->data(), len); + memset(result.d->data()+len, fill, padlen); } else { if (truncate) result = left(width); @@ -3227,8 +3241,8 @@ QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const if (padlen > 0) { result.resize(len+padlen); if (len) - memcpy(result.d->data+padlen, data(), len); - memset(result.d->data, fill, padlen); + memcpy(result.d->data()+padlen, data(), len); + memset(result.d->data(), fill, padlen); } else { if (truncate) result = left(width); @@ -3238,7 +3252,7 @@ QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const return result; } -bool QByteArray::isNull() const { return d == &shared_null; } +bool QByteArray::isNull() const { return d == &shared_null.ba; } /*! @@ -3562,13 +3576,13 @@ QByteArray QByteArray::toBase64() const char *out = tmp.data(); while (i < d->size) { int chunk = 0; - chunk |= int(uchar(d->data[i++])) << 16; + chunk |= int(uchar(d->data()[i++])) << 16; if (i == d->size) { padlen = 2; } else { - chunk |= int(uchar(d->data[i++])) << 8; + chunk |= int(uchar(d->data()[i++])) << 8; if (i == d->size) padlen = 1; - else chunk |= int(uchar(d->data[i++])); + else chunk |= int(uchar(d->data()[i++])); } int j = (chunk & 0x00fc0000) >> 18; @@ -3864,17 +3878,20 @@ QByteArray QByteArray::number(double n, char f, int prec) QByteArray QByteArray::fromRawData(const char *data, int size) { - Data *x = static_cast(qMalloc(sizeof(Data))); - Q_CHECK_PTR(x); - if (data) { - x->data = const_cast(data); + Data *x; + if (!data) { + x = const_cast(&shared_null.ba); + } else if (!size) { + x = const_cast(&shared_empty.ba); } else { - x->data = x->array; - size = 0; + x = static_cast(qMalloc(sizeof(Data) + 1)); + Q_CHECK_PTR(x); + x->ref = 1; + x->size = size; + x->alloc = 0; + x->capacityReserved = false; + x->offset = data - (x->d + sizeof(qptrdiff)); } - x->ref = 1; - x->alloc = x->size = size; - *x->array = '\0'; return QByteArray(x, 0, 0); } @@ -3898,13 +3915,13 @@ QByteArray &QByteArray::setRawData(const char *data, uint size) *this = fromRawData(data, size); } else { if (data) { - d->data = const_cast(data); + d->size = size; + d->offset = data - (d->d + sizeof(qptrdiff)); } else { - d->data = d->array; - size = 0; + d->offset = 0; + d->size = 0; + *d->data() = 0; } - d->alloc = d->size = size; - *d->array = '\0'; } return *this; } @@ -4013,7 +4030,7 @@ QByteArray QByteArray::toHex() const { QByteArray hex(d->size * 2, Qt::Uninitialized); char *hexData = hex.data(); - const uchar *data = (const uchar *)d->data; + const uchar *data = (const uchar *)d->data(); for (int i = 0; i < d->size; ++i) { int j = (data[i] >> 4) & 0xf; if (j <= 9) diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 26cf2af59c..dbac302d05 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -42,7 +42,7 @@ #ifndef QBYTEARRAY_H #define QBYTEARRAY_H -#include +#include #include #include @@ -119,18 +119,65 @@ class QString; class QDataStream; template class QList; +struct QByteArrayData +{ + QtPrivate::RefCount ref; + int size; + uint alloc : 31; + uint capacityReserved : 1; + union { + qptrdiff offset; // will always work as we add/subtract from a ushort ptr + char d[sizeof(qptrdiff)]; + }; + inline char *data() { return d + sizeof(qptrdiff) + offset; } + inline const char *data() const { return d + sizeof(qptrdiff) + offset; } +}; + +template struct QConstByteArrayData +{ + const QByteArrayData ba; + const char data[n]; +}; + +template struct QConstByteArrayDataPtr +{ + const QConstByteArrayData *ptr; +}; + + +#if defined(Q_COMPILER_LAMBDA) +# define QByteArrayLiteral(str) ([]() { \ + enum { Size = sizeof(str) }; \ + static const QConstByteArrayData qbytearray_literal = \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ + return holder; }()) + +#elif defined(Q_CC_GNU) +// We need to create a QByteArrayData in the .rodata section of memory +// and the only way to do that is to create a "static const" variable. +// To do that, we need the __extension__ {( )} trick which only GCC supports + +# define QByteArrayLiteral(str) \ + __extension__ ({ \ + enum { Size = sizeof(str) }; \ + static const QConstByteArrayData qbytearray_literal = \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ + holder; }) +#endif + +#ifndef QByteArrayLiteral +// no lambdas, not GCC, use const char * instead + +# define QByteArrayLiteral(str) (str) +#endif + + class Q_CORE_EXPORT QByteArray { private: - struct Data { - QBasicAtomicInt ref; - int alloc, size; - // ### Qt 5.0: We need to add the missing capacity bit - // (like other tool classes have), to maintain the - // reserved memory on resize. - char *data; - char array[1]; - }; + typedef QByteArrayData Data; public: inline QByteArray(); @@ -330,10 +377,17 @@ public: int length() const { return d->size; } bool isNull() const; + template + inline QByteArray(const QConstByteArrayData &dd) + : d(const_cast(&dd.str)) {} + template + Q_DECL_CONSTEXPR inline QByteArray(QConstByteArrayDataPtr dd) + : d(const_cast(&dd.ptr->ba)) {} + private: operator QNoImplicitBoolCast() const; - static Data shared_null; - static Data shared_empty; + static QConstByteArrayData<1> shared_null; + static QConstByteArrayData<1> shared_empty; Data *d; QByteArray(Data *dd, int /*dummy*/, int /*dummy*/) : d(dd) {} void realloc(int alloc); @@ -348,34 +402,34 @@ public: inline DataPtr &data_ptr() { return d; } }; -inline QByteArray::QByteArray(): d(&shared_null) { d->ref.ref(); } +inline QByteArray::QByteArray(): d(const_cast(&shared_null.ba)) { d->ref.ref(); } inline QByteArray::~QByteArray() { if (!d->ref.deref()) qFree(d); } inline int QByteArray::size() const { return d->size; } inline char QByteArray::at(int i) const -{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } +{ Q_ASSERT(i >= 0 && i < size()); return d->data()[i]; } inline char QByteArray::operator[](int i) const -{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } +{ Q_ASSERT(i >= 0 && i < size()); return d->data()[i]; } inline char QByteArray::operator[](uint i) const -{ Q_ASSERT(i < uint(size())); return d->data[i]; } +{ Q_ASSERT(i < uint(size())); return d->data()[i]; } inline bool QByteArray::isEmpty() const { return d->size == 0; } #ifndef QT_NO_CAST_FROM_BYTEARRAY inline QByteArray::operator const char *() const -{ return d->data; } +{ return d->data(); } inline QByteArray::operator const void *() const -{ return d->data; } +{ return d->data(); } #endif inline char *QByteArray::data() -{ detach(); return d->data; } +{ detach(); return d->data(); } inline const char *QByteArray::data() const -{ return d->data; } +{ return d->data(); } inline const char *QByteArray::constData() const -{ return d->data; } +{ return d->data(); } inline void QByteArray::detach() -{ if (d->ref != 1 || d->data != d->array) realloc(d->size); } +{ if (d->ref != 1 || d->offset) realloc(d->size); } inline bool QByteArray::isDetached() const { return d->ref == 1; } inline QByteArray::QByteArray(const QByteArray &a) : d(a.d) @@ -385,10 +439,10 @@ inline int QByteArray::capacity() const { return d->alloc; } inline void QByteArray::reserve(int asize) -{ if (d->ref != 1 || asize > d->alloc) realloc(asize); } +{ if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true; } inline void QByteArray::squeeze() -{ if (d->size < d->alloc) realloc(d->size); } +{ if (d->size < d->alloc) realloc(d->size); d->capacityReserved = false; } class Q_CORE_EXPORT QByteRef { QByteArray &a; @@ -398,25 +452,25 @@ class Q_CORE_EXPORT QByteRef { friend class QByteArray; public: inline operator char() const - { return i < a.d->size ? a.d->data[i] : char(0); } + { return i < a.d->size ? a.d->data()[i] : char(0); } inline QByteRef &operator=(char c) { if (i >= a.d->size) a.expand(i); else a.detach(); - a.d->data[i] = c; return *this; } + a.d->data()[i] = c; return *this; } inline QByteRef &operator=(const QByteRef &c) { if (i >= a.d->size) a.expand(i); else a.detach(); - a.d->data[i] = c.a.d->data[c.i]; return *this; } + a.d->data()[i] = c.a.d->data()[c.i]; return *this; } inline bool operator==(char c) const - { return a.d->data[i] == c; } + { return a.d->data()[i] == c; } inline bool operator!=(char c) const - { return a.d->data[i] != c; } + { return a.d->data()[i] != c; } inline bool operator>(char c) const - { return a.d->data[i] > c; } + { return a.d->data()[i] > c; } inline bool operator>=(char c) const - { return a.d->data[i] >= c; } + { return a.d->data()[i] >= c; } inline bool operator<(char c) const - { return a.d->data[i] < c; } + { return a.d->data()[i] < c; } inline bool operator<=(char c) const - { return a.d->data[i] <= c; } + { return a.d->data()[i] <= c; } }; inline QByteRef QByteArray::operator[](int i) @@ -424,17 +478,17 @@ inline QByteRef QByteArray::operator[](int i) inline QByteRef QByteArray::operator[](uint i) { return QByteRef(*this, i); } inline QByteArray::iterator QByteArray::begin() -{ detach(); return d->data; } +{ detach(); return d->data(); } inline QByteArray::const_iterator QByteArray::begin() const -{ return d->data; } +{ return d->data(); } inline QByteArray::const_iterator QByteArray::constBegin() const -{ return d->data; } +{ return d->data(); } inline QByteArray::iterator QByteArray::end() -{ detach(); return d->data + d->size; } +{ detach(); return d->data() + d->size; } inline QByteArray::const_iterator QByteArray::end() const -{ return d->data + d->size; } +{ return d->data() + d->size; } inline QByteArray::const_iterator QByteArray::constEnd() const -{ return d->data + d->size; } +{ return d->data() + d->size; } inline QByteArray &QByteArray::operator+=(char c) { return append(c); } inline QByteArray &QByteArray::operator+=(const char *s) -- cgit v1.2.3