mirror of
https://github.com/Gator96100/ProxSpace.git
synced 2025-07-16 02:03:02 -07:00
978 lines
31 KiB
C++
978 lines
31 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the QtCore module of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
|
** 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 http://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at http://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 2.1 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** $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
|
|
|
|
class QRegion;
|
|
|
|
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);
|
|
#ifdef Q_COMPILER_RVALUE_REFS
|
|
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);
|
|
#ifdef Q_COMPILER_RVALUE_REFS
|
|
void append(T &&t);
|
|
#endif
|
|
inline void append(const QVector<T> &l) { *this += l; }
|
|
void prepend(const 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();
|
|
inline T takeFirst() { Q_ASSERT(!isEmpty()); T r = first(); removeFirst(); return r; }
|
|
inline T takeLast() { Q_ASSERT(!isEmpty()); T r = 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 may become invalidated:
|
|
const int firstFoundIdx = std::distance(this->cbegin(), cit);
|
|
const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, t);
|
|
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 = at(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_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); }
|
|
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); }
|
|
#ifdef Q_COMPILER_RVALUE_REFS
|
|
void push_back(T &&t) { append(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(); }
|
|
|
|
// 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; }
|
|
|
|
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:
|
|
friend class QRegion; // Optimization for QRegion::rects()
|
|
|
|
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
|
|
{
|
|
return (i <= d->end()) && (d->begin() <= i);
|
|
}
|
|
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 )
|
|
#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));
|
|
}
|
|
}
|
|
|
|
#ifdef Q_CC_MSVC
|
|
# pragma warning ( pop )
|
|
#endif
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
#if defined(Q_CC_MSVC)
|
|
#pragma warning( push )
|
|
#pragma warning( disable : 4127 ) // conditional expression is constant
|
|
#endif
|
|
|
|
template <typename T>
|
|
void QVector<T>::destruct(T *from, T *to)
|
|
{
|
|
if (QTypeInfo<T>::isComplex) {
|
|
while (from != to) {
|
|
from++->~T();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(Q_CC_MSVC)
|
|
#pragma warning( pop )
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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())
|
|
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()
|
|
{ *this = QVector<T>(); }
|
|
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>::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>::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
|
|
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();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template <typename T>
|
|
void QVector<T>::freeData(Data *x)
|
|
{
|
|
destruct(x->begin(), x->end());
|
|
Data::deallocate(x);
|
|
}
|
|
|
|
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 (QTypeInfo<T>::isStatic || (isShared && QTypeInfo<T>::isComplex)) {
|
|
// we can not move the data, we need to copy construct it
|
|
while (srcBegin != srcEnd) {
|
|
new (dst++) T(*srcBegin++);
|
|
}
|
|
} 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
|
|
QT_TRY {
|
|
defaultConstruct(dst, x->end());
|
|
} 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 (QTypeInfo<T>::isStatic || !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);
|
|
}
|
|
|
|
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");
|
|
|
|
int 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 (QTypeInfo<T>::isStatic) {
|
|
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(i, 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>::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 int itemsToErase = aend - abegin;
|
|
|
|
if (!itemsToErase)
|
|
return abegin;
|
|
|
|
Q_ASSERT(abegin >= d->begin());
|
|
Q_ASSERT(aend <= d->end());
|
|
Q_ASSERT(abegin <= aend);
|
|
|
|
const int itemsUntouched = abegin - d->begin();
|
|
|
|
// FIXME we could do a proper realloc, which copy constructs only needed data.
|
|
// FIXME we ara 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 (QTypeInfo<T>::isStatic) {
|
|
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);
|
|
memmove(abegin, aend, (d->size - itemsToErase - itemsUntouched) * sizeof(T));
|
|
}
|
|
d->size -= 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)
|
|
{
|
|
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
|
|
|
|
#if defined(QT_BUILD_CORE_LIB)
|
|
#define Q_TEMPLATE_EXTERN
|
|
#else
|
|
#define Q_TEMPLATE_EXTERN extern
|
|
#endif
|
|
Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPointF>;
|
|
Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPoint>;
|
|
#endif
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
#endif // QVECTOR_H
|