From a00a1d8806cfbf17e04b88d1b4ff4a9cf5b6294a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 4 Apr 2022 15:20:51 +0200 Subject: [PATCH] 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 Reviewed-by: Thiago Macieira --- src/corelib/text/qbytearray.cpp | 25 +++++++++++++++++ src/corelib/text/qbytearray.h | 1 + src/corelib/tools/qvarlengtharray.h | 27 +++++++++++++++---- src/corelib/tools/qvarlengtharray.qdoc | 13 +++++++++ .../text/qbytearray/tst_qbytearray.cpp | 18 +++++++++++++ .../tst_containerapisymmetry.cpp | 23 ++++++++++++++++ 6 files changed, 102 insertions(+), 5 deletions(-) diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index d9518c9e8f..7675d7f4a2 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -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. diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 2f0b099db9..75fb75fd35 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -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); diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index fd3d4ffbf2..2c9d0dd975 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -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 + std::enable_if_t> +#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::append_impl(qsizetype prealloc, void *arr } template -Q_OUTOFLINE_TEMPLATE void QVLABase::reallocate_impl(qsizetype prealloc, void *array, qsizetype asize, qsizetype aalloc) +Q_OUTOFLINE_TEMPLATE void QVLABase::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::reallocate_impl(qsizetype prealloc, void if (oldPtr != reinterpret_cast(array) && oldPtr != data()) free(oldPtr); - if constexpr (QTypeInfo::isComplex) { + if (v) { + if constexpr (std::is_copy_constructible_v) { + while (size() < asize) { + new (data() + size()) T(*v); + ++s; + } + } else { + Q_UNREACHABLE(); + } + } else if constexpr (QTypeInfo::isComplex) { // call default constructor for new objects (which can throw) while (size() < asize) { new (data() + size()) T; diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc index de57daf4e4..12789b49b9 100644 --- a/src/corelib/tools/qvarlengtharray.qdoc +++ b/src/corelib/tools/qvarlengtharray.qdoc @@ -245,6 +245,19 @@ \sa size(), squeeze() */ +/*! + \fn template void QVarLengthArray::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 qsizetype QVarLengthArray::capacity() const Returns the maximum number of elements that can be stored in the diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp index 78b6f4d506..1de223d1e7 100644 --- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -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("array"); diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp index 26fe1167d5..dabf9dd7f4 100644 --- a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp +++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp @@ -345,6 +345,17 @@ private Q_SLOTS: void ranged_ctor_QMultiHash_Movable() { ranged_ctor_associative_impl>(); } void ranged_ctor_QMultiHash_Complex() { ranged_ctor_associative_impl>(); } +private: + template + void resize_impl() const; + +private Q_SLOTS: + void resize_std_vector() { resize_impl>(); } + void resize_QList() { resize_impl>(); } + void resize_QVarLengthArray() { resize_impl>(); } + void resize_QString() { resize_impl(); } + void resize_QByteArray() { resize_impl(); } + private: template 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 T clean(T &&t) { return std::forward(t); } inline char clean(QLatin1Char ch) { return ch.toLatin1(); } +template +void tst_ContainerApiSymmetry::resize_impl() const +{ + using V = typename Container::value_type; + using S = typename Container::size_type; + auto c = make(3); + QCOMPARE(c.size(), S(3)); + c.resize(4, V(5)); + QCOMPARE(c.size(), S(4)); + QCOMPARE(c.back(), V(5)); +} + template void tst_ContainerApiSymmetry::front_back_impl() const {