QList/QString/QByteArray: no prepend optimized allocation when empty

Scoped prepend optimized allocation to only work when prepending into
a non-empty container. Otherwise, even appends would be considered
prepends since d.size == 0 when container is empty

This is, of course, not good for prepend cases but we prefer appends
over prepends. My proposal is to figure out what's the best strategy
based on use cases and performance measurements. For now, let's just
make sure appends are not additionally pessimized

Anyhow, this is an implementation detail and should not be considered
behavior change (at least not the one that is user noticeable)

Task-number: QTBUG-84320
Change-Id: Ibed616a2afa9bc24f78252f15a617bf92e2c6ea3
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
bb10
Andrei Golubev 2020-09-04 11:27:44 +02:00
parent c9e419e026
commit 08c70ca0cc
3 changed files with 6 additions and 7 deletions

View File

@ -1942,7 +1942,7 @@ QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
// ### optimize me
if (d->needsDetach() || newSize > capacity() || shouldGrow) {
auto flags = d->detachFlags() | Data::GrowsForward;
if (i <= oldSize / 4) // using QList's policy
if (oldSize != 0 && i <= oldSize / 4) // using QList's policy
flags |= Data::GrowsBackwards;
reallocGrowData(newSize + 1, flags);
}

View File

@ -2690,7 +2690,7 @@ QString& QString::insert(qsizetype i, const QChar *unicode, qsizetype size)
const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + qMin(i, oldSize), size);
auto flags = d->detachFlags() | Data::GrowsForward;
if (i <= oldSize / 4)
if (oldSize != 0 && i <= oldSize / 4)
flags |= Data::GrowsBackwards;
// ### optimize me
@ -2724,7 +2724,7 @@ QString& QString::insert(qsizetype i, QChar ch)
const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + qMin(i, oldSize), 1);
auto flags = d->detachFlags() | Data::GrowsForward;
if (i <= oldSize / 4)
if (oldSize != 0 && i <= oldSize / 4)
flags |= Data::GrowsBackwards;
// ### optimize me

View File

@ -528,8 +528,7 @@ inline void QList<T>::remove(qsizetype i, qsizetype n)
((d->flags() & Data::CapacityReserved) == 0
&& newSize < d->allocatedCapacity()/2)) {
// allocate memory
DataPointer detached(Data::allocate(d->detachCapacity(newSize),
d->detachFlags() & ~(Data::GrowsBackwards | Data::GrowsForward)));
DataPointer detached(Data::allocate(d->detachCapacity(newSize), d->detachFlags()));
const_iterator where = constBegin() + i;
if (newSize) {
detached->copyAppend(constBegin(), where);
@ -616,7 +615,7 @@ QList<T>::insert(qsizetype i, qsizetype n, parameter_type t)
const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + i, n);
if (d->needsDetach() || newSize > d->allocatedCapacity() || shouldGrow) {
typename Data::ArrayOptions flags = d->detachFlags() | Data::GrowsForward;
if (i <= d.size / 4)
if (d.size != 0 && i <= d.size / 4)
flags |= Data::GrowsBackwards;
DataPointer detached(DataPointer::allocateGrow(d, newSize, flags));
@ -648,7 +647,7 @@ QList<T>::emplace(qsizetype i, Args&&... args)
const size_t newSize = size() + 1;
if (d->needsDetach() || newSize > d->allocatedCapacity() || shouldGrow) {
typename Data::ArrayOptions flags = d->detachFlags() | Data::GrowsForward;
if (i <= d.size / 4)
if (d.size != 0 && i <= d.size / 4)
flags |= Data::GrowsBackwards;
DataPointer detached(DataPointer::allocateGrow(d, newSize, flags));