summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qarraydatapointer.h
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-11-04 22:59:09 +0100
committerLars Knoll <lars.knoll@qt.io>2020-11-17 11:45:46 +0100
commit6be39809b038768a665b0e29a3a3668fdc424d9a (patch)
tree51b29213d4beed589e89a6bcae34874d5f63c593 /src/corelib/tools/qarraydatapointer.h
parent20883c9bcc7882b79db438ed0959530f82c8ee0a (diff)
Simplify reallocation handling in QList
Have one generic method for detaching and reallocations. Use that method throughout QList to avoid duplicated instantiations of code paths that are rarely used. Change-Id: I5b9add3be5f17b387e2d34028b72c8f52db68444 Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/tools/qarraydatapointer.h')
-rw-r--r--src/corelib/tools/qarraydatapointer.h88
1 files changed, 46 insertions, 42 deletions
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index 26e8f934ee..1aa9a670e7 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -162,17 +162,55 @@ public:
swap(tmp);
}
- QArrayDataPointer detach()
+ void detach(QArrayDataPointer *old = nullptr)
{
- if (needsDetach()) {
- QPair<Data *, T *> copy = clone();
- QArrayDataPointer old(d, ptr, size);
- d = copy.first;
- ptr = copy.second;
- return old;
+ if (needsDetach())
+ reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
+ }
+
+ // pass in a pointer to a default constructed QADP, to keep it alive beyond the detach() call
+ void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n, QArrayDataPointer *old = nullptr)
+ {
+ if (!needsDetach()) {
+ if (!n ||
+ (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n) ||
+ (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
+ return;
+ }
+ reallocateAndGrow(where, n, old);
+ }
+
+ Q_NEVER_INLINE void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n, QArrayDataPointer *old = nullptr)
+ {
+ if constexpr (QTypeInfo<T>::isRelocatable && alignof(T) <= alignof(std::max_align_t)) {
+ if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
+ (*this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow); // fast path
+ return;
+ }
+ }
+
+ QArrayDataPointer dp(allocateGrow(*this, n, where));
+ if (where == QArrayData::GrowsAtBeginning) {
+ dp.ptr += n;
+ Q_ASSERT(dp.freeSpaceAtBegin() >= n);
+ } else {
+ Q_ASSERT(dp.freeSpaceAtEnd() >= n);
+ }
+ if (size) {
+ qsizetype toCopy = size;
+ if (n < 0)
+ toCopy += n;
+ if (needsDetach() || old)
+ dp->copyAppend(begin(), begin() + toCopy);
+ else
+ dp->moveAppend(begin(), begin() + toCopy);
+ dp.d->flags = flags();
+ Q_ASSERT(dp.size == toCopy);
}
- return QArrayDataPointer();
+ swap(dp);
+ if (old)
+ old->swap(dp);
}
// forwards from QArrayData
@@ -244,40 +282,6 @@ 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::GrowsAtEnd));
- dd->copyAppend(from.data(), from.data() + from.size);
- from.swap(dd);
- } else {
- if (from.needsDetach()) {
- QArrayDataPointer dd(allocateGrow(from, n, QArrayData::GrowsAtEnd));
- 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
- {
- QPair<Data *, T *> pair = Data::allocate(detachCapacity(size), QArrayData::KeepSize);
- QArrayDataPointer copy(pair.first, pair.second, 0);
- if (size)
- copy->copyAppend(begin(), end());
-
- if (pair.first)
- pair.first->flags = flags();
- copy.d = nullptr;
- copy.ptr = nullptr;
- return pair;
- }
-
protected:
Data *d;
T *ptr;