Implement QList::emplaceBack as a proper function

My endeavours figuring out why QList::append(elem) gives worst
performance compared to 5.15 ended up into this commit. After some
straightforward fixes, what was left is "everything is uniformly worse"
and takes more CPU cycles

Introduce emplaceBack implementation as append is quite a special case
that could be greatly simplified. This is a "straightforward" part of
the optimizations

While at it, change append(t) to use emplaceBack(t)

For workloads like:
QList<int> list;
forever {
  list.append(0);
}
this gives huge improvement (roughly 30% for 10k+ elements),
movable and complex types also get a tiny speedup

Task-number: QTBUG-87330
Change-Id: I9261084e545c24e5473234220d2a3f2cd26c2b7f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Andrei Golubev 2020-10-27 20:00:18 +01:00 committed by Lars Knoll
parent 4deb0d1737
commit 8f7016252a
2 changed files with 19 additions and 5 deletions

View File

@ -310,8 +310,7 @@ public:
return data()[i];
}
const_reference operator[](qsizetype i) const noexcept { return at(i); }
void append(parameter_type t)
{ append(const_iterator(std::addressof(t)), const_iterator(std::addressof(t)) + 1); }
void append(parameter_type t) { emplaceBack(t); }
void append(const_iterator i1, const_iterator i2);
void append(rvalue_ref t) { emplaceBack(std::move(t)); }
void append(const QList<T> &l)
@ -324,8 +323,8 @@ public:
void prepend(rvalue_ref t) { emplaceFront(std::move(t)); }
void prepend(parameter_type t) { emplaceFront(t); }
template <typename ...Args>
reference emplaceBack(Args&&... args) { return *emplace(count(), std::forward<Args>(args)...); }
template<typename... Args>
inline reference emplaceBack(Args &&... args);
template <typename ...Args>
inline reference emplaceFront(Args&&... args);
@ -766,6 +765,21 @@ QList<T>::emplace(qsizetype i, Args&&... args)
return d.begin() + i;
}
template<typename T>
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);
} else {
d->emplace(d.end(), std::forward<Args>(args)...);
}
return *(d.end() - 1);
}
template <typename T>
typename QList<T>::iterator QList<T>::erase(const_iterator abegin, const_iterator aend)
{

View File

@ -875,7 +875,7 @@ void tst_QList::appendList() const
v6 << (QList<ConstructionCounted>() << 3 << 4);
QCOMPARE(v6, expectedFour);
QCOMPARE(v6.at(0).copies, 2);
QCOMPARE(v6.at(0).moves, 2);
QCOMPARE(v6.at(0).moves, 1);
// +=
QList<ConstructionCounted> v7;