QVarLengthArray: cope with vector<unique_ptr>'s copyability
Despite being move-only, std::vector<unique_ptr> advertizes
is_copyable:
https://quuxplusone.github.io/blog/2020/02/05/vector-is-copyable-except-when-its-not/
Our combined reallocation and resizing function, reallocate_impl(),
runs afoul of this when it uses std::is_copyable in a constexpr-if to
implement resize(n, v) without running into problems with move-only
types: the trait is true, but actual instantation runs into a
static_assert in the STL implementation.
To fix, move the problematic resize functionality out of
reallocate_impl() and into the resp. resize_impl overloads. The shrink
functionality remains in reallocate_impl(), because there are many
more users, and it only requires destructible<T>, which isn't
constraining at all.
Amends a00a1d8806
.
Fixes: QTBUG-109745
Pick-to: 6.5 6.4
Change-Id: Ibc5b9cf5375108eb3d8f6c8a16d4fd02dadd73b1
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
03ed57afa0
commit
800ebd84f5
@ -208,14 +208,27 @@ protected:
|
||||
}
|
||||
|
||||
void append_impl(qsizetype prealloc, void *array, const T *buf, qsizetype n);
|
||||
void reallocate_impl(qsizetype prealloc, void *array, qsizetype size, qsizetype alloc, const T *v = nullptr);
|
||||
void reallocate_impl(qsizetype prealloc, void *array, qsizetype size, qsizetype alloc);
|
||||
void resize_impl(qsizetype prealloc, void *array, qsizetype sz, const T &v)
|
||||
{
|
||||
reallocate_impl(prealloc, array, sz, qMax(sz, capacity()), &v);
|
||||
reallocate_impl(prealloc, array, sz, qMax(sz, capacity()));
|
||||
while (size() < sz) {
|
||||
new (data() + size()) T(v);
|
||||
++s;
|
||||
}
|
||||
}
|
||||
void resize_impl(qsizetype prealloc, void *array, qsizetype sz)
|
||||
{
|
||||
reallocate_impl(prealloc, array, sz, qMax(sz, capacity()));
|
||||
if constexpr (QTypeInfo<T>::isComplex) {
|
||||
// call default constructor for new objects (which can throw)
|
||||
while (size() < sz) {
|
||||
new (data() + size()) T;
|
||||
++s;
|
||||
}
|
||||
} else {
|
||||
s = sz;
|
||||
}
|
||||
}
|
||||
|
||||
bool isValidIterator(const const_iterator &i) const
|
||||
@ -714,7 +727,7 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::append_impl(qsizetype prealloc, void *arr
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void *array, qsizetype asize, qsizetype aalloc, const T *v)
|
||||
Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void *array, qsizetype asize, qsizetype aalloc)
|
||||
{
|
||||
Q_ASSERT(aalloc >= asize);
|
||||
Q_ASSERT(data());
|
||||
@ -755,26 +768,6 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void
|
||||
|
||||
if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != data())
|
||||
free(oldPtr);
|
||||
|
||||
if (v) {
|
||||
if constexpr (std::is_copy_constructible_v<T>) {
|
||||
while (size() < asize) {
|
||||
new (data() + size()) T(*v);
|
||||
++s;
|
||||
}
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
} else if constexpr (QTypeInfo<T>::isComplex) {
|
||||
// call default constructor for new objects (which can throw)
|
||||
while (size() < asize) {
|
||||
new (data() + size()) T;
|
||||
++s;
|
||||
}
|
||||
} else {
|
||||
s = asize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -92,6 +92,8 @@ private slots:
|
||||
void remove();
|
||||
void erase();
|
||||
|
||||
// special cases:
|
||||
void copesWithCopyabilityOfMoveOnlyVector(); // QTBUG-109745
|
||||
private:
|
||||
template <typename T>
|
||||
void defaultConstructor();
|
||||
@ -1640,5 +1642,26 @@ void tst_QVarLengthArray::erase()
|
||||
QCOMPARE(arr, QVarLengthArray<QString>({ "val0" }));
|
||||
}
|
||||
|
||||
void tst_QVarLengthArray::copesWithCopyabilityOfMoveOnlyVector()
|
||||
{
|
||||
// std::vector<move-only-type> is_copyable
|
||||
// (https://quuxplusone.github.io/blog/2020/02/05/vector-is-copyable-except-when-its-not/)
|
||||
|
||||
QVarLengthArray<std::vector<std::unique_ptr<int>>, 2> vla;
|
||||
vla.emplace_back(42);
|
||||
vla.emplace_back(43);
|
||||
vla.emplace_back(44); // goes to the heap
|
||||
QCOMPARE_EQ(vla.size(), 3);
|
||||
QCOMPARE_EQ(vla.front().size(), 42U);
|
||||
QCOMPARE_EQ(vla.front().front(), nullptr);
|
||||
QCOMPARE_EQ(vla.back().size(), 44U);
|
||||
|
||||
auto moved = std::move(vla);
|
||||
QCOMPARE_EQ(moved.size(), 3);
|
||||
QCOMPARE_EQ(moved.front().size(), 42U);
|
||||
QCOMPARE_EQ(moved.front().front(), nullptr);
|
||||
QCOMPARE_EQ(moved.back().size(), 44U);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QVarLengthArray)
|
||||
#include "tst_qvarlengtharray.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user