summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/text/qbytearray.cpp24
-rw-r--r--src/corelib/text/qbytearray.h8
-rw-r--r--src/corelib/text/qstring.cpp18
-rw-r--r--src/corelib/text/qstring.h10
-rw-r--r--src/corelib/tools/qarraydata.cpp3
-rw-r--r--src/corelib/tools/qarraydata.h12
-rw-r--r--src/corelib/tools/qarraydatapointer.h7
-rw-r--r--src/corelib/tools/qvector.h3
-rw-r--r--tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp2
-rw-r--r--tests/auto/corelib/tools/qarraydata/simplevector.h10
10 files changed, 54 insertions, 43 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index d7fcfce90c..da91a93700 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -63,7 +63,7 @@
#include <string.h>
#include <stdlib.h>
-#define IS_RAW_DATA(d) (!(d)->isMutable())
+#define IS_RAW_DATA(d) ((d)->flags & QArrayData::RawDataType)
QT_BEGIN_NAMESPACE
@@ -1208,7 +1208,7 @@ QByteArray &QByteArray::operator=(const char *str)
} else {
const int len = int(strlen(str));
const int fullLen = len + 1;
- if (d->ref.isShared() || fullLen > int(d->allocatedCapacity())
+ if (d->needsDetach() || fullLen > int(d->allocatedCapacity())
|| (len < d->size && fullLen < int(d->allocatedCapacity() >> 1)))
reallocData(fullLen, d->detachFlags());
x = d;
@@ -1755,7 +1755,7 @@ void QByteArray::resize(int size)
if (size < 0)
size = 0;
- if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) {
+ if (!d->ref.isShared() && !d->isMutable() && size < d->size) {
d->size = size;
return;
}
@@ -1775,9 +1775,9 @@ void QByteArray::resize(int size)
x->data()[size] = '\0';
d = x;
} else {
- if (d->ref.isShared() || size > capacity())
+ if (d->needsDetach() || size > capacity())
reallocData(uint(size) + 1u, d->detachFlags() | Data::GrowsForward);
- if (d->allocatedCapacity()) {
+ if (d->isMutable()) {
d->size = size;
d->data()[size] = '\0';
}
@@ -1805,7 +1805,7 @@ QByteArray &QByteArray::fill(char ch, int size)
void QByteArray::reallocData(uint alloc, Data::ArrayOptions options)
{
- if (d->ref.isShared() || IS_RAW_DATA(d)) {
+ if (d->needsDetach()) {
Data *x = Data::allocate(alloc, options);
Q_CHECK_PTR(x);
x->size = qMin(int(alloc) - 1, d->size);
@@ -1900,7 +1900,7 @@ QByteArray &QByteArray::prepend(const char *str)
QByteArray &QByteArray::prepend(const char *str, int len)
{
if (str) {
- if (d->ref.isShared() || d->size + len > capacity())
+ if (d->needsDetach() || d->size + len > capacity())
reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::GrowsForward);
memmove(d->data()+len, d->data(), d->size);
memcpy(d->data(), str, len);
@@ -1926,7 +1926,7 @@ QByteArray &QByteArray::prepend(const char *str, int len)
QByteArray &QByteArray::prepend(char ch)
{
- if (d->ref.isShared() || d->size + 1 > capacity())
+ if (d->needsDetach() || d->size + 1 > capacity())
reallocData(uint(d->size) + 2u, d->detachFlags() | Data::GrowsForward);
memmove(d->data()+1, d->data(), d->size);
d->data()[0] = ch;
@@ -1964,7 +1964,7 @@ QByteArray &QByteArray::append(const QByteArray &ba)
if (d->size == 0 && d->ref.isStatic() && !IS_RAW_DATA(ba.d)) {
*this = ba;
} else if (ba.d->size != 0) {
- if (d->ref.isShared() || d->size + ba.d->size > capacity())
+ if (d->needsDetach() || d->size + ba.d->size > capacity())
reallocData(uint(d->size + ba.d->size) + 1u, d->detachFlags() | Data::GrowsForward);
memcpy(d->data() + d->size, ba.d->data(), ba.d->size);
d->size += ba.d->size;
@@ -1996,7 +1996,7 @@ QByteArray& QByteArray::append(const char *str)
{
if (str) {
const int len = int(strlen(str));
- if (d->ref.isShared() || d->size + len > capacity())
+ if (d->needsDetach() || d->size + len > capacity())
reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::GrowsForward);
memcpy(d->data() + d->size, str, len + 1); // include null terminator
d->size += len;
@@ -2021,7 +2021,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 > capacity())
+ if (d->needsDetach() || d->size + len > capacity())
reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::GrowsForward);
memcpy(d->data() + d->size, str, len); // include null terminator
d->size += len;
@@ -2049,7 +2049,7 @@ QByteArray &QByteArray::append(const char *str, int len)
QByteArray& QByteArray::append(char ch)
{
- if (d->ref.isShared() || d->size + 1 > capacity())
+ if (d->needsDetach() || d->size + 1 > capacity())
reallocData(uint(d->size) + 2u, d->detachFlags() | Data::GrowsForward);
d->data()[d->size++] = ch;
d->data()[d->size] = '\0';
diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h
index 611cacc646..597bc8bcb3 100644
--- a/src/corelib/text/qbytearray.h
+++ b/src/corelib/text/qbytearray.h
@@ -495,7 +495,7 @@ inline const char *QByteArray::data() const
inline const char *QByteArray::constData() const
{ return d->data(); }
inline void QByteArray::detach()
-{ if (d->ref.isShared() || !d->isMutable()) reallocData(uint(d->size) + 1u, d->detachFlags()); }
+{ if (d->needsDetach()) reallocData(uint(d->size) + 1u, d->detachFlags()); }
inline bool QByteArray::isDetached() const
{ return !d->ref.isShared(); }
inline QByteArray::QByteArray(const QByteArray &a) noexcept : d(a.d)
@@ -506,7 +506,7 @@ inline int QByteArray::capacity() const
inline void QByteArray::reserve(int asize)
{
- if (d->ref.isShared() || asize > capacity()) {
+ if (d->needsDetach() || asize > capacity()) {
reallocData(qMax(uint(size()), uint(asize)) + 1u, d->detachFlags() | Data::CapacityReserved);
} else {
d->flags |= Data::CapacityReserved;
@@ -515,7 +515,9 @@ inline void QByteArray::reserve(int asize)
inline void QByteArray::squeeze()
{
- if (d->ref.isShared() || d->size < capacity()) {
+ if ((d->flags & Data::CapacityReserved) == 0)
+ return;
+ if (d->needsDetach() || d->size < capacity()) {
reallocData(uint(d->size) + 1u, d->detachFlags() & ~Data::CapacityReserved);
} else {
d->flags &= ~Data::CapacityReserved;
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index d0f141e079..ab08d497bd 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -100,7 +100,7 @@
#define ULLONG_MAX quint64_C(18446744073709551615)
#endif
-#define IS_RAW_DATA(d) (!(d)->isMutable())
+#define IS_RAW_DATA(d) ((d)->flags & QArrayData::RawDataType)
QT_BEGIN_NAMESPACE
@@ -2265,14 +2265,14 @@ void QString::resize(int size)
if (size < 0)
size = 0;
- if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) {
+ if (!d->ref.isShared() && !d->isMutable() && size < d->size) {
d->size = size;
return;
}
- if (d->ref.isShared() || uint(size) + 1u > d->allocatedCapacity())
+ if (d->needsDetach() || size > capacity())
reallocData(uint(size) + 1u, true);
- if (d->flags & Data::AllocatedDataType) {
+ if (d->isMutable()) {
d->size = size;
d->data()[size] = '\0';
}
@@ -2353,7 +2353,7 @@ void QString::reallocData(uint alloc, bool grow)
if (grow)
allocOptions |= QArrayData::GrowsForward;
- if (d->ref.isShared() || IS_RAW_DATA(d)) {
+ if (d->needsDetach()) {
Data *x = Data::allocate(alloc, allocOptions);
Q_CHECK_PTR(x);
x->size = qMin(int(alloc) - 1, d->size);
@@ -2658,7 +2658,7 @@ QString &QString::append(const QString &str)
if (d == Data::sharedNull()) {
operator=(str);
} else {
- if (d->ref.isShared() || d->size + str.d->size > capacity())
+ 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;
@@ -2696,7 +2696,7 @@ QString &QString::append(QLatin1String str)
const char *s = str.latin1();
if (s) {
int len = str.size();
- if (d->ref.isShared() || d->size + len > capacity())
+ if (d->needsDetach() || d->size + len > capacity())
reallocData(uint(d->size + len) + 1u, true);
ushort *i = d->data() + d->size;
qt_from_latin1(i, s, uint(len));
@@ -2743,7 +2743,7 @@ QString &QString::append(QLatin1String str)
*/
QString &QString::append(QChar ch)
{
- if (d->ref.isShared() || d->size + 1 > capacity())
+ if (d->needsDetach() || d->size + 1 > capacity())
reallocData(uint(d->size) + 2u, true);
d->data()[d->size++] = ch.unicode();
d->data()[d->size] = '\0';
@@ -6457,7 +6457,7 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
const ushort *QString::utf16() const
{
- if (IS_RAW_DATA(d)) {
+ if (!d->isMutable()) {
// ensure '\0'-termination for ::fromRawData strings
const_cast<QString*>(this)->reallocData(uint(d->size) + 1u);
}
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index 03d83eeab9..fd674284fe 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -542,7 +542,7 @@ public:
inline QString &prepend(QLatin1String s) { return insert(0, s); }
inline QString &operator+=(QChar c) {
- if (d->ref.isShared() || d->size + 1 > capacity())
+ if (d->needsDetach() || d->size + 1 > capacity())
reallocData(uint(d->size) + 2u, true);
d->data()[d->size++] = c.unicode();
d->data()[d->size] = '\0';
@@ -1041,7 +1041,7 @@ inline QChar *QString::data()
inline const QChar *QString::constData() const
{ return reinterpret_cast<const QChar*>(d->data()); }
inline void QString::detach()
-{ if (d->ref.isShared() || !d->isMutable()) reallocData(uint(d->size) + 1u); }
+{ if (d->needsDetach()) reallocData(uint(d->size) + 1u); }
inline bool QString::isDetached() const
{ return !d->ref.isShared(); }
inline void QString::clear()
@@ -1263,7 +1263,7 @@ inline QString::~QString() { if (!d->ref.deref()) Data::deallocate(d); }
inline void QString::reserve(int asize)
{
- if (d->ref.isShared() || asize >= capacity())
+ if (d->needsDetach() || asize >= capacity())
reallocData(qMax(asize, size()) + 1u);
// we're not shared anymore, for sure
@@ -1272,7 +1272,9 @@ inline void QString::reserve(int asize)
inline void QString::squeeze()
{
- if (d->ref.isShared() || d->size < capacity())
+ if ((d->flags & Data::CapacityReserved) == 0)
+ return;
+ if (d->needsDetach() || d->size < capacity())
reallocData(uint(d->size) + 1u);
// we're not shared anymore, for sure
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index bc48619349..3123d7467f 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -222,7 +222,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
return nullptr;
size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
- options |= ArrayOption(AllocatedDataType);
+ options |= AllocatedDataType | Mutable;
QArrayData *header = allocateData(allocSize, options);
if (header) {
quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
@@ -252,6 +252,7 @@ QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize,
options |= ArrayOption(AllocatedDataType);
size_t headerSize = sizeof(QArrayData);
size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
+ options |= AllocatedDataType | Mutable;
QArrayData *header = reallocateData(data, allocSize, options);
if (header)
header->alloc = capacity;
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index babccc6017..8c21fd55c8 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -56,6 +56,7 @@ struct Q_CORE_EXPORT QArrayData
CapacityReserved = 0x0010, //!< the capacity was reserved by the user, try to keep it
GrowsForward = 0x0020, //!< allocate with eyes towards growing through append()
GrowsBackwards = 0x0040, //!< allocate with eyes towards growing through prepend()
+ Mutable = 0x0080, //!< the data can be changed; doesn't say anything about the header
/// this option is used by the Q_ARRAY_LITERAL and similar macros
StaticDataFlags = RawDataType,
@@ -102,7 +103,16 @@ struct Q_CORE_EXPORT QArrayData
// follow COW principles.
bool isMutable() const
{
- return flags & AllocatedDataType;
+ return flags & Mutable;
+ }
+
+ // Returns true if a detach is necessary before modifying the data
+ // This method is intentionally not const: if you want to know whether
+ // detaching is necessary, you should be in a non-const function already
+ bool needsDetach()
+ {
+ // ### optimize me -- this currently requires 3 conditionals!
+ return !isMutable() || ref.isShared();
}
size_t detachCapacity(size_t newSize) const
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index ffeaff5862..b7236d485a 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -126,11 +126,6 @@ public:
return d;
}
- bool needsDetach() const
- {
- return (!d->isMutable() || d->ref.isShared());
- }
-
void swap(QArrayDataPointer &other) noexcept
{
qSwap(d, other.d);
@@ -144,7 +139,7 @@ public:
bool detach()
{
- if (needsDetach()) {
+ if (d->needsDetach()) {
Data *copy = clone(d->detachFlags());
QArrayDataPointer old(d);
d = copy;
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 9ef2ace471..a596beedcf 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -390,10 +390,11 @@ inline QVector<T>::QVector(const QVector<T> &v)
template <typename T>
void QVector<T>::detach()
{
+ // ### check whether this is still required
if (d->ref.isStatic())
return;
- if (!isDetached())
+ if (d->needsDetach())
realloc(d->allocatedCapacity(), d->detachFlags());
Q_ASSERT(isDetached());
}
diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
index cc65662e26..f5748ea060 100644
--- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
+++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
@@ -2163,7 +2163,7 @@ void tst_QByteArray::movablity()
const int newSize = size + 2;
const bool newIsEmpty = false;
const bool newIsNull = false;
- const int newCapacity = 16;
+ const int newCapacity = memSpace.capacity();
// move back memSpace -> array
array.~QByteArray();
diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h
index f3e3a1bb50..c9a77a6f42 100644
--- a/tests/auto/corelib/tools/qarraydata/simplevector.h
+++ b/tests/auto/corelib/tools/qarraydata/simplevector.h
@@ -159,7 +159,7 @@ public:
if (size() == newSize)
return;
- if (d.needsDetach() || newSize > capacity()) {
+ if (d->needsDetach() || newSize > capacity()) {
SimpleVector detached(Data::allocate(
d->detachCapacity(newSize), d->detachFlags()));
if (newSize) {
@@ -195,7 +195,7 @@ public:
return;
T *const begin = d->begin();
- if (d.needsDetach()
+ if (d->needsDetach()
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
d->detachCapacity(size() + (last - first)),
@@ -216,7 +216,7 @@ public:
if (first == last)
return;
- if (d.needsDetach()
+ if (d->needsDetach()
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
d->detachCapacity(size() + (last - first)),
@@ -256,7 +256,7 @@ public:
const iterator begin = d->begin();
const iterator where = begin + position;
const iterator end = begin + d->size;
- if (d.needsDetach()
+ if (d->needsDetach()
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
d->detachCapacity(size() + (last - first)),
@@ -294,7 +294,7 @@ public:
const T *const begin = d->begin();
const T *const end = begin + d->size;
- if (d.needsDetach()) {
+ if (d->needsDetach()) {
SimpleVector detached(Data::allocate(
d->detachCapacity(size() - (last - first)),
d->detachFlags()));