Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:42

0001 // Copyright (C) 2021 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QVARLENGTHARRAY_H
0005 #define QVARLENGTHARRAY_H
0006 
0007 #if 0
0008 #pragma qt_class(QVarLengthArray)
0009 #pragma qt_sync_stop_processing
0010 #endif
0011 
0012 #include <QtCore/qcontainerfwd.h>
0013 #include <QtCore/qglobal.h>
0014 #include <QtCore/qalgorithms.h>
0015 #include <QtCore/qcontainertools_impl.h>
0016 #include <QtCore/qhashfunctions.h>
0017 
0018 #include <algorithm>
0019 #include <initializer_list>
0020 #include <iterator>
0021 #include <QtCore/q20memory.h>
0022 #include <new>
0023 
0024 #include <string.h>
0025 #include <stdlib.h>
0026 
0027 QT_BEGIN_NAMESPACE
0028 
0029 template <size_t Size, size_t Align, qsizetype Prealloc>
0030 class QVLAStorage
0031 {
0032     template <size_t> class print;
0033 protected:
0034     ~QVLAStorage() = default;
0035 
0036     alignas(Align) char array[Prealloc * (Align > Size ? Align : Size)];
0037     QT_WARNING_PUSH
0038     QT_WARNING_DISABLE_DEPRECATED
0039     // ensure we maintain BC: std::aligned_storage_t was only specified by a
0040     // minimum size, but for BC we need the substitution to be exact in size:
0041     static_assert(std::is_same_v<print<sizeof(std::aligned_storage_t<Size, Align>[Prealloc])>,
0042                                  print<sizeof(array)>>);
0043     QT_WARNING_POP
0044 };
0045 
0046 class QVLABaseBase
0047 {
0048 protected:
0049     ~QVLABaseBase() = default;
0050 
0051     qsizetype a;      // capacity
0052     qsizetype s;      // size
0053     void *ptr;     // data
0054 
0055     Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
0056                                           [[maybe_unused]] qsizetype n = 1) const
0057     {
0058         Q_ASSERT(pos >= 0);
0059         Q_ASSERT(pos <= size());
0060         Q_ASSERT(n >= 0);
0061         Q_ASSERT(n <= size() - pos);
0062     }
0063 
0064     struct free_deleter {
0065         void operator()(void *p) const noexcept { free(p); }
0066     };
0067     using malloced_ptr = std::unique_ptr<void, free_deleter>;
0068 
0069 public:
0070     using size_type = qsizetype;
0071 
0072     constexpr size_type capacity() const noexcept { return a; }
0073     constexpr size_type size() const noexcept { return s; }
0074     constexpr bool empty() const noexcept { return size() == 0; }
0075 };
0076 
0077 template<class T>
0078 class QVLABase : public QVLABaseBase
0079 {
0080 protected:
0081     ~QVLABase() = default;
0082 
0083 public:
0084     T *data() noexcept { return static_cast<T *>(ptr); }
0085     const T *data() const noexcept { return static_cast<T *>(ptr); }
0086 
0087     using iterator = T*;
0088     using const_iterator = const T*;
0089 
0090     iterator begin() noexcept { return data(); }
0091     const_iterator begin() const noexcept { return data(); }
0092     const_iterator cbegin() const noexcept { return begin(); }
0093     iterator end() noexcept { return data() + size(); }
0094     const_iterator end() const noexcept { return data() + size(); }
0095     const_iterator cend() const noexcept { return end(); }
0096 
0097     using reverse_iterator = std::reverse_iterator<iterator>;
0098     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0099 
0100     reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
0101     const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
0102     const_reverse_iterator crbegin() const noexcept { return rbegin(); }
0103     reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
0104     const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
0105     const_reverse_iterator crend() const noexcept { return rend(); }
0106 
0107     using value_type = T;
0108     using reference = value_type&;
0109     using const_reference = const value_type&;
0110     using pointer = value_type*;
0111     using const_pointer = const value_type*;
0112     using difference_type = qptrdiff;
0113 
0114     reference front()
0115     {
0116         verify();
0117         return *begin();
0118     }
0119 
0120     const_reference front() const
0121     {
0122         verify();
0123         return *begin();
0124     }
0125 
0126     reference back()
0127     {
0128         verify();
0129         return *rbegin();
0130     }
0131 
0132     const_reference back() const
0133     {
0134         verify();
0135         return *rbegin();
0136     }
0137 
0138     void pop_back()
0139     {
0140         verify();
0141         if constexpr (QTypeInfo<T>::isComplex)
0142             data()[size() - 1].~T();
0143         --s;
0144     }
0145 
0146     template <typename AT = T>
0147     qsizetype indexOf(const AT &t, qsizetype from = 0) const;
0148     template <typename AT = T>
0149     qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const;
0150     template <typename AT = T>
0151     bool contains(const AT &t) const;
0152 
0153     reference operator[](qsizetype idx)
0154     {
0155         verify(idx);
0156         return data()[idx];
0157     }
0158     const_reference operator[](qsizetype idx) const
0159     {
0160         verify(idx);
0161         return data()[idx];
0162     }
0163 
0164     value_type value(qsizetype i) const;
0165     value_type value(qsizetype i, const T& defaultValue) const;
0166 
0167     void replace(qsizetype i, const T &t);
0168     void remove(qsizetype i, qsizetype n = 1);
0169     template <typename AT = T>
0170     qsizetype removeAll(const AT &t);
0171     template <typename AT = T>
0172     bool removeOne(const AT &t);
0173     template <typename Predicate>
0174     qsizetype removeIf(Predicate pred);
0175 
0176     void clear()
0177     {
0178         if constexpr (QTypeInfo<T>::isComplex)
0179             std::destroy_n(data(), size());
0180         s = 0;
0181     }
0182 
0183     iterator erase(const_iterator begin, const_iterator end);
0184     iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
0185 
0186     size_t hash(size_t seed) const noexcept(QtPrivate::QNothrowHashable_v<T>)
0187     {
0188         return qHashRange(begin(), end(), seed);
0189     }
0190 protected:
0191     void growBy(qsizetype prealloc, void *array, qsizetype increment)
0192     { reallocate_impl(prealloc, array, size(), (std::max)(size() * 2, size() + increment)); }
0193     template <typename...Args>
0194     reference emplace_back_impl(qsizetype prealloc, void *array, Args&&...args)
0195     {
0196         if (size() == capacity()) // ie. size() != 0
0197             growBy(prealloc, array, 1);
0198         reference r = *q20::construct_at(end(), std::forward<Args>(args)...);
0199         ++s;
0200         return r;
0201     }
0202     template <typename...Args>
0203     iterator emplace_impl(qsizetype prealloc, void *array, const_iterator pos, Args&&...arg);
0204 
0205     iterator insert_impl(qsizetype prealloc, void *array, const_iterator pos, qsizetype n, const T &t);
0206 
0207     template <typename S>
0208     bool equal(const QVLABase<S> &other) const
0209     {
0210         return std::equal(begin(), end(), other.begin(), other.end());
0211     }
0212     template <typename S>
0213     bool less_than(const QVLABase<S> &other) const
0214     {
0215         return std::lexicographical_compare(begin(), end(), other.begin(), other.end());
0216     }
0217 
0218     void append_impl(qsizetype prealloc, void *array, const T *buf, qsizetype n);
0219     void reallocate_impl(qsizetype prealloc, void *array, qsizetype size, qsizetype alloc);
0220     void resize_impl(qsizetype prealloc, void *array, qsizetype sz, const T &v)
0221     {
0222         if (QtPrivate::q_points_into_range(&v, begin(), end())) {
0223             resize_impl(prealloc, array, sz, T(v));
0224             return;
0225         }
0226         reallocate_impl(prealloc, array, sz, qMax(sz, capacity()));
0227         while (size() < sz) {
0228             q20::construct_at(data() + size(), v);
0229             ++s;
0230         }
0231     }
0232     void resize_impl(qsizetype prealloc, void *array, qsizetype sz)
0233     {
0234         reallocate_impl(prealloc, array, sz, qMax(sz, capacity()));
0235         if constexpr (QTypeInfo<T>::isComplex) {
0236             // call default constructor for new objects (which can throw)
0237             while (size() < sz) {
0238                 q20::construct_at(data() + size());
0239                 ++s;
0240             }
0241         } else {
0242             s = sz;
0243         }
0244     }
0245 
0246     void assign_impl(qsizetype prealloc, void *array, qsizetype n, const T &t);
0247     template <typename Iterator>
0248     void assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last);
0249 
0250     bool isValidIterator(const const_iterator &i) const
0251     {
0252         const std::less<const T *> less = {};
0253         return !less(cend(), i) && !less(i, cbegin());
0254     }
0255 };
0256 
0257 // Prealloc = 256 by default, specified in qcontainerfwd.h
0258 template<class T, qsizetype Prealloc>
0259 class QVarLengthArray
0260 #if QT_VERSION >= QT_VERSION_CHECK(7,0,0) || defined(QT_BOOTSTRAPPED)
0261     : public QVLAStorage<sizeof(T), alignof(T), Prealloc>,
0262       public QVLABase<T>
0263 #else
0264     : public QVLABase<T>,
0265       public QVLAStorage<sizeof(T), alignof(T), Prealloc>
0266 #endif
0267 {
0268     template <class S, qsizetype Prealloc2>
0269     friend class QVarLengthArray;
0270     using Base = QVLABase<T>;
0271     using Storage = QVLAStorage<sizeof(T), alignof(T), Prealloc>;
0272     static_assert(Prealloc > 0, "QVarLengthArray Prealloc must be greater than 0.");
0273     static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0274     using Base::verify;
0275 
0276     template <typename U>
0277     using if_copyable = std::enable_if_t<std::is_copy_constructible_v<U>, bool>;
0278     template <typename InputIterator>
0279     using if_input_iterator = QtPrivate::IfIsInputIterator<InputIterator>;
0280 public:
0281     using size_type = typename Base::size_type;
0282     using value_type = typename Base::value_type;
0283     using pointer = typename Base::pointer;
0284     using const_pointer = typename Base::const_pointer;
0285     using reference = typename Base::reference;
0286     using const_reference = typename Base::const_reference;
0287     using difference_type = typename Base::difference_type;
0288 
0289     using iterator = typename Base::iterator;
0290     using const_iterator = typename Base::const_iterator;
0291     using reverse_iterator = typename Base::reverse_iterator;
0292     using const_reverse_iterator = typename Base::const_reverse_iterator;
0293 
0294     QVarLengthArray() noexcept
0295     {
0296         this->a = Prealloc;
0297         this->s = 0;
0298         this->ptr = this->array;
0299     }
0300 
0301     inline explicit QVarLengthArray(qsizetype size);
0302 
0303 #ifndef Q_QDOC
0304     template <typename U = T, if_copyable<U> = true>
0305 #endif
0306     explicit QVarLengthArray(qsizetype sz, const T &v)
0307         : QVarLengthArray{}
0308     {
0309         resize(sz, v);
0310     }
0311 
0312     QVarLengthArray(const QVarLengthArray &other)
0313         : QVarLengthArray{}
0314     {
0315         append(other.constData(), other.size());
0316     }
0317 
0318     QVarLengthArray(QVarLengthArray &&other)
0319             noexcept(std::is_nothrow_move_constructible_v<T>)
0320         : Base(other)
0321     {
0322         const auto otherInlineStorage = reinterpret_cast<T*>(other.array);
0323         if (data() == otherInlineStorage) {
0324             // inline buffer - move into our inline buffer:
0325             this->ptr = this->array;
0326             QtPrivate::q_uninitialized_relocate_n(otherInlineStorage, size(), data());
0327         } else {
0328             // heap buffer - we just stole the memory
0329         }
0330         // reset other to internal storage:
0331         other.a = Prealloc;
0332         other.s = 0;
0333         other.ptr = otherInlineStorage;
0334     }
0335 
0336     QVarLengthArray(std::initializer_list<T> args)
0337         : QVarLengthArray(args.begin(), args.end())
0338     {
0339     }
0340 
0341     template <typename InputIterator, if_input_iterator<InputIterator> = true>
0342     inline QVarLengthArray(InputIterator first, InputIterator last)
0343         : QVarLengthArray()
0344     {
0345         QtPrivate::reserveIfForwardIterator(this, first, last);
0346         std::copy(first, last, std::back_inserter(*this));
0347     }
0348 
0349     inline ~QVarLengthArray()
0350     {
0351         if constexpr (QTypeInfo<T>::isComplex)
0352             std::destroy_n(data(), size());
0353         if (data() != reinterpret_cast<T *>(this->array))
0354             free(data());
0355     }
0356     inline QVarLengthArray<T, Prealloc> &operator=(const QVarLengthArray<T, Prealloc> &other)
0357     {
0358         if (this != &other) {
0359             clear();
0360             append(other.constData(), other.size());
0361         }
0362         return *this;
0363     }
0364 
0365     QVarLengthArray &operator=(QVarLengthArray &&other)
0366         noexcept(std::is_nothrow_move_constructible_v<T>)
0367     {
0368         // we're only required to be self-move-assignment-safe
0369         // when we're in the moved-from state (Hinnant criterion)
0370         // the moved-from state is the empty state, so we're good with the clear() here:
0371         clear();
0372         Q_ASSERT(capacity() >= Prealloc);
0373         const auto otherInlineStorage = other.array;
0374         if (other.ptr != otherInlineStorage) {
0375             // heap storage: steal the external buffer, reset other to otherInlineStorage
0376             this->a = std::exchange(other.a, Prealloc);
0377             this->ptr = std::exchange(other.ptr, otherInlineStorage);
0378         } else {
0379             // inline storage: move into our storage (doesn't matter whether inline or external)
0380             QtPrivate::q_uninitialized_relocate_n(other.data(), other.size(), data());
0381         }
0382         this->s = std::exchange(other.s, 0);
0383         return *this;
0384     }
0385 
0386     QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
0387     {
0388         assign(list);
0389         return *this;
0390     }
0391 
0392     inline void removeLast()
0393     {
0394         Base::pop_back();
0395     }
0396 #ifdef Q_QDOC
0397     inline qsizetype size() const { return this->s; }
0398 #endif
0399     using Base::size;
0400     inline qsizetype count() const { return size(); }
0401     inline qsizetype length() const { return size(); }
0402     inline T &first()
0403     {
0404         return front();
0405     }
0406     inline const T &first() const
0407     {
0408         return front();
0409     }
0410     T &last()
0411     {
0412         return back();
0413     }
0414     const T &last() const
0415     {
0416         return back();
0417     }
0418     bool isEmpty() const { return empty(); }
0419     void resize(qsizetype sz) { Base::resize_impl(Prealloc, this->array, sz); }
0420 #ifndef Q_QDOC
0421     template <typename U = T, if_copyable<U> = true>
0422 #endif
0423     void resize(qsizetype sz, const T &v)
0424     { Base::resize_impl(Prealloc, this->array, sz, v); }
0425     using Base::clear;
0426 #ifdef Q_QDOC
0427     inline void clear() { resize(0); }
0428 #endif
0429     void squeeze() { reallocate(size(), size()); }
0430 
0431     using Base::capacity;
0432 #ifdef Q_QDOC
0433     qsizetype capacity() const { return this->a; }
0434 #endif
0435     void reserve(qsizetype sz) { if (sz > capacity()) reallocate(size(), sz); }
0436 
0437 #ifdef Q_QDOC
0438     template <typename AT = T>
0439     inline qsizetype indexOf(const AT &t, qsizetype from = 0) const;
0440     template <typename AT = T>
0441     inline qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const;
0442     template <typename AT = T>
0443     inline bool contains(const AT &t) const;
0444 #endif
0445     using Base::indexOf;
0446     using Base::lastIndexOf;
0447     using Base::contains;
0448 
0449 #ifdef Q_QDOC
0450     inline T &operator[](qsizetype idx)
0451     {
0452         verify(idx);
0453         return data()[idx];
0454     }
0455     inline const T &operator[](qsizetype idx) const
0456     {
0457         verify(idx);
0458         return data()[idx];
0459     }
0460 #endif
0461     using Base::operator[];
0462     inline const T &at(qsizetype idx) const { return operator[](idx); }
0463 
0464 #ifdef Q_QDOC
0465     T value(qsizetype i) const;
0466     T value(qsizetype i, const T &defaultValue) const;
0467 #endif
0468     using Base::value;
0469 
0470     inline void append(const T &t)
0471     {
0472         if (size() == capacity())
0473             emplace_back(T(t));
0474         else
0475             emplace_back(t);
0476     }
0477 
0478     void append(T &&t)
0479     {
0480         emplace_back(std::move(t));
0481     }
0482 
0483     void append(const T *buf, qsizetype sz)
0484     { Base::append_impl(Prealloc, this->array, buf, sz); }
0485     inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
0486     { append(t); return *this; }
0487     inline QVarLengthArray<T, Prealloc> &operator<<(T &&t)
0488     { append(std::move(t)); return *this; }
0489     inline QVarLengthArray<T, Prealloc> &operator+=(const T &t)
0490     { append(t); return *this; }
0491     inline QVarLengthArray<T, Prealloc> &operator+=(T &&t)
0492     { append(std::move(t)); return *this; }
0493 
0494 #if QT_DEPRECATED_SINCE(6, 3)
0495     QT_DEPRECATED_VERSION_X_6_3("This is slow. If you must, use insert(cbegin(), ~~~) instead.")
0496     void prepend(T &&t);
0497     QT_DEPRECATED_VERSION_X_6_3("This is slow. If you must, use insert(cbegin(), ~~~) instead.")
0498     void prepend(const T &t);
0499 #endif
0500     void insert(qsizetype i, T &&t);
0501     void insert(qsizetype i, const T &t);
0502     void insert(qsizetype i, qsizetype n, const T &t);
0503 
0504     QVarLengthArray &assign(qsizetype n, const T &t)
0505     { Base::assign_impl(Prealloc, this->array, n, t); return *this; }
0506     template <typename InputIterator, if_input_iterator<InputIterator> = true>
0507     QVarLengthArray &assign(InputIterator first, InputIterator last)
0508     { Base::assign_impl(Prealloc, this->array, first, last); return *this; }
0509     QVarLengthArray &assign(std::initializer_list<T> list)
0510     { assign(list.begin(), list.end()); return *this; }
0511 
0512 #ifdef Q_QDOC
0513     void replace(qsizetype i, const T &t);
0514     void remove(qsizetype i, qsizetype n = 1);
0515     template <typename AT = T>
0516     qsizetype removeAll(const AT &t);
0517     template <typename AT = T>
0518     bool removeOne(const AT &t);
0519     template <typename Predicate>
0520     qsizetype removeIf(Predicate pred);
0521 #endif
0522     using Base::replace;
0523     using Base::remove;
0524     using Base::removeAll;
0525     using Base::removeOne;
0526     using Base::removeIf;
0527 
0528 #ifdef Q_QDOC
0529     inline T *data() { return this->ptr; }
0530     inline const T *data() const { return this->ptr; }
0531 #endif
0532     using Base::data;
0533     inline const T *constData() const { return data(); }
0534 #ifdef Q_QDOC
0535     inline iterator begin() { return data(); }
0536     inline const_iterator begin() const { return data(); }
0537     inline const_iterator cbegin() const { return begin(); }
0538     inline const_iterator constBegin() const { return begin(); }
0539     inline iterator end() { return data() + size(); }
0540     inline const_iterator end() const { return data() + size(); }
0541     inline const_iterator cend() const { return end(); }
0542 #endif
0543 
0544     using Base::begin;
0545     using Base::cbegin;
0546     auto constBegin() const -> const_iterator { return begin(); }
0547     using Base::end;
0548     using Base::cend;
0549     inline const_iterator constEnd() const { return end(); }
0550 #ifdef Q_QDOC
0551     reverse_iterator rbegin() { return reverse_iterator(end()); }
0552     reverse_iterator rend() { return reverse_iterator(begin()); }
0553     const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
0554     const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
0555     const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }
0556     const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }
0557 #endif
0558     using Base::rbegin;
0559     using Base::crbegin;
0560     using Base::rend;
0561     using Base::crend;
0562 
0563     iterator insert(const_iterator before, qsizetype n, const T &x)
0564     { return Base::insert_impl(Prealloc, this->array, before, n, x); }
0565     iterator insert(const_iterator before, T &&x) { return emplace(before, std::move(x)); }
0566     inline iterator insert(const_iterator before, const T &x) { return insert(before, 1, x); }
0567 #ifdef Q_QDOC
0568     iterator erase(const_iterator begin, const_iterator end);
0569     inline iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
0570 #endif
0571     using Base::erase;
0572 
0573     // STL compatibility:
0574 #ifdef Q_QDOC
0575     inline bool empty() const { return isEmpty(); }
0576 #endif
0577     using Base::empty;
0578     inline void push_back(const T &t) { append(t); }
0579     void push_back(T &&t) { append(std::move(t)); }
0580 #ifdef Q_QDOC
0581     inline void pop_back() { removeLast(); }
0582     inline T &front() { return first(); }
0583     inline const T &front() const { return first(); }
0584     inline T &back() { return last(); }
0585     inline const T &back() const { return last(); }
0586 #endif
0587     using Base::pop_back;
0588     using Base::front;
0589     using Base::back;
0590     void shrink_to_fit() { squeeze(); }
0591     template <typename...Args>
0592     iterator emplace(const_iterator pos, Args &&...args)
0593     { return Base::emplace_impl(Prealloc, this->array, pos, std::forward<Args>(args)...); }
0594     template <typename...Args>
0595     T &emplace_back(Args &&...args)
0596     { return Base::emplace_back_impl(Prealloc, this->array, std::forward<Args>(args)...); }
0597 
0598 
0599 #ifdef Q_QDOC
0600     template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0601     friend inline bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
0602     template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0603     friend inline bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
0604     template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0605     friend inline bool operator< (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
0606     template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0607     friend inline bool operator> (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
0608     template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0609     friend inline bool operator<=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
0610     template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0611     friend inline bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
0612 #else
0613     template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
0614     QTypeTraits::compare_eq_result<U> operator==(const QVarLengthArray<T, Prealloc> &l, const QVarLengthArray<T, Prealloc2> &r)
0615     {
0616         return l.equal(r);
0617     }
0618 
0619     template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
0620     QTypeTraits::compare_eq_result<U> operator!=(const QVarLengthArray<T, Prealloc> &l, const QVarLengthArray<T, Prealloc2> &r)
0621     {
0622         return !(l == r);
0623     }
0624 
0625     template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
0626     QTypeTraits::compare_lt_result<U> operator<(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
0627         noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
0628                                                        rhs.begin(), rhs.end())))
0629     {
0630         return lhs.less_than(rhs);
0631     }
0632 
0633     template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
0634     QTypeTraits::compare_lt_result<U> operator>(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
0635         noexcept(noexcept(lhs < rhs))
0636     {
0637         return rhs < lhs;
0638     }
0639 
0640     template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
0641     QTypeTraits::compare_lt_result<U> operator<=(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
0642         noexcept(noexcept(lhs < rhs))
0643     {
0644         return !(lhs > rhs);
0645     }
0646 
0647     template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
0648     QTypeTraits::compare_lt_result<U> operator>=(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
0649         noexcept(noexcept(lhs < rhs))
0650     {
0651         return !(lhs < rhs);
0652     }
0653 #endif
0654 
0655 private:
0656     template <typename U, qsizetype Prealloc2>
0657     bool equal(const QVarLengthArray<U, Prealloc2> &other) const
0658     { return Base::equal(other); }
0659     template <typename U, qsizetype Prealloc2>
0660     bool less_than(const QVarLengthArray<U, Prealloc2> &other) const
0661     { return Base::less_than(other); }
0662 
0663     void reallocate(qsizetype sz, qsizetype alloc)
0664     { Base::reallocate_impl(Prealloc, this->array, sz, alloc); }
0665 
0666     using Base::isValidIterator;
0667 };
0668 
0669 template <typename InputIterator,
0670           typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
0671           QtPrivate::IfIsInputIterator<InputIterator> = true>
0672 QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray<ValueType>;
0673 
0674 template <class T, qsizetype Prealloc>
0675 Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype asize)
0676     : QVarLengthArray()
0677 {
0678     Q_ASSERT_X(asize >= 0, "QVarLengthArray::QVarLengthArray(qsizetype)",
0679                "Size must be greater than or equal to 0.");
0680 
0681     // historically, this ctor worked for non-copyable/non-movable T, so keep it working, why not?
0682     // resize(asize) // this requires a movable or copyable T, can't use, need to do it by hand
0683 
0684     if (asize > Prealloc) {
0685         this->ptr = malloc(asize * sizeof(T));
0686         Q_CHECK_PTR(this->ptr);
0687         this->a = asize;
0688     }
0689     if constexpr (QTypeInfo<T>::isComplex)
0690         std::uninitialized_default_construct_n(data(), asize);
0691     this->s = asize;
0692 }
0693 
0694 template <class T>
0695 template <typename AT>
0696 Q_INLINE_TEMPLATE qsizetype QVLABase<T>::indexOf(const AT &t, qsizetype from) const
0697 {
0698     if (from < 0)
0699         from = qMax(from + size(), qsizetype(0));
0700     if (from < size()) {
0701         const T *n = data() + from - 1;
0702         const T *e = end();
0703         while (++n != e)
0704             if (*n == t)
0705                 return n - data();
0706     }
0707     return -1;
0708 }
0709 
0710 template <class T>
0711 template <typename AT>
0712 Q_INLINE_TEMPLATE qsizetype QVLABase<T>::lastIndexOf(const AT &t, qsizetype from) const
0713 {
0714     if (from < 0)
0715         from += size();
0716     else if (from >= size())
0717         from = size() - 1;
0718     if (from >= 0) {
0719         const T *b = begin();
0720         const T *n = b + from + 1;
0721         while (n != b) {
0722             if (*--n == t)
0723                 return n - b;
0724         }
0725     }
0726     return -1;
0727 }
0728 
0729 template <class T>
0730 template <typename AT>
0731 Q_INLINE_TEMPLATE bool QVLABase<T>::contains(const AT &t) const
0732 {
0733     const T *b = begin();
0734     const T *i = end();
0735     while (i != b) {
0736         if (*--i == t)
0737             return true;
0738     }
0739     return false;
0740 }
0741 
0742 template <class T>
0743 Q_OUTOFLINE_TEMPLATE void QVLABase<T>::append_impl(qsizetype prealloc, void *array, const T *abuf, qsizetype increment)
0744 {
0745     Q_ASSERT(abuf || increment == 0);
0746     if (increment <= 0)
0747         return;
0748 
0749     const qsizetype asize = size() + increment;
0750 
0751     if (asize >= capacity())
0752         growBy(prealloc, array, increment);
0753 
0754     if constexpr (QTypeInfo<T>::isComplex)
0755         std::uninitialized_copy_n(abuf, increment, end());
0756     else
0757         memcpy(static_cast<void *>(end()), static_cast<const void *>(abuf), increment * sizeof(T));
0758 
0759     this->s = asize;
0760 }
0761 
0762 template <class T>
0763 Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, qsizetype n, const T &t)
0764 {
0765     Q_ASSERT(n >= 0);
0766     if (n > capacity()) {
0767         reallocate_impl(prealloc, array, 0, capacity()); // clear
0768         resize_impl(prealloc, array, n, t);
0769     } else {
0770         auto mid = (std::min)(n, size());
0771         std::fill(data(), data() + mid, t);
0772         std::uninitialized_fill(data() + mid, data() + n, t);
0773         s = n;
0774         erase(data() + n, data() + size());
0775     }
0776 }
0777 
0778 template <class T>
0779 template <typename Iterator>
0780 Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last)
0781 {
0782     // This function only provides the basic exception guarantee.
0783     constexpr bool IsFwdIt =
0784             std::is_convertible_v<typename std::iterator_traits<Iterator>::iterator_category,
0785                                   std::forward_iterator_tag>;
0786     if constexpr (IsFwdIt) {
0787         const qsizetype n = std::distance(first, last);
0788         if (n > capacity())
0789             reallocate_impl(prealloc, array, 0, n); // clear & reserve n
0790     }
0791 
0792     auto dst = begin();
0793     const auto dend = end();
0794     while (true) {
0795         if (first == last) {          // ran out of elements to assign
0796             std::destroy(dst, dend);
0797             break;
0798         }
0799         if (dst == dend) {            // ran out of existing elements to overwrite
0800             if constexpr (IsFwdIt) {
0801                 dst = std::uninitialized_copy(first, last, dst);
0802                 break;
0803             } else {
0804                 do {
0805                     emplace_back_impl(prealloc, array, *first);
0806                 } while (++first != last);
0807                 return; // size() is already correct (and dst invalidated)!
0808             }
0809         }
0810         *dst = *first;                // overwrite existing element
0811         ++dst;
0812         ++first;
0813     }
0814     this->s = dst - begin();
0815 }
0816 
0817 template <class T>
0818 Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void *array, qsizetype asize, qsizetype aalloc)
0819 {
0820     Q_ASSERT(aalloc >= asize);
0821     Q_ASSERT(data());
0822     T *oldPtr = data();
0823     qsizetype osize = size();
0824 
0825     const qsizetype copySize = qMin(asize, osize);
0826     Q_ASSERT(copySize >= 0);
0827 
0828     if (aalloc != capacity()) {
0829         QVLABaseBase::malloced_ptr guard;
0830         void *newPtr;
0831         qsizetype newA;
0832         if (aalloc > prealloc) {
0833             newPtr = malloc(aalloc * sizeof(T));
0834             guard.reset(newPtr);
0835             Q_CHECK_PTR(newPtr); // could throw
0836             // by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here
0837             newA = aalloc;
0838         } else {
0839             newPtr = array;
0840             newA = prealloc;
0841         }
0842         QtPrivate::q_uninitialized_relocate_n(oldPtr, copySize,
0843                                               reinterpret_cast<T *>(newPtr));
0844         // commit:
0845         ptr = newPtr;
0846         guard.release();
0847         a = newA;
0848     }
0849     s = copySize;
0850 
0851     // destroy remaining old objects
0852     if constexpr (QTypeInfo<T>::isComplex) {
0853         if (osize > asize)
0854             std::destroy(oldPtr + asize, oldPtr + osize);
0855     }
0856 
0857     if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != data())
0858         free(oldPtr);
0859 }
0860 
0861 template <class T>
0862 Q_OUTOFLINE_TEMPLATE T QVLABase<T>::value(qsizetype i) const
0863 {
0864     if (size_t(i) >= size_t(size()))
0865         return T();
0866     return operator[](i);
0867 }
0868 template <class T>
0869 Q_OUTOFLINE_TEMPLATE T QVLABase<T>::value(qsizetype i, const T &defaultValue) const
0870 {
0871     return (size_t(i) >= size_t(size())) ? defaultValue : operator[](i);
0872 }
0873 
0874 template <class T, qsizetype Prealloc>
0875 inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, T &&t)
0876 { verify(i, 0);
0877   insert(cbegin() + i, std::move(t)); }
0878 template <class T, qsizetype Prealloc>
0879 inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, const T &t)
0880 { verify(i, 0);
0881   insert(begin() + i, 1, t); }
0882 template <class T, qsizetype Prealloc>
0883 inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, qsizetype n, const T &t)
0884 { verify(i, 0);
0885   insert(begin() + i, n, t); }
0886 template <class T>
0887 inline void QVLABase<T>::remove(qsizetype i, qsizetype n)
0888 { verify(i, n);
0889   erase(begin() + i, begin() + i + n); }
0890 template <class T>
0891 template <typename AT>
0892 inline qsizetype QVLABase<T>::removeAll(const AT &t)
0893 { return QtPrivate::sequential_erase_with_copy(*this, t); }
0894 template <class T>
0895 template <typename AT>
0896 inline bool QVLABase<T>::removeOne(const AT &t)
0897 { return QtPrivate::sequential_erase_one(*this, t); }
0898 template <class T>
0899 template <typename Predicate>
0900 inline qsizetype QVLABase<T>::removeIf(Predicate pred)
0901 { return QtPrivate::sequential_erase_if(*this, pred); }
0902 #if QT_DEPRECATED_SINCE(6, 3)
0903 template <class T, qsizetype Prealloc>
0904 inline void QVarLengthArray<T, Prealloc>::prepend(T &&t)
0905 { insert(cbegin(), std::move(t)); }
0906 template <class T, qsizetype Prealloc>
0907 inline void QVarLengthArray<T, Prealloc>::prepend(const T &t)
0908 { insert(begin(), 1, t); }
0909 #endif
0910 
0911 template <class T>
0912 inline void QVLABase<T>::replace(qsizetype i, const T &t)
0913 {
0914     verify(i);
0915     data()[i] = t;
0916 }
0917 
0918 template <class T>
0919 template <typename...Args>
0920 Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::emplace_impl(qsizetype prealloc, void *array, const_iterator before, Args &&...args) -> iterator
0921 {
0922     Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
0923     Q_ASSERT(size() <= capacity());
0924     Q_ASSERT(capacity() > 0);
0925 
0926     const qsizetype offset = qsizetype(before - cbegin());
0927     emplace_back_impl(prealloc, array, std::forward<Args>(args)...);
0928     const auto b = begin() + offset;
0929     const auto e = end();
0930     QtPrivate::q_rotate(b, e - 1, e);
0931     return b;
0932 }
0933 
0934 template <class T>
0935 Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::insert_impl(qsizetype prealloc, void *array, const_iterator before, qsizetype n, const T &t) -> iterator
0936 {
0937     Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
0938 
0939     const qsizetype offset = qsizetype(before - cbegin());
0940     resize_impl(prealloc, array, size() + n, t);
0941     const auto b = begin() + offset;
0942     const auto e = end();
0943     QtPrivate::q_rotate(b, e - n, e);
0944     return b;
0945 }
0946 
0947 template <class T>
0948 Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::erase(const_iterator abegin, const_iterator aend) -> iterator
0949 {
0950     Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::insert", "The specified const_iterator argument 'abegin' is invalid");
0951     Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::insert", "The specified const_iterator argument 'aend' is invalid");
0952 
0953     qsizetype f = qsizetype(abegin - cbegin());
0954     qsizetype l = qsizetype(aend - cbegin());
0955     qsizetype n = l - f;
0956 
0957     if (n == 0) // avoid UB in std::move() below
0958         return data() + f;
0959 
0960     Q_ASSERT(n > 0); // aend must be reachable from abegin
0961 
0962     if constexpr (QTypeInfo<T>::isComplex) {
0963         std::move(begin() + l, end(), QT_MAKE_CHECKED_ARRAY_ITERATOR(begin() + f, size() - f));
0964         std::destroy(end() - n, end());
0965     } else {
0966         memmove(static_cast<void *>(data() + f), static_cast<const void *>(data() + l), (size() - l) * sizeof(T));
0967     }
0968     this->s -= n;
0969     return data() + f;
0970 }
0971 
0972 #ifdef Q_QDOC
0973 // Fake definitions for qdoc, only the redeclaration is used.
0974 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0975 bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
0976 { return bool{}; }
0977 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0978 bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
0979 { return bool{}; }
0980 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0981 bool operator< (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
0982 { return bool{}; }
0983 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0984 bool operator> (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
0985 { return bool{}; }
0986 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0987 bool operator<=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
0988 { return bool{}; }
0989 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
0990 bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
0991 { return bool{}; }
0992 #endif
0993 
0994 template <typename T, qsizetype Prealloc>
0995 size_t qHash(const QVarLengthArray<T, Prealloc> &key, size_t seed = 0)
0996     noexcept(QtPrivate::QNothrowHashable_v<T>)
0997 {
0998     return key.hash(seed);
0999 }
1000 
1001 template <typename T, qsizetype Prealloc, typename AT>
1002 qsizetype erase(QVarLengthArray<T, Prealloc> &array, const AT &t)
1003 {
1004     return array.removeAll(t);
1005 }
1006 
1007 template <typename T, qsizetype Prealloc, typename Predicate>
1008 qsizetype erase_if(QVarLengthArray<T, Prealloc> &array, Predicate pred)
1009 {
1010     return array.removeIf(pred);
1011 }
1012 
1013 QT_END_NAMESPACE
1014 
1015 #endif // QVARLENGTHARRAY_H