QByteArray/QVarLengthArray: add missing resize(n, v) overloads

QList and QString had them, so add them to QByteArray and
QVarLengthArray, too.

In the QVLA case, we need to jump though a hoop or two to avoid having
to duplicate all the reallocation logic. Nothing a few template tricks
cannot solve.

[ChangeLog][QtCore][QByteArray] Added resize(n, ch) overload.

[ChangeLog][QtCore][QVarLengthArray] Added resize(n, v) overload.

Fixes: QTBUG-102270
Change-Id: I0d281ae5b574f440f682e4a62427b434dcf5b687
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Marc Mutz 2022-04-04 15:20:51 +02:00
parent 2fb7c94f63
commit a00a1d8806
6 changed files with 102 additions and 5 deletions

View File

@ -1759,6 +1759,31 @@ void QByteArray::resize(qsizetype size)
d.data()[size] = 0;
}
/*!
\since 6.4
Sets the size of the byte array to \a newSize bytes.
If \a newSize is greater than the current size, the byte array is
extended to make it \a newSize bytes with the extra bytes added to
the end. The new bytes are initialized to \a c.
If \a newSize is less than the current size, bytes beyond position
\a newSize are excluded from the byte array.
\note While resize() will grow the capacity if needed, it never shrinks
capacity. To shed excess capacity, use squeeze().
\sa size(), truncate(), squeeze()
*/
void QByteArray::resize(qsizetype newSize, char c)
{
const auto old = d.size;
resize(newSize);
if (old < d.size)
memset(d.data() + old, c, d.size - old);
}
/*!
Sets every byte in the byte array to \a ch. If \a size is different from -1
(the default), the byte array is resized to size \a size beforehand.

View File

@ -128,6 +128,7 @@ public:
bool isEmpty() const noexcept { return size() == 0; }
void resize(qsizetype size);
void resize(qsizetype size, char c);
QByteArray &fill(char c, qsizetype size = -1);

View File

@ -237,9 +237,9 @@ protected:
}
void append_impl(qsizetype prealloc, void *array, const T *buf, qsizetype n);
void reallocate_impl(qsizetype prealloc, void *array, qsizetype size, qsizetype alloc);
void resize_impl(qsizetype prealloc, void *array, qsizetype sz)
{ reallocate_impl(prealloc, array, sz, qMax(sz, capacity())); }
void reallocate_impl(qsizetype prealloc, void *array, qsizetype size, qsizetype alloc, const T *v = nullptr);
void resize_impl(qsizetype prealloc, void *array, qsizetype sz, const T *v = nullptr)
{ reallocate_impl(prealloc, array, sz, qMax(sz, capacity()), v); }
bool isValidIterator(const const_iterator &i) const
{
@ -393,6 +393,14 @@ public:
}
bool isEmpty() const { return empty(); }
void resize(qsizetype sz) { Base::resize_impl(Prealloc, this->array, sz); }
#ifdef Q_QDOC
void
#else
template <typename U = T>
std::enable_if_t<std::is_copy_constructible_v<U>>
#endif
resize(qsizetype sz, const T &v)
{ Base::resize_impl(Prealloc, this->array, sz, &v); }
inline void clear() { resize(0); }
void squeeze() { reallocate(size(), size()); }
@ -720,7 +728,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)
Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void *array, qsizetype asize, qsizetype aalloc, const T *v)
{
Q_ASSERT(aalloc >= asize);
Q_ASSERT(data());
@ -765,7 +773,16 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void
if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != data())
free(oldPtr);
if constexpr (QTypeInfo<T>::isComplex) {
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;

View File

@ -245,6 +245,19 @@
\sa size(), squeeze()
*/
/*!
\fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::resize(qsizetype size, const T &v)
\since 6.4
Sets the size of the array to \a size. If \a size is greater than
the current size, copies of \a v are added to the end. If \a size is
less than the current size, elements are removed from the end.
\note This function is only available when \c T is copy-constructible.
\sa size(), squeeze()
*/
/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::capacity() const
Returns the maximum number of elements that can be stored in the

View File

@ -125,6 +125,7 @@ private slots:
void reserve();
void reserveExtended_data();
void reserveExtended();
void resize();
void movablity_data();
void movablity();
void literals();
@ -2091,6 +2092,23 @@ void tst_QByteArray::reserveExtended()
QCOMPARE(array.capacity(), array.size());
}
void tst_QByteArray::resize()
{
QByteArray ba;
ba.resize(15);
QCOMPARE(ba.size(), qsizetype(15));
ba.resize(10);
QCOMPARE(ba.size(), 10);
ba.resize(0);
QCOMPARE(ba.size(), 0);
ba.resize(5, 'a');
QCOMPARE(ba.size(), 5);
QCOMPARE(ba, "aaaaa");
ba.resize(10, 'b');
QCOMPARE(ba.size(), 10);
QCOMPARE(ba, "aaaaabbbbb");
}
void tst_QByteArray::movablity_data()
{
QTest::addColumn<QByteArray>("array");

View File

@ -345,6 +345,17 @@ private Q_SLOTS:
void ranged_ctor_QMultiHash_Movable() { ranged_ctor_associative_impl<QMultiHash<Movable, int>>(); }
void ranged_ctor_QMultiHash_Complex() { ranged_ctor_associative_impl<QMultiHash<Complex, int>>(); }
private:
template <typename Container>
void resize_impl() const;
private Q_SLOTS:
void resize_std_vector() { resize_impl<std::vector<int>>(); }
void resize_QList() { resize_impl<QList<qintptr>>(); }
void resize_QVarLengthArray() { resize_impl<QVarLengthArray<int>>(); }
void resize_QString() { resize_impl<QString>(); }
void resize_QByteArray() { resize_impl<QByteArray>(); }
private:
template <typename Container>
void front_back_impl() const;
@ -729,6 +740,18 @@ template <> QByteArray make(int size) { return QByteArray("\1\2\3\4\5\6\7", s
template <typename T> T clean(T &&t) { return std::forward<T>(t); }
inline char clean(QLatin1Char ch) { return ch.toLatin1(); }
template <typename Container>
void tst_ContainerApiSymmetry::resize_impl() const
{
using V = typename Container::value_type;
using S = typename Container::size_type;
auto c = make<Container>(3);
QCOMPARE(c.size(), S(3));
c.resize(4, V(5));
QCOMPARE(c.size(), S(4));
QCOMPARE(c.back(), V(5));
}
template <typename Container>
void tst_ContainerApiSymmetry::front_back_impl() const
{