Introduce QADP::reallocateGrow()
Added realloc() code path to QMovableArrayOps Implemented fast realloc() based growing for QADP and used it in QList::emplaceBack. This gives quite a bit of speedup and shows better results than 5.15 at 100k+ iterations of "list.append(elem)", meanwhile also closing a gap between movable types Task-number: QTBUG-87330 Change-Id: I42fc182ecd93c85600dac622385152fc57735da8 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
8f7016252a
commit
2e8656779a
@ -236,6 +236,7 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
|
|||||||
qsizetype headerSize = sizeof(QArrayData);
|
qsizetype headerSize = sizeof(QArrayData);
|
||||||
qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option);
|
qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option);
|
||||||
qptrdiff offset = dataPointer ? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data) : headerSize;
|
qptrdiff offset = dataPointer ? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data) : headerSize;
|
||||||
|
Q_ASSERT(offset > 0);
|
||||||
|
|
||||||
allocSize = reserveExtraBytes(allocSize);
|
allocSize = reserveExtraBytes(allocSize);
|
||||||
if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot reallocate reliably
|
if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot reallocate reliably
|
||||||
@ -245,6 +246,8 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
|
|||||||
if (header) {
|
if (header) {
|
||||||
header->alloc = uint(capacity);
|
header->alloc = uint(capacity);
|
||||||
dataPointer = reinterpret_cast<char *>(header) + offset;
|
dataPointer = reinterpret_cast<char *>(header) + offset;
|
||||||
|
} else {
|
||||||
|
dataPointer = nullptr;
|
||||||
}
|
}
|
||||||
return qMakePair(static_cast<QArrayData *>(header), dataPointer);
|
return qMakePair(static_cast<QArrayData *>(header), dataPointer);
|
||||||
}
|
}
|
||||||
|
@ -854,6 +854,10 @@ template <class T>
|
|||||||
struct QMovableArrayOps
|
struct QMovableArrayOps
|
||||||
: QGenericArrayOps<T>
|
: QGenericArrayOps<T>
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
typedef QTypedArrayData<T> Data;
|
||||||
|
|
||||||
|
public:
|
||||||
// using QGenericArrayOps<T>::appendInitialize;
|
// using QGenericArrayOps<T>::appendInitialize;
|
||||||
// using QGenericArrayOps<T>::copyAppend;
|
// using QGenericArrayOps<T>::copyAppend;
|
||||||
// using QGenericArrayOps<T>::moveAppend;
|
// using QGenericArrayOps<T>::moveAppend;
|
||||||
@ -993,6 +997,13 @@ struct QMovableArrayOps
|
|||||||
(b++)->~T();
|
(b++)->~T();
|
||||||
} while (b != e);
|
} 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>
|
template <class T, class = void>
|
||||||
|
@ -244,6 +244,25 @@ public:
|
|||||||
return lhs.data() != rhs.data() || lhs.size != rhs.size;
|
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:
|
private:
|
||||||
[[nodiscard]] QPair<Data *, T *> clone() const
|
[[nodiscard]] QPair<Data *, T *> clone() const
|
||||||
{
|
{
|
||||||
|
@ -770,10 +770,22 @@ template<typename... Args>
|
|||||||
inline typename QList<T>::reference QList<T>::emplaceBack(Args &&... args)
|
inline typename QList<T>::reference QList<T>::emplaceBack(Args &&... args)
|
||||||
{
|
{
|
||||||
if (d->needsDetach() || !d.freeSpaceAtEnd()) {
|
if (d->needsDetach() || !d.freeSpaceAtEnd()) {
|
||||||
DataPointer detached(DataPointer::allocateGrow(d, 1, QArrayData::AllocateAtEnd));
|
// condition below should follow the condition in QArrayDataPointer::reallocateGrow()
|
||||||
detached->copyAppend(constBegin(), constEnd());
|
if constexpr (!QTypeInfo<T>::isRelocatable || alignof(T) > alignof(std::max_align_t)) {
|
||||||
detached->emplace(detached.end(), std::forward<Args>(args)...);
|
// avoid taking a temporary copy of Args
|
||||||
d.swap(detached);
|
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 {
|
} else {
|
||||||
d->emplace(d.end(), std::forward<Args>(args)...);
|
d->emplace(d.end(), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user