diff options
Diffstat (limited to 'src/corelib/tools/qvector.h')
-rw-r--r-- | src/corelib/tools/qvector.h | 1145 |
1 files changed, 11 insertions, 1134 deletions
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 5def2eceb2..4fad2bce8f 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -1,1150 +1,27 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QVECTOR_H #define QVECTOR_H -#include <QtCore/qalgorithms.h> -#include <QtCore/qiterator.h> -#include <QtCore/qrefcount.h> -#include <QtCore/qarraydata.h> -#include <QtCore/qhashfunctions.h> -#include <QtCore/qcontainertools_impl.h> +#include <QtCore/qlist.h> +#include <QtCore/qcontainerfwd.h> -#include <iterator> -#include <initializer_list> -#if QT_VERSION < QT_VERSION_CHECK(6,0,0) -#include <vector> +#if 0 +#pragma qt_class(QVector) +#pragma qt_class(QMutableVectorIterator) +#pragma qt_class(QVectorIterator) #endif -#include <stdlib.h> -#include <string.h> - -#include <algorithm> QT_BEGIN_NAMESPACE -namespace QtPrivate { - template <typename V, typename U> int indexOf(const QVector<V> &list, const U &u, int from); - template <typename V, typename U> int lastIndexOf(const QVector<V> &list, const U &u, int from); -} - -template <typename T> struct QVectorSpecialMethods -{ -protected: - ~QVectorSpecialMethods() = default; -}; -template <> struct QVectorSpecialMethods<QByteArray>; -template <> struct QVectorSpecialMethods<QString>; - -template <typename T> -class QVector -#ifndef Q_QDOC - : public QVectorSpecialMethods<T> -#endif -{ - typedef QTypedArrayData<T> Data; - Data *d; - - template <typename V, typename U> friend int QtPrivate::indexOf(const QVector<V> &list, const U &u, int from); - template <typename V, typename U> friend int QtPrivate::lastIndexOf(const QVector<V> &list, const U &u, int from); - -public: - inline QVector() noexcept : 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); - QVector(QVector<T> &&other) noexcept : d(other.d) { other.d = Data::sharedNull(); } - QVector<T> &operator=(QVector<T> &&other) noexcept - { QVector moved(std::move(other)); swap(moved); return *this; } - void swap(QVector<T> &other) noexcept { qSwap(d, other.d); } - inline QVector(std::initializer_list<T> args); - QVector<T> &operator=(std::initializer_list<T> args); - template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true> - inline QVector(InputIterator first, InputIterator last); - explicit QVector(QArrayDataPointerRef<T> ref) noexcept : d(ref.ptr) {} - - 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() - { - if (d->size < int(d->alloc)) { - if (!d->size) { - *this = QVector<T>(); - return; - } - realloc(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(); } - - 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); - void append(T &&t); - 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; - inline iterator begin() { detach(); return d->begin(); } - inline const_iterator begin() const noexcept { return d->constBegin(); } - inline const_iterator cbegin() const noexcept { return d->constBegin(); } - inline const_iterator constBegin() const noexcept { return d->constBegin(); } - inline iterator end() { detach(); return d->end(); } - inline const_iterator end() const noexcept { return d->constEnd(); } - inline const_iterator cend() const noexcept { return d->constEnd(); } - inline const_iterator constEnd() const noexcept { return d->constEnd(); } - reverse_iterator rbegin() { return reverse_iterator(end()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } - const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } - const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } - const_reverse_iterator crend() const noexcept { 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; - - void swapItemsAt(int i, int j) { - Q_ASSERT_X(i >= 0 && i < size() && j >= 0 && j < size(), - "QVector<T>::swap", "index out of range"); - detach(); - qSwap(d->begin()[i], d->begin()[j]); - } - - // 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); } - void push_back(T &&t) { append(std::move(t)); } - void push_front(T &&t) { prepend(std::move(t)); } - 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; } - -#if QT_VERSION < QT_VERSION_CHECK(6,0,0) - Q_DECL_DEPRECATED_X("Use QVector<T>(vector.begin(), vector.end()) instead.") - static inline QVector<T> fromStdVector(const std::vector<T> &vector) - { return QVector<T>(vector.begin(), vector.end()); } - Q_DECL_DEPRECATED_X("Use std::vector<T>(vector.begin(), vector.end()) instead.") - inline std::vector<T> toStdVector() const - { return std::vector<T>(d->begin(), d->end()); } -#endif - - // Consider deprecating in 6.4 or later - static QVector<T> fromList(const QVector<T> &list) { return list; } - QVector<T> toList() const { return *this; } - - static inline QVector<T> fromVector(const QVector<T> &vector) { return vector; } - inline QVector<T> toVector() const { return *this; } - -private: - // ### Qt6: remove methods, they are unused - void reallocData(const int size, const int alloc, QArrayData::AllocationOptions options = QArrayData::Default); - void reallocData(const int sz) { reallocData(sz, d->alloc); } - void realloc(int alloc, QArrayData::AllocationOptions options = QArrayData::Default); - 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]; }; -}; - -#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606 -template <typename InputIterator, - typename ValueType = typename std::iterator_traits<InputIterator>::value_type, - QtPrivate::IfIsInputIterator<InputIterator> = true> -QVector(InputIterator, InputIterator) -> QVector<ValueType>; -#endif - -#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 (d->ref.isStatic()) - return; - - if (!isDetached()) - realloc(int(d->alloc)); - Q_ASSERT(isDetached()); -} - -template <typename T> -void QVector<T>::reserve(int asize) -{ - if (asize > int(d->alloc)) - realloc(asize); - if (isDetached()) - d->capacityReserved = 1; - Q_ASSERT(capacity() >= asize); -} - -template <typename T> -void QVector<T>::resize(int asize) -{ - if (asize == d->size) - return detach(); - if (asize > int(d->alloc) || !isDetached()) { // there is not enough space - QArrayData::AllocationOptions opt = asize > int(d->alloc) ? QArrayData::Grow : QArrayData::Default; - realloc(qMax(int(d->alloc), asize), opt); - } - if (asize < d->size) - destruct(begin() + asize, end()); - else - defaultConstruct(end(), begin() + asize); - d->size = asize; -} -template <typename T> -inline void QVector<T>::clear() -{ - if (!d->size) - return; - destruct(begin(), end()); - d->size = 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(); - } -} - -#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(); - } -} - -template <typename T> -QVector<T> &QVector<T>::operator=(std::initializer_list<T> args) -{ - QVector<T> tmp(args); - tmp.swap(*this); - return *this; -} - -#if defined(Q_CC_MSVC) -QT_WARNING_POP -#endif // Q_CC_MSVC - -template <typename T> -template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator>> -QVector<T>::QVector(InputIterator first, InputIterator last) - : QVector() -{ - QtPrivate::reserveIfForwardIterator(this, first, last); - std::copy(first, last, std::back_inserter(*this)); -} - -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 - 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); - Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull()); - Q_ASSERT(d->alloc >= uint(aalloc)); - Q_ASSERT(d->size == asize); -} - -template<typename T> -void QVector<T>::realloc(int aalloc, QArrayData::AllocationOptions options) -{ - Q_ASSERT(aalloc >= d->size); - Data *x = d; - - const bool isShared = d->ref.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 - Q_ASSERT(!x->ref.isStatic()); - x->size = d->size; - - T *srcBegin = d->begin(); - T *srcEnd = d->end(); - 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; - } - - } QT_CATCH (...) { - Data::deallocate(x); - QT_RETHROW; - } - x->capacityReserved = d->capacityReserved; - - Q_ASSERT(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); - Q_ASSERT(d != Data::sharedNull()); - Q_ASSERT(d->alloc >= uint(aalloc)); -} - -#if defined(Q_CC_MSVC) -QT_WARNING_POP -#endif - +#if !defined(QT_NO_JAVA_STYLE_ITERATORS) 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]; -} +using QMutableVectorIterator = QMutableListIterator<T>; 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); - realloc(isTooSmall ? d->size + 1 : d->alloc, opt); - - if (QTypeInfo<T>::isComplex) - new (d->end()) T(std::move(copy)); - else - *d->end() = std::move(copy); - - } else { - if (QTypeInfo<T>::isComplex) - new (d->end()) T(t); - else - *d->end() = t; - } - ++d->size; -} - -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); - realloc(isTooSmall ? d->size + 1 : d->alloc, opt); - } - - new (d->end()) T(std::move(t)); - - ++d->size; -} - -template <typename T> -void QVector<T>::removeLast() -{ - Q_ASSERT(!isEmpty()); - Q_ASSERT(d->alloc); - - if (d->ref.isShared()) - detach(); - --d->size; - if (QTypeInfo<T>::isComplex) - (d->data() + d->size)->~T(); -} - -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)) - realloc(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)) - realloc(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->size == 0) { - *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); - realloc(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; -} - -namespace QtPrivate { -template <typename T, typename U> -int indexOf(const QVector<T> &vector, const U &u, int from) -{ - if (from < 0) - from = qMax(from + vector.size(), 0); - if (from < vector.size()) { - auto n = vector.begin() + from - 1; - auto e = vector.end(); - while (++n != e) - if (*n == u) - return n - vector.begin(); - } - return -1; -} - -template <typename T, typename U> -int lastIndexOf(const QVector<T> &vector, const U &u, int from) -{ - if (from < 0) - from += vector.d->size; - else if (from >= vector.size()) - from = vector.size() - 1; - if (from >= 0) { - auto b = vector.begin(); - auto n = vector.begin() + from + 1; - while (n != b) { - if (*--n == u) - return n - b; - } - } - return -1; -} -} - -template <typename T> -int QVector<T>::indexOf(const T &t, int from) const -{ - return QtPrivate::indexOf<T, T>(*this, t, from); -} - -template <typename T> -int QVector<T>::lastIndexOf(const T &t, int from) const -{ - return QtPrivate::lastIndexOf(*this, t, from); -} - -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.realloc(len); - T *srcFrom = d->begin() + pos; - T *srcTo = d->begin() + pos + len; - midResult.copyConstruct(srcFrom, srcTo, midResult.data()); - midResult.d->size = len; - return midResult; -} - -Q_DECLARE_SEQUENTIAL_ITERATOR(Vector) -Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Vector) - -template <typename T> -uint qHash(const QVector<T> &key, uint seed = 0) - noexcept(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) - noexcept(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) - noexcept(noexcept(lhs < rhs)) -{ - return rhs < lhs; -} - -template <typename T> -inline bool operator<=(const QVector<T> &lhs, const QVector<T> &rhs) - noexcept(noexcept(lhs < rhs)) -{ - return !(lhs > rhs); -} - -template <typename T> -inline bool operator>=(const QVector<T> &lhs, const QVector<T> &rhs) - noexcept(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. -*/ - -#if defined(Q_CC_MSVC) && !defined(QT_BUILD_CORE_LIB) -QT_BEGIN_INCLUDE_NAMESPACE -#include <QtCore/qpoint.h> -QT_END_INCLUDE_NAMESPACE -extern template class Q_CORE_EXPORT QVector<QPointF>; -extern template class Q_CORE_EXPORT QVector<QPoint>; +using QVectorIterator = QListIterator<T>; #endif -QVector<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*this); } - -QVector<QStringRef> QString::splitRef(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const -{ return splitRef(sep, _sb(behavior), cs); } -QVector<QStringRef> QString::splitRef(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const -{ return splitRef(sep, _sb(behavior), cs); } -#ifndef QT_NO_REGEXP -QVector<QStringRef> QString::splitRef(const QRegExp &sep, Qt::SplitBehavior behavior) const -{ return splitRef(sep, _sb(behavior)); } -#endif -#if QT_CONFIG(regularexpression) -QVector<QStringRef> QString::splitRef(const QRegularExpression &sep, Qt::SplitBehavior behavior) const -{ return splitRef(sep, _sb(behavior)); } -#endif -QVector<QStringRef> QStringRef::split(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const -{ return split(sep, QString::_sb(behavior), cs); } -QVector<QStringRef> QStringRef::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const -{ return split(sep, QString::_sb(behavior), cs); } - - QT_END_NAMESPACE -#include <QtCore/qbytearraylist.h> -#include <QtCore/qstringlist.h> - #endif // QVECTOR_H |