• QVector


    QVector

    /****************************************************************************
    **
    ** Copyright (C) 2016 The Qt Company Ltd.
    ** Contact: https://www.qt.io/licensing/
    **
    ** This file is part of the QtCore module of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:LGPL$
    ** Commercial License Usage
    ** Licensees holding valid commercial Qt licenses may use this file in
    ** accordance with the commercial license agreement provided with the
    ** Software or, alternatively, in accordance with the terms contained in
    ** a written agreement between you and The Qt Company. For licensing terms
    ** and conditions see https://www.qt.io/terms-conditions. For further
    ** information use the contact form at https://www.qt.io/contact-us.
    **
    ** GNU Lesser General Public License Usage
    ** Alternatively, this file may be used under the terms of the GNU Lesser
    ** General Public License version 3 as published by the Free Software
    ** Foundation and appearing in the file LICENSE.LGPL3 included in the
    ** packaging of this file. Please review the following information to
    ** ensure the GNU Lesser General Public License version 3 requirements
    ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
    **
    ** GNU General Public License Usage
    ** Alternatively, this file may be used under the terms of the GNU
    ** General Public License version 2.0 or (at your option) the GNU General
    ** Public license version 3 or any later version approved by the KDE Free
    ** Qt Foundation. The licenses are as published by the Free Software
    ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
    ** included in the packaging of this file. Please review the following
    ** information to ensure the GNU General Public License requirements will
    ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
    ** https://www.gnu.org/licenses/gpl-3.0.html.
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/
    
    #ifndef QVECTOR_H
    #define QVECTOR_H
    
    #include <QtCore/qalgorithms.h>
    #include <QtCore/qiterator.h>
    #include <QtCore/qlist.h>
    #include <QtCore/qrefcount.h>
    #include <QtCore/qarraydata.h>
    #include <QtCore/qhashfunctions.h>
    
    #include <iterator>
    #include <vector>
    #include <stdlib.h>
    #include <string.h>
    #ifdef Q_COMPILER_INITIALIZER_LISTS
    #include <initializer_list>
    #endif
    
    #include <algorithm>
    
    QT_BEGIN_NAMESPACE
    
    template <typename T>
    class QVector
    {
        typedef QTypedArrayData<T> Data;
        Data *d;
    
    public:
        inline QVector() Q_DECL_NOTHROW : d(Data::sharedNull()) { }
        explicit QVector(int size);
        QVector(int size, const T &t);
        inline QVector(const QVector<T> &v);
        inline ~QVector() { if (!d->ref.deref()) freeData(d); }
        QVector<T> &operator=(const QVector<T> &v);
    #if defined(Q_COMPILER_RVALUE_REFS) || defined(Q_CLANG_QDOC)
        QVector(QVector<T> &&other) Q_DECL_NOTHROW : d(other.d) { other.d = Data::sharedNull(); }
        QVector<T> &operator=(QVector<T> &&other) Q_DECL_NOTHROW
        { QVector moved(std::move(other)); swap(moved); return *this; }
    #endif
        void swap(QVector<T> &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
    #ifdef Q_COMPILER_INITIALIZER_LISTS
        inline QVector(std::initializer_list<T> args);
    #endif
        bool operator==(const QVector<T> &v) const;
        inline bool operator!=(const QVector<T> &v) const { return !(*this == v); }
    
        inline int size() const { return d->size; }
    
        inline bool isEmpty() const { return d->size == 0; }
    
        void resize(int size);
    
        inline int capacity() const { return int(d->alloc); }
        void reserve(int size);
        inline void squeeze()
        {
            reallocData(d->size, d->size);
            if (d->capacityReserved) {
                // capacity reserved in a read only memory would be useless
                // this checks avoid writing to such memory.
                d->capacityReserved = 0;
            }
        }
    
        inline void detach();
        inline bool isDetached() const { return !d->ref.isShared(); }
    #if !defined(QT_NO_UNSHARABLE_CONTAINERS)
        inline void setSharable(bool sharable)
        {
            if (sharable == d->ref.isSharable())
                return;
            if (!sharable)
                detach();
    
            if (d == Data::unsharableEmpty()) {
                if (sharable)
                    d = Data::sharedNull();
            } else {
                d->ref.setSharable(sharable);
            }
            Q_ASSERT(d->ref.isSharable() == sharable);
        }
    #endif
    
        inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
    
        inline T *data() { detach(); return d->begin(); }
        inline const T *data() const { return d->begin(); }
        inline const T *constData() const { return d->begin(); }
        void clear();
    
        const T &at(int i) const;
        T &operator[](int i);
        const T &operator[](int i) const;
        void append(const T &t);
    #if defined(Q_COMPILER_RVALUE_REFS) || defined(Q_CLANG_QDOC)
        void append(T &&t);
    #endif
        inline void append(const QVector<T> &l) { *this += l; }
        void prepend(T &&t);
        void prepend(const T &t);
        void insert(int i, T &&t);
        void insert(int i, const T &t);
        void insert(int i, int n, const T &t);
        void replace(int i, const T &t);
        void remove(int i);
        void remove(int i, int n);
        inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(d->begin()); }
        inline void removeLast();
        T takeFirst() { Q_ASSERT(!isEmpty()); T r = std::move(first()); removeFirst(); return r; }
        T takeLast()  { Q_ASSERT(!isEmpty()); T r = std::move(last()); removeLast(); return r; }
    
        QVector<T> &fill(const T &t, int size = -1);
    
        int indexOf(const T &t, int from = 0) const;
        int lastIndexOf(const T &t, int from = -1) const;
        bool contains(const T &t) const;
        int count(const T &t) const;
    
        // QList compatibility
        void removeAt(int i) { remove(i); }
        int removeAll(const T &t)
        {
            const const_iterator ce = this->cend(), cit = std::find(this->cbegin(), ce, t);
            if (cit == ce)
                return 0;
            // next operation detaches, so ce, cit, t may become invalidated:
            const T tCopy = t;
            const int firstFoundIdx = std::distance(this->cbegin(), cit);
            const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, tCopy);
            const int result = std::distance(it, e);
            erase(it, e);
            return result;
        }
        bool removeOne(const T &t)
        {
            const int i = indexOf(t);
            if (i < 0)
                return false;
            remove(i);
            return true;
        }
        int length() const { return size(); }
        T takeAt(int i) { T t = std::move((*this)[i]); remove(i); return t; }
        void move(int from, int to)
        {
            Q_ASSERT_X(from >= 0 && from < size(), "QVector::move(int,int)", "'from' is out-of-range");
            Q_ASSERT_X(to >= 0 && to < size(), "QVector::move(int,int)", "'to' is out-of-range");
            if (from == to) // don't detach when no-op
                return;
            detach();
            T * const b = d->begin();
            if (from < to)
                std::rotate(b + from, b + from + 1, b + to + 1);
            else
                std::rotate(b + to, b + from, b + from + 1);
        }
    
        // STL-style
        typedef typename Data::iterator iterator;
        typedef typename Data::const_iterator const_iterator;
        typedef std::reverse_iterator<iterator> reverse_iterator;
        typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    #if !defined(QT_STRICT_ITERATORS) || defined(Q_CLANG_QDOC)
        inline iterator begin() { detach(); return d->begin(); }
        inline const_iterator begin() const Q_DECL_NOTHROW { return d->constBegin(); }
        inline const_iterator cbegin() const Q_DECL_NOTHROW { return d->constBegin(); }
        inline const_iterator constBegin() const Q_DECL_NOTHROW { return d->constBegin(); }
        inline iterator end() { detach(); return d->end(); }
        inline const_iterator end() const Q_DECL_NOTHROW { return d->constEnd(); }
        inline const_iterator cend() const Q_DECL_NOTHROW { return d->constEnd(); }
        inline const_iterator constEnd() const Q_DECL_NOTHROW { return d->constEnd(); }
    #else
        inline iterator begin(iterator = iterator()) { detach(); return d->begin(); }
        inline const_iterator begin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
        inline const_iterator cbegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
        inline const_iterator constBegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
        inline iterator end(iterator = iterator()) { detach(); return d->end(); }
        inline const_iterator end(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constEnd(); }
        inline const_iterator cend(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constEnd(); }
        inline const_iterator constEnd(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constEnd(); }
    #endif
        reverse_iterator rbegin() { return reverse_iterator(end()); }
        reverse_iterator rend() { return reverse_iterator(begin()); }
        const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); }
        const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); }
        const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); }
        const_reverse_iterator crend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); }
        iterator insert(iterator before, int n, const T &x);
        inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
        inline iterator insert(iterator before, T &&x);
        iterator erase(iterator begin, iterator end);
        inline iterator erase(iterator pos) { return erase(pos, pos+1); }
    
        // more Qt
        inline int count() const { return d->size; }
        inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
        inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); }
        inline const T &constFirst() const { Q_ASSERT(!isEmpty()); return *begin(); }
        inline T& last() { Q_ASSERT(!isEmpty()); return *(end()-1); }
        inline const T &last() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
        inline const T &constLast() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
        inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
        inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
        QVector<T> mid(int pos, int len = -1) const;
    
        T value(int i) const;
        T value(int i, const T &defaultValue) const;
    
        // STL compatibility
        typedef T value_type;
        typedef value_type* pointer;
        typedef const value_type* const_pointer;
        typedef value_type& reference;
        typedef const value_type& const_reference;
        typedef qptrdiff difference_type;
        typedef iterator Iterator;
        typedef const_iterator ConstIterator;
        typedef int size_type;
        inline void push_back(const T &t) { append(t); }
    #if defined(Q_COMPILER_RVALUE_REFS) || defined(Q_CLANG_QDOC)
        void push_back(T &&t) { append(std::move(t)); }
        void push_front(T &&t) { prepend(std::move(t)); }
    #endif
        inline void push_front(const T &t) { prepend(t); }
        void pop_back() { removeLast(); }
        void pop_front() { removeFirst(); }
        inline bool empty() const
        { return d->size == 0; }
        inline T& front() { return first(); }
        inline const_reference front() const { return first(); }
        inline reference back() { return last(); }
        inline const_reference back() const { return last(); }
        void shrink_to_fit() { squeeze(); }
    
        // comfort
        QVector<T> &operator+=(const QVector<T> &l);
        inline QVector<T> operator+(const QVector<T> &l) const
        { QVector n = *this; n += l; return n; }
        inline QVector<T> &operator+=(const T &t)
        { append(t); return *this; }
        inline QVector<T> &operator<< (const T &t)
        { append(t); return *this; }
        inline QVector<T> &operator<<(const QVector<T> &l)
        { *this += l; return *this; }
        inline QVector<T> &operator+=(T &&t)
        { append(std::move(t)); return *this; }
        inline QVector<T> &operator<<(T &&t)
        { append(std::move(t)); return *this; }
    
        QList<T> toList() const;
    
        static QVector<T> fromList(const QList<T> &list);
    
        static inline QVector<T> fromStdVector(const std::vector<T> &vector)
        { QVector<T> tmp; tmp.reserve(int(vector.size())); std::copy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; }
        inline std::vector<T> toStdVector() const
        { return std::vector<T>(d->begin(), d->end()); }
    private:
        // ### Qt6: remove const from int parameters
        void reallocData(const int size, const int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
        void reallocData(const int sz) { reallocData(sz, d->alloc); }
        void freeData(Data *d);
        void defaultConstruct(T *from, T *to);
        void copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom);
        void destruct(T *from, T *to);
        bool isValidIterator(const iterator &i) const
        {
            const std::less<const T*> less = {};
            return !less(d->end(), i) && !less(i, d->begin());
        }
        class AlignmentDummy { Data header; T array[1]; };
    };
    
    #ifdef Q_CC_MSVC
    // behavior change: an object of POD type constructed with an initializer of the form ()
    // will be default-initialized
    #   pragma warning ( push )
    #   pragma warning ( disable : 4345 )
    #   pragma warning(disable : 4127) // conditional expression is constant
    #endif
    
    template <typename T>
    void QVector<T>::defaultConstruct(T *from, T *to)
    {
        if (QTypeInfo<T>::isComplex) {
            while (from != to) {
                new (from++) T();
            }
        } else {
            ::memset(static_cast<void *>(from), 0, (to - from) * sizeof(T));
        }
    }
    
    template <typename T>
    void QVector<T>::copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom)
    {
        if (QTypeInfo<T>::isComplex) {
            while (srcFrom != srcTo)
                new (dstFrom++) T(*srcFrom++);
        } else {
            ::memcpy(static_cast<void *>(dstFrom), static_cast<const void *>(srcFrom), (srcTo - srcFrom) * sizeof(T));
        }
    }
    
    template <typename T>
    void QVector<T>::destruct(T *from, T *to)
    {
        if (QTypeInfo<T>::isComplex) {
            while (from != to) {
                from++->~T();
            }
        }
    }
    
    template <typename T>
    inline QVector<T>::QVector(const QVector<T> &v)
    {
        if (v.d->ref.ref()) {
            d = v.d;
        } else {
            if (v.d->capacityReserved) {
                d = Data::allocate(v.d->alloc);
                Q_CHECK_PTR(d);
                d->capacityReserved = true;
            } else {
                d = Data::allocate(v.d->size);
                Q_CHECK_PTR(d);
            }
            if (d->alloc) {
                copyConstruct(v.d->begin(), v.d->end(), d->begin());
                d->size = v.d->size;
            }
        }
    }
    
    #if defined(Q_CC_MSVC)
    #pragma warning( pop )
    #endif
    
    template <typename T>
    void QVector<T>::detach()
    {
        if (!isDetached()) {
    #if !defined(QT_NO_UNSHARABLE_CONTAINERS)
            if (!d->alloc)
                d = Data::unsharableEmpty();
            else
    #endif
                reallocData(d->size, int(d->alloc));
        }
        Q_ASSERT(isDetached());
    }
    
    template <typename T>
    void QVector<T>::reserve(int asize)
    {
        if (asize > int(d->alloc))
            reallocData(d->size, asize);
        if (isDetached()
    #if !defined(QT_NO_UNSHARABLE_CONTAINERS)
                && d != Data::unsharableEmpty()
    #endif
                )
            d->capacityReserved = 1;
        Q_ASSERT(capacity() >= asize);
    }
    
    template <typename T>
    void QVector<T>::resize(int asize)
    {
        int newAlloc;
        const int oldAlloc = int(d->alloc);
        QArrayData::AllocationOptions opt;
    
        if (asize > oldAlloc) { // there is not enough space
            newAlloc = asize;
            opt = QArrayData::Grow;
        } else {
            newAlloc = oldAlloc;
        }
        reallocData(asize, newAlloc, opt);
    }
    template <typename T>
    inline void QVector<T>::clear()
    { resize(0); }
    template <typename T>
    inline const T &QVector<T>::at(int i) const
    { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
      return d->begin()[i]; }
    template <typename T>
    inline const T &QVector<T>::operator[](int i) const
    { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
      return d->begin()[i]; }
    template <typename T>
    inline T &QVector<T>::operator[](int i)
    { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
      return data()[i]; }
    template <typename T>
    inline void QVector<T>::insert(int i, const T &t)
    { Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
      insert(begin() + i, 1, t); }
    template <typename T>
    inline void QVector<T>::insert(int i, int n, const T &t)
    { Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
      insert(begin() + i, n, t); }
    template <typename T>
    inline void QVector<T>::insert(int i, T &&t)
    { Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
      insert(begin() + i, std::move(t)); }
    template <typename T>
    inline void QVector<T>::remove(int i, int n)
    { Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= d->size, "QVector<T>::remove", "index out of range");
      erase(d->begin() + i, d->begin() + i + n); }
    template <typename T>
    inline void QVector<T>::remove(int i)
    { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::remove", "index out of range");
      erase(d->begin() + i, d->begin() + i + 1); }
    template <typename T>
    inline void QVector<T>::prepend(const T &t)
    { insert(begin(), 1, t); }
    template <typename T>
    inline void QVector<T>::prepend(T &&t)
    { insert(begin(), std::move(t)); }
    
    template <typename T>
    inline void QVector<T>::replace(int i, const T &t)
    {
        Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::replace", "index out of range");
        const T copy(t);
        data()[i] = copy;
    }
    
    template <typename T>
    QVector<T> &QVector<T>::operator=(const QVector<T> &v)
    {
        if (v.d != d) {
            QVector<T> tmp(v);
            tmp.swap(*this);
        }
        return *this;
    }
    
    template <typename T>
    QVector<T>::QVector(int asize)
    {
        Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
        if (Q_LIKELY(asize > 0)) {
            d = Data::allocate(asize);
            Q_CHECK_PTR(d);
            d->size = asize;
            defaultConstruct(d->begin(), d->end());
        } else {
            d = Data::sharedNull();
        }
    }
    
    template <typename T>
    QVector<T>::QVector(int asize, const T &t)
    {
        Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
        if (asize > 0) {
            d = Data::allocate(asize);
            Q_CHECK_PTR(d);
            d->size = asize;
            T* i = d->end();
            while (i != d->begin())
                new (--i) T(t);
        } else {
            d = Data::sharedNull();
        }
    }
    
    #ifdef Q_COMPILER_INITIALIZER_LISTS
    # if defined(Q_CC_MSVC)
    QT_WARNING_PUSH
    QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
    # endif // Q_CC_MSVC
    
    template <typename T>
    QVector<T>::QVector(std::initializer_list<T> args)
    {
        if (args.size() > 0) {
            d = Data::allocate(args.size());
            Q_CHECK_PTR(d);
            // std::initializer_list<T>::iterator is guaranteed to be
            // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct
            copyConstruct(args.begin(), args.end(), d->begin());
            d->size = int(args.size());
        } else {
            d = Data::sharedNull();
        }
    }
    # if defined(Q_CC_MSVC)
    QT_WARNING_POP
    # endif // Q_CC_MSVC
    #endif // Q_COMPILER_INITALIZER_LISTS
    
    template <typename T>
    void QVector<T>::freeData(Data *x)
    {
        destruct(x->begin(), x->end());
        Data::deallocate(x);
    }
    
    #if defined(Q_CC_MSVC)
    QT_WARNING_PUSH
    QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
    #endif
    
    template <typename T>
    void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::AllocationOptions options)
    {
        Q_ASSERT(asize >= 0 && asize <= aalloc);
        Data *x = d;
    
        const bool isShared = d->ref.isShared();
    
        if (aalloc != 0) {
            if (aalloc != int(d->alloc) || isShared) {
                QT_TRY {
                    // allocate memory
                    x = Data::allocate(aalloc, options);
                    Q_CHECK_PTR(x);
                    // aalloc is bigger then 0 so it is not [un]sharedEmpty
    #if !defined(QT_NO_UNSHARABLE_CONTAINERS)
                    Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable));
    #endif
                    Q_ASSERT(!x->ref.isStatic());
                    x->size = asize;
    
                    T *srcBegin = d->begin();
                    T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
                    T *dst = x->begin();
    
                    if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
                        QT_TRY {
                            if (isShared || !std::is_nothrow_move_constructible<T>::value) {
                                // we can not move the data, we need to copy construct it
                                while (srcBegin != srcEnd)
                                    new (dst++) T(*srcBegin++);
                            } else {
                                while (srcBegin != srcEnd)
                                    new (dst++) T(std::move(*srcBegin++));
                            }
                        } QT_CATCH (...) {
                            // destruct already copied objects
                            destruct(x->begin(), dst);
                            QT_RETHROW;
                        }
                    } else {
                        ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
                        dst += srcEnd - srcBegin;
    
                        // destruct unused / not moved data
                        if (asize < d->size)
                            destruct(d->begin() + asize, d->end());
                    }
    
                    if (asize > d->size) {
                        // construct all new objects when growing
                        if (!QTypeInfo<T>::isComplex) {
                            ::memset(static_cast<void *>(dst), 0, (static_cast<T *>(x->end()) - dst) * sizeof(T));
                        } else {
                            QT_TRY {
                                while (dst != x->end())
                                    new (dst++) T();
                            } QT_CATCH (...) {
                                // destruct already copied objects
                                destruct(x->begin(), dst);
                                QT_RETHROW;
                            }
                        }
                    }
                } QT_CATCH (...) {
                    Data::deallocate(x);
                    QT_RETHROW;
                }
                x->capacityReserved = d->capacityReserved;
            } else {
                Q_ASSERT(int(d->alloc) == aalloc); // resize, without changing allocation size
                Q_ASSERT(isDetached());       // can be done only on detached d
                Q_ASSERT(x == d);             // in this case we do not need to allocate anything
                if (asize <= d->size) {
                    destruct(x->begin() + asize, x->end()); // from future end to current end
                } else {
                    defaultConstruct(x->end(), x->begin() + asize); // from current end to future end
                }
                x->size = asize;
            }
        } else {
            x = Data::sharedNull();
        }
        if (d != x) {
            if (!d->ref.deref()) {
                if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
                    // data was copy constructed, we need to call destructors
                    // or if !alloc we did nothing to the old 'd'.
                    freeData(d);
                } else {
                    Data::deallocate(d);
                }
            }
            d = x;
        }
    
        Q_ASSERT(d->data());
        Q_ASSERT(uint(d->size) <= d->alloc);
    #if !defined(QT_NO_UNSHARABLE_CONTAINERS)
        Q_ASSERT(d != Data::unsharableEmpty());
    #endif
        Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull());
        Q_ASSERT(d->alloc >= uint(aalloc));
        Q_ASSERT(d->size == asize);
    }
    
    #if defined(Q_CC_MSVC)
    QT_WARNING_POP
    #endif
    
    template<typename T>
    Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
    {
        if (uint(i) >= uint(d->size)) {
            return T();
        }
        return d->begin()[i];
    }
    template<typename T>
    Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
    {
        return uint(i) >= uint(d->size) ? defaultValue : d->begin()[i];
    }
    
    template <typename T>
    void QVector<T>::append(const T &t)
    {
        const bool isTooSmall = uint(d->size + 1) > d->alloc;
        if (!isDetached() || isTooSmall) {
            T copy(t);
            QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
            reallocData(d->size, isTooSmall ? d->size + 1 : d->alloc, opt);
    
            if (QTypeInfo<T>::isComplex)
                new (d->end()) T(qMove(copy));
            else
                *d->end() = qMove(copy);
    
        } else {
            if (QTypeInfo<T>::isComplex)
                new (d->end()) T(t);
            else
                *d->end() = t;
        }
        ++d->size;
    }
    
    #ifdef Q_COMPILER_RVALUE_REFS
    template <typename T>
    void QVector<T>::append(T &&t)
    {
        const bool isTooSmall = uint(d->size + 1) > d->alloc;
        if (!isDetached() || isTooSmall) {
            QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
            reallocData(d->size, isTooSmall ? d->size + 1 : d->alloc, opt);
        }
    
        new (d->end()) T(std::move(t));
    
        ++d->size;
    }
    #endif
    
    template <typename T>
    void QVector<T>::removeLast()
    {
        Q_ASSERT(!isEmpty());
        Q_ASSERT(d->alloc);
    
        if (!d->ref.isShared()) {
            --d->size;
            if (QTypeInfo<T>::isComplex)
                (d->data() + d->size)->~T();
        } else {
            reallocData(d->size - 1);
        }
    }
    
    template <typename T>
    typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
    {
        Q_ASSERT_X(isValidIterator(before),  "QVector::insert", "The specified iterator argument 'before' is invalid");
    
        const auto offset = std::distance(d->begin(), before);
        if (n != 0) {
            const T copy(t);
            if (!isDetached() || d->size + n > int(d->alloc))
                reallocData(d->size, d->size + n, QArrayData::Grow);
            if (!QTypeInfoQuery<T>::isRelocatable) {
                T *b = d->end();
                T *i = d->end() + n;
                while (i != b)
                    new (--i) T;
                i = d->end();
                T *j = i + n;
                b = d->begin() + offset;
                while (i != b)
                    *--j = *--i;
                i = b+n;
                while (i != b)
                    *--i = copy;
            } else {
                T *b = d->begin() + offset;
                T *i = b + n;
                memmove(static_cast<void *>(i), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
                while (i != b)
                    new (--i) T(copy);
            }
            d->size += n;
        }
        return d->begin() + offset;
    }
    
    template <typename T>
    typename QVector<T>::iterator QVector<T>::insert(iterator before, T &&t)
    {
        Q_ASSERT_X(isValidIterator(before),  "QVector::insert", "The specified iterator argument 'before' is invalid");
    
        const auto offset = std::distance(d->begin(), before);
        if (!isDetached() || d->size + 1 > int(d->alloc))
            reallocData(d->size, d->size + 1, QArrayData::Grow);
        if (!QTypeInfoQuery<T>::isRelocatable) {
            T *i = d->end();
            T *j = i + 1;
            T *b = d->begin() + offset;
            // The new end-element needs to be constructed, the rest must be move assigned
            if (i != b) {
                new (--j) T(std::move(*--i));
                while (i != b)
                    *--j = std::move(*--i);
                *b = std::move(t);
            } else {
                new (b) T(std::move(t));
            }
        } else {
            T *b = d->begin() + offset;
            memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
            new (b) T(std::move(t));
        }
        d->size += 1;
        return d->begin() + offset;
    }
    
    template <typename T>
    typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
    {
        Q_ASSERT_X(isValidIterator(abegin), "QVector::erase", "The specified iterator argument 'abegin' is invalid");
        Q_ASSERT_X(isValidIterator(aend), "QVector::erase", "The specified iterator argument 'aend' is invalid");
    
        const auto itemsToErase = aend - abegin;
    
        if (!itemsToErase)
            return abegin;
    
        Q_ASSERT(abegin >= d->begin());
        Q_ASSERT(aend <= d->end());
        Q_ASSERT(abegin <= aend);
    
        const auto itemsUntouched = abegin - d->begin();
    
        // FIXME we could do a proper realloc, which copy constructs only needed data.
        // FIXME we are about to delete data - maybe it is good time to shrink?
        // FIXME the shrink is also an issue in removeLast, that is just a copy + reduce of this.
        if (d->alloc) {
            detach();
            abegin = d->begin() + itemsUntouched;
            aend = abegin + itemsToErase;
            if (!QTypeInfoQuery<T>::isRelocatable) {
                iterator moveBegin = abegin + itemsToErase;
                iterator moveEnd = d->end();
                while (moveBegin != moveEnd) {
                    if (QTypeInfo<T>::isComplex)
                        static_cast<T *>(abegin)->~T();
                    new (abegin++) T(*moveBegin++);
                }
                if (abegin < d->end()) {
                    // destroy rest of instances
                    destruct(abegin, d->end());
                }
            } else {
                destruct(abegin, aend);
                // QTBUG-53605: static_cast<void *> masks clang errors of the form
                // error: destination for this 'memmove' call is a pointer to class containing a dynamic class
                // FIXME maybe use std::is_polymorphic (as soon as allowed) to avoid the memmove
                memmove(static_cast<void *>(abegin), static_cast<void *>(aend),
                        (d->size - itemsToErase - itemsUntouched) * sizeof(T));
            }
            d->size -= int(itemsToErase);
        }
        return d->begin() + itemsUntouched;
    }
    
    template <typename T>
    bool QVector<T>::operator==(const QVector<T> &v) const
    {
        if (d == v.d)
            return true;
        if (d->size != v.d->size)
            return false;
        const T *vb = v.d->begin();
        const T *b  = d->begin();
        const T *e  = d->end();
        return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(vb, v.d->size));
    }
    
    template <typename T>
    QVector<T> &QVector<T>::fill(const T &from, int asize)
    {
        const T copy(from);
        resize(asize < 0 ? d->size : asize);
        if (d->size) {
            T *i = d->end();
            T *b = d->begin();
            while (i != b)
                *--i = copy;
        }
        return *this;
    }
    
    template <typename T>
    QVector<T> &QVector<T>::operator+=(const QVector &l)
    {
        if (d == Data::sharedNull()) {
            *this = l;
        } else {
            uint newSize = d->size + l.d->size;
            const bool isTooSmall = newSize > d->alloc;
            if (!isDetached() || isTooSmall) {
                QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
                reallocData(d->size, isTooSmall ? newSize : d->alloc, opt);
            }
    
            if (d->alloc) {
                T *w = d->begin() + newSize;
                T *i = l.d->end();
                T *b = l.d->begin();
                while (i != b) {
                    if (QTypeInfo<T>::isComplex)
                        new (--w) T(*--i);
                    else
                        *--w = *--i;
                }
                d->size = newSize;
            }
        }
        return *this;
    }
    
    template <typename T>
    int QVector<T>::indexOf(const T &t, int from) const
    {
        if (from < 0)
            from = qMax(from + d->size, 0);
        if (from < d->size) {
            T* n = d->begin() + from - 1;
            T* e = d->end();
            while (++n != e)
                if (*n == t)
                    return n - d->begin();
        }
        return -1;
    }
    
    template <typename T>
    int QVector<T>::lastIndexOf(const T &t, int from) const
    {
        if (from < 0)
            from += d->size;
        else if (from >= d->size)
            from = d->size-1;
        if (from >= 0) {
            T* b = d->begin();
            T* n = d->begin() + from + 1;
            while (n != b) {
                if (*--n == t)
                    return n - b;
            }
        }
        return -1;
    }
    
    template <typename T>
    bool QVector<T>::contains(const T &t) const
    {
        const T *b = d->begin();
        const T *e = d->end();
        return std::find(b, e, t) != e;
    }
    
    template <typename T>
    int QVector<T>::count(const T &t) const
    {
        const T *b = d->begin();
        const T *e = d->end();
        return int(std::count(b, e, t));
    }
    
    template <typename T>
    Q_OUTOFLINE_TEMPLATE QVector<T> QVector<T>::mid(int pos, int len) const
    {
        using namespace QtPrivate;
        switch (QContainerImplHelper::mid(d->size, &pos, &len)) {
        case QContainerImplHelper::Null:
        case QContainerImplHelper::Empty:
            return QVector<T>();
        case QContainerImplHelper::Full:
            return *this;
        case QContainerImplHelper::Subset:
            break;
        }
    
        QVector<T> midResult;
        midResult.reallocData(0, len);
        T *srcFrom = d->begin() + pos;
        T *srcTo = d->begin() + pos + len;
        midResult.copyConstruct(srcFrom, srcTo, midResult.data());
        midResult.d->size = len;
        return midResult;
    }
    
    template <typename T>
    Q_OUTOFLINE_TEMPLATE QList<T> QVector<T>::toList() const
    {
        QList<T> result;
        result.reserve(size());
        for (int i = 0; i < size(); ++i)
            result.append(at(i));
        return result;
    }
    
    template <typename T>
    Q_OUTOFLINE_TEMPLATE QVector<T> QList<T>::toVector() const
    {
        QVector<T> result(size());
        for (int i = 0; i < size(); ++i)
            result[i] = at(i);
        return result;
    }
    
    template <typename T>
    QVector<T> QVector<T>::fromList(const QList<T> &list)
    {
        return list.toVector();
    }
    
    template <typename T>
    QList<T> QList<T>::fromVector(const QVector<T> &vector)
    {
        return vector.toList();
    }
    
    Q_DECLARE_SEQUENTIAL_ITERATOR(Vector)
    Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Vector)
    
    template <typename T>
    uint qHash(const QVector<T> &key, uint seed = 0)
        Q_DECL_NOEXCEPT_EXPR(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
    {
        return qHashRange(key.cbegin(), key.cend(), seed);
    }
    
    template <typename T>
    bool operator<(const QVector<T> &lhs, const QVector<T> &rhs)
        Q_DECL_NOEXCEPT_EXPR(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
                                                                   rhs.begin(), rhs.end())))
    {
        return std::lexicographical_compare(lhs.begin(), lhs.end(),
                                            rhs.begin(), rhs.end());
    }
    
    template <typename T>
    inline bool operator>(const QVector<T> &lhs, const QVector<T> &rhs)
        Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs))
    {
        return rhs < lhs;
    }
    
    template <typename T>
    inline bool operator<=(const QVector<T> &lhs, const QVector<T> &rhs)
        Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs))
    {
        return !(lhs > rhs);
    }
    
    template <typename T>
    inline bool operator>=(const QVector<T> &lhs, const QVector<T> &rhs)
        Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs))
    {
        return !(lhs < rhs);
    }
    
    /*
       ### Qt 5:
       ### This needs to be removed for next releases of Qt. It is a workaround for vc++ because
       ### Qt exports QPolygon and QPolygonF that inherit QVector<QPoint> and
       ### QVector<QPointF> respectively.
    */
    
    #ifdef Q_CC_MSVC
    QT_BEGIN_INCLUDE_NAMESPACE
    #include <QtCore/qpoint.h>
    QT_END_INCLUDE_NAMESPACE
    
    #ifndef Q_TEMPLATE_EXTERN
    #if defined(QT_BUILD_CORE_LIB)
    #define Q_TEMPLATE_EXTERN
    #else
    #define Q_TEMPLATE_EXTERN extern
    #endif
    #endif
    Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPointF>;
    Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPoint>;
    #endif
    
    QVector<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*this); }
    
    QT_END_NAMESPACE
    
    #endif // QVECTOR_H

    #########################

    QQ 3087438119
  • 相关阅读:
    OpenWrt(LEDE)2020.4.29更新 UPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成+软件包
    OpenWrt(LEDE)2020.4.12编译 UnPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成
    软路由OpenWrt(LEDE)2020.4.6编译 UnPnP+NAS+多拨+网盘+DNS优化
    软路由OpenWrt(LEDE)2020.4.4编译 UnPnP+NAS+多拨+网盘+DNS优化
    【x64软路由】OpenWrt(LEDE) 20200329编译 反追踪 抗污染 加速 PSW 无缝集成 UPnP NAS
    OpenWrt R2020.3.19 反追踪 抗污染 加速 PSW 无缝集成 UnPnP NAS
    Go语言进阶学习笔记
    go语言基础学习笔记
    深入剖析PHP7内核源码(二)- PHP变量容器
    深入剖析PHP7内核源码(一)- PHP架构与生命周期
  • 原文地址:https://www.cnblogs.com/herd/p/15468850.html
Copyright © 2020-2023  润新知