summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qarraydata.cpp3
-rw-r--r--src/corelib/tools/qarraydataops.h11
-rw-r--r--src/corelib/tools/qarraydatapointer.h19
-rw-r--r--src/corelib/tools/qlist.h20
4 files changed, 49 insertions, 4 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 3217e87cc8e..2bf3e9bacc2 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -236,6 +236,7 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
qsizetype headerSize = sizeof(QArrayData);
qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option);
qptrdiff offset = dataPointer ? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data) : headerSize;
+ Q_ASSERT(offset > 0);
allocSize = reserveExtraBytes(allocSize);
if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot reallocate reliably
@@ -245,6 +246,8 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
if (header) {
header->alloc = uint(capacity);
dataPointer = reinterpret_cast<char *>(header) + offset;
+ } else {
+ dataPointer = nullptr;
}
return qMakePair(static_cast<QArrayData *>(header), dataPointer);
}
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 730476c2136..a864ac4c2b5 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -854,6 +854,10 @@ template <class T>
struct QMovableArrayOps
: QGenericArrayOps<T>
{
+protected:
+ typedef QTypedArrayData<T> Data;
+
+public:
// using QGenericArrayOps<T>::appendInitialize;
// using QGenericArrayOps<T>::copyAppend;
// using QGenericArrayOps<T>::moveAppend;
@@ -993,6 +997,13 @@ struct QMovableArrayOps
(b++)->~T();
} while (b != e);
}
+
+ void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
+ {
+ auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, option);
+ this->d = pair.first;
+ this->ptr = pair.second;
+ }
};
template <class T, class = void>
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index d483a5a5e5b..20015cbaddc 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -244,6 +244,25 @@ public:
return lhs.data() != rhs.data() || lhs.size != rhs.size;
}
+ static void reallocateGrow(QArrayDataPointer &from, qsizetype n)
+ {
+ Q_ASSERT(n > 0);
+
+ if constexpr (!QTypeInfo<T>::isRelocatable || alignof(T) > alignof(std::max_align_t)) {
+ QArrayDataPointer dd(allocateGrow(from, n, QArrayData::AllocateAtEnd));
+ dd->copyAppend(from.data(), from.data() + from.size);
+ from.swap(dd);
+ } else {
+ if (from.needsDetach()) {
+ QArrayDataPointer dd(allocateGrow(from, n, QArrayData::AllocateAtEnd));
+ dd->copyAppend(from.data(), from.data() + from.size);
+ from.swap(dd);
+ } else {
+ from->reallocate(from.constAllocatedCapacity() - from.freeSpaceAtEnd() + n, QArrayData::Grow); // fast path
+ }
+ }
+ }
+
private:
[[nodiscard]] QPair<Data *, T *> clone() const
{
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index f3e78b4cdb0..3ea932c0fe2 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -770,10 +770,22 @@ template<typename... Args>
inline typename QList<T>::reference QList<T>::emplaceBack(Args &&... args)
{
if (d->needsDetach() || !d.freeSpaceAtEnd()) {
- DataPointer detached(DataPointer::allocateGrow(d, 1, QArrayData::AllocateAtEnd));
- detached->copyAppend(constBegin(), constEnd());
- detached->emplace(detached.end(), std::forward<Args>(args)...);
- d.swap(detached);
+ // condition below should follow the condition in QArrayDataPointer::reallocateGrow()
+ if constexpr (!QTypeInfo<T>::isRelocatable || alignof(T) > alignof(std::max_align_t)) {
+ // avoid taking a temporary copy of Args
+ DataPointer detached(DataPointer::allocateGrow(d, 1, QArrayData::AllocateAtEnd));
+ detached->copyAppend(constBegin(), constEnd());
+ detached->emplace(detached.end(), std::forward<Args>(args)...);
+ d.swap(detached);
+ } else {
+ // Create an element here to handle cases when a user moves the element
+ // from a container to the same container. This is required as we call
+ // reallocate, which could delete the data args points to.
+ // This should be optimised to only take the copy when really required.
+ T tmp(std::forward<Args>(args)...);
+ DataPointer::reallocateGrow(d, 1);
+ d->emplace(d.end(), std::move(tmp));
+ }
} else {
d->emplace(d.end(), std::forward<Args>(args)...);
}