diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index dfe15f439c..de13f2c829 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -57,11 +57,34 @@ QT_BEGIN_NAMESPACE +template +class QVLAStorage +{ +protected: + ~QVLAStorage() = default; + + std::aligned_storage_t array[Prealloc]; +}; + +template +class QVLABase +{ +protected: + ~QVLABase() = default; + + qsizetype a; // capacity + qsizetype s; // size + T *ptr; // data +}; // Prealloc = 256 by default, specified in qcontainerfwd.h template class QVarLengthArray + : public QVLABase, // ### Qt 7: swap base class order + public QVLAStorage { + using Base = QVLABase; + using Storage = QVLAStorage; static_assert(std::is_nothrow_destructible_v, "Types with throwing destructors are not supported in Qt containers."); Q_ALWAYS_INLINE void verify(qsizetype pos = 0, qsizetype n = 1) const @@ -75,8 +98,10 @@ class QVarLengthArray public: QVarLengthArray() noexcept - : a{Prealloc}, s{0}, ptr{reinterpret_cast(array)} { + this->a = Prealloc; + this->s = 0; + this->ptr = reinterpret_cast(this->array); } inline explicit QVarLengthArray(qsizetype size); @@ -89,14 +114,12 @@ public: QVarLengthArray(QVarLengthArray &&other) noexcept(std::is_nothrow_move_constructible_v) - : a{other.a}, - s{other.s}, - ptr{other.ptr} + : Base(other) { const auto otherInlineStorage = reinterpret_cast(other.array); if (data() == otherInlineStorage) { // inline buffer - move into our inline buffer: - ptr = reinterpret_cast(array); + this->ptr = reinterpret_cast(this->array); QtPrivate::q_uninitialized_relocate_n(otherInlineStorage, size(), data()); } else { // heap buffer - we just stole the memory @@ -124,7 +147,7 @@ public: { if constexpr (QTypeInfo::isComplex) std::destroy_n(data(), size()); - if (data() != reinterpret_cast(array)) + if (data() != reinterpret_cast(this->array)) free(data()); } inline QVarLengthArray &operator=(const QVarLengthArray &other) @@ -147,13 +170,13 @@ public: const auto otherInlineStorage = reinterpret_cast(other.array); if (other.ptr != otherInlineStorage) { // heap storage: steal the external buffer, reset other to otherInlineStorage - a = std::exchange(other.a, Prealloc); - ptr = std::exchange(other.ptr, otherInlineStorage); + this->a = std::exchange(other.a, Prealloc); + this->ptr = std::exchange(other.ptr, otherInlineStorage); } else { // inline storage: move into our storage (doesn't matter whether inline or external) QtPrivate::q_uninitialized_relocate_n(other.data(), other.size(), data()); } - s = std::exchange(other.s, 0); + this->s = std::exchange(other.s, 0); return *this; } @@ -161,7 +184,7 @@ public: { resize(qsizetype(list.size())); std::copy(list.begin(), list.end(), - QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size())); + QT_MAKE_CHECKED_ARRAY_ITERATOR(begin(), size())); return *this; } @@ -170,9 +193,9 @@ public: verify(); if constexpr (QTypeInfo::isComplex) data()[size() - 1].~T(); - --s; + --this->s; } - inline qsizetype size() const { return s; } + inline qsizetype size() const { return this->s; } inline qsizetype count() const { return size(); } inline qsizetype length() const { return size(); } inline T &first() @@ -200,7 +223,7 @@ public: inline void clear() { resize(0); } void squeeze() { reallocate(size(), size()); } - inline qsizetype capacity() const { return a; } + qsizetype capacity() const { return this->a; } void reserve(qsizetype sz) { if (sz > capacity()) reallocate(size(), sz); } template @@ -262,8 +285,8 @@ public: template qsizetype removeIf(Predicate pred); - inline T *data() { return ptr; } - inline const T *data() const { return ptr; } + inline T *data() { return this->ptr; } + inline const T *data() const { return this->ptr; } inline const T *constData() const { return data(); } typedef qsizetype size_type; typedef T value_type; @@ -374,11 +397,6 @@ public: private: void reallocate(qsizetype size, qsizetype alloc); - qsizetype a; // capacity - qsizetype s; // size - T *ptr; // data - std::aligned_storage_t array[Prealloc]; - bool isValidIterator(const const_iterator &i) const { const std::less less = {}; @@ -393,16 +411,17 @@ QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray; template Q_INLINE_TEMPLATE QVarLengthArray::QVarLengthArray(qsizetype asize) - : s(asize) { +{ + this->s = asize; static_assert(Prealloc > 0, "QVarLengthArray Prealloc must be greater than 0."); Q_ASSERT_X(size() >= 0, "QVarLengthArray::QVarLengthArray()", "Size must be greater than or equal to 0."); if (size() > Prealloc) { - ptr = reinterpret_cast(malloc(s * sizeof(T))); + this->ptr = reinterpret_cast(malloc(size() * sizeof(T))); Q_CHECK_PTR(data()); - a = size(); + this->a = size(); } else { - ptr = reinterpret_cast(array); - a = Prealloc; + this->ptr = reinterpret_cast(this->array); + this->a = Prealloc; } if constexpr (QTypeInfo::isComplex) { T *i = end(); @@ -476,7 +495,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::append(const T *abuf, qs else memcpy(static_cast(end()), static_cast(abuf), increment * sizeof(T)); - s = asize; + this->s = asize; } template @@ -504,16 +523,16 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::reallocate(qsizetype asi // by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here newA = aalloc; } else { - newPtr = reinterpret_cast(array); + newPtr = reinterpret_cast(this->array); newA = Prealloc; } QtPrivate::q_uninitialized_relocate_n(oldPtr, copySize, newPtr); // commit: - ptr = newPtr; + this->ptr = newPtr; guard.release(); - a = newA; + this->a = newA; } - s = copySize; + this->s = copySize; // destroy remaining old objects if constexpr (QTypeInfo::isComplex) { @@ -521,17 +540,17 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::reallocate(qsizetype asi std::destroy(oldPtr + asize, oldPtr + osize); } - if (oldPtr != reinterpret_cast(array) && oldPtr != data()) + if (oldPtr != reinterpret_cast(this->array) && oldPtr != data()) free(oldPtr); if constexpr (QTypeInfo::isComplex) { // call default constructor for new objects (which can throw) while (size() < asize) { new (data() + size()) T; - ++s; + ++this->s; } } else { - s = asize; + this->s = asize; } } @@ -620,7 +639,7 @@ Q_OUTOFLINE_TEMPLATE auto QVarLengthArray::emplace(const_iterator b memmove(static_cast(b + 1), static_cast(b), (size() - offset) * sizeof(T)); new (b) T(std::forward(args)...); } - s += 1; + this->s += 1; return data() + offset; } @@ -669,7 +688,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray::iterator QVarLengthA } else { memmove(static_cast(data() + f), static_cast(data() + l), (size() - l) * sizeof(T)); } - s -= n; + this->s -= n; return data() + f; }