1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QVECTOR_H
41#define QVECTOR_H
42
43#include <QtCore/qalgorithms.h>
44#include <QtCore/qiterator.h>
45#include <QtCore/qrefcount.h>
46#include <QtCore/qarraydata.h>
47#include <QtCore/qhashfunctions.h>
48
49#include <iterator>
50#include <vector>
51#include <stdlib.h>
52#include <string.h>
53#ifdef Q_COMPILER_INITIALIZER_LISTS
54#include <initializer_list>
55#endif
56
57#include <algorithm>
58
59QT_BEGIN_NAMESPACE
60
61template <typename T>
62class QVector
63{
64 typedef QTypedArrayData<T> Data;
65 Data *d;
66
67public:
68 inline QVector() Q_DECL_NOTHROW : d(Data::sharedNull()) { }
69 explicit QVector(int size);
70 QVector(int size, const T &t);
71 inline QVector(const QVector<T> &v);
72 inline ~QVector() { if (!d->ref.deref()) freeData(d); }
73 QVector<T> &operator=(const QVector<T> &v);
74#if defined(Q_COMPILER_RVALUE_REFS) || defined(Q_CLANG_QDOC)
75 QVector(QVector<T> &&other) Q_DECL_NOTHROW : d(other.d) { other.d = Data::sharedNull(); }
76 QVector<T> &operator=(QVector<T> &&other) Q_DECL_NOTHROW
77 { QVector moved(std::move(other)); swap(moved); return *this; }
78#endif
79 void swap(QVector<T> &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
80#ifdef Q_COMPILER_INITIALIZER_LISTS
81 inline QVector(std::initializer_list<T> args);
82#endif
83 bool operator==(const QVector<T> &v) const;
84 inline bool operator!=(const QVector<T> &v) const { return !(*this == v); }
85
86 inline int size() const { return d->size; }
87
88 inline bool isEmpty() const { return d->size == 0; }
89
90 void resize(int size);
91
92 inline int capacity() const { return int(d->alloc); }
93 void reserve(int size);
94 inline void squeeze()
95 {
96 if (d->size < int(d->alloc)) {
97 if (!d->size) {
98 *this = QVector<T>();
99 return;
100 }
101 realloc(d->size);
102 }
103 if (d->capacityReserved) {
104 // capacity reserved in a read only memory would be useless
105 // this checks avoid writing to such memory.
106 d->capacityReserved = 0;
107 }
108 }
109
110 inline void detach();
111 inline bool isDetached() const { return !d->ref.isShared(); }
112#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
113 inline void setSharable(bool sharable)
114 {
115 if (sharable == d->ref.isSharable())
116 return;
117 if (!sharable)
118 detach();
119
120 if (d == Data::unsharableEmpty()) {
121 if (sharable)
122 d = Data::sharedNull();
123 } else {
124 d->ref.setSharable(sharable);
125 }
126 Q_ASSERT(d->ref.isSharable() == sharable);
127 }
128#endif
129
130 inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
131
132 inline T *data() { detach(); return d->begin(); }
133 inline const T *data() const { return d->begin(); }
134 inline const T *constData() const { return d->begin(); }
135 void clear();
136
137 const T &at(int i) const;
138 T &operator[](int i);
139 const T &operator[](int i) const;
140 void append(const T &t);
141#if defined(Q_COMPILER_RVALUE_REFS) || defined(Q_CLANG_QDOC)
142 void append(T &&t);
143#endif
144 inline void append(const QVector<T> &l) { *this += l; }
145 void prepend(T &&t);
146 void prepend(const T &t);
147 void insert(int i, T &&t);
148 void insert(int i, const T &t);
149 void insert(int i, int n, const T &t);
150 void replace(int i, const T &t);
151 void remove(int i);
152 void remove(int i, int n);
153 inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(d->begin()); }
154 inline void removeLast();
155 T takeFirst() { Q_ASSERT(!isEmpty()); T r = std::move(first()); removeFirst(); return r; }
156 T takeLast() { Q_ASSERT(!isEmpty()); T r = std::move(last()); removeLast(); return r; }
157
158 QVector<T> &fill(const T &t, int size = -1);
159
160 int indexOf(const T &t, int from = 0) const;
161 int lastIndexOf(const T &t, int from = -1) const;
162 bool contains(const T &t) const;
163 int count(const T &t) const;
164
165 // QList compatibility
166 void removeAt(int i) { remove(i); }
167 int removeAll(const T &t)
168 {
169 const const_iterator ce = this->cend(), cit = std::find(this->cbegin(), ce, t);
170 if (cit == ce)
171 return 0;
172 // next operation detaches, so ce, cit, t may become invalidated:
173 const T tCopy = t;
174 const int firstFoundIdx = std::distance(this->cbegin(), cit);
175 const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, tCopy);
176 const int result = std::distance(it, e);
177 erase(it, e);
178 return result;
179 }
180 bool removeOne(const T &t)
181 {
182 const int i = indexOf(t);
183 if (i < 0)
184 return false;
185 remove(i);
186 return true;
187 }
188 int length() const { return size(); }
189 T takeAt(int i) { T t = std::move((*this)[i]); remove(i); return t; }
190 void move(int from, int to)
191 {
192 Q_ASSERT_X(from >= 0 && from < size(), "QVector::move(int,int)", "'from' is out-of-range");
193 Q_ASSERT_X(to >= 0 && to < size(), "QVector::move(int,int)", "'to' is out-of-range");
194 if (from == to) // don't detach when no-op
195 return;
196 detach();
197 T * const b = d->begin();
198 if (from < to)
199 std::rotate(b + from, b + from + 1, b + to + 1);
200 else
201 std::rotate(b + to, b + from, b + from + 1);
202 }
203
204 // STL-style
205 typedef typename Data::iterator iterator;
206 typedef typename Data::const_iterator const_iterator;
207 typedef std::reverse_iterator<iterator> reverse_iterator;
208 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
209#if !defined(QT_STRICT_ITERATORS) || defined(Q_CLANG_QDOC)
210 inline iterator begin() { detach(); return d->begin(); }
211 inline const_iterator begin() const Q_DECL_NOTHROW { return d->constBegin(); }
212 inline const_iterator cbegin() const Q_DECL_NOTHROW { return d->constBegin(); }
213 inline const_iterator constBegin() const Q_DECL_NOTHROW { return d->constBegin(); }
214 inline iterator end() { detach(); return d->end(); }
215 inline const_iterator end() const Q_DECL_NOTHROW { return d->constEnd(); }
216 inline const_iterator cend() const Q_DECL_NOTHROW { return d->constEnd(); }
217 inline const_iterator constEnd() const Q_DECL_NOTHROW { return d->constEnd(); }
218#else
219 inline iterator begin(iterator = iterator()) { detach(); return d->begin(); }
220 inline const_iterator begin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
221 inline const_iterator cbegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
222 inline const_iterator constBegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
223 inline iterator end(iterator = iterator()) { detach(); return d->end(); }
224 inline const_iterator end(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constEnd(); }
225 inline const_iterator cend(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constEnd(); }
226 inline const_iterator constEnd(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constEnd(); }
227#endif
228 reverse_iterator rbegin() { return reverse_iterator(end()); }
229 reverse_iterator rend() { return reverse_iterator(begin()); }
230 const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); }
231 const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); }
232 const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); }
233 const_reverse_iterator crend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); }
234 iterator insert(iterator before, int n, const T &x);
235 inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
236 inline iterator insert(iterator before, T &&x);
237 iterator erase(iterator begin, iterator end);
238 inline iterator erase(iterator pos) { return erase(pos, pos+1); }
239
240 // more Qt
241 inline int count() const { return d->size; }
242 inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
243 inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); }
244 inline const T &constFirst() const { Q_ASSERT(!isEmpty()); return *begin(); }
245 inline T& last() { Q_ASSERT(!isEmpty()); return *(end()-1); }
246 inline const T &last() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
247 inline const T &constLast() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
248 inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
249 inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
250 QVector<T> mid(int pos, int len = -1) const;
251
252 T value(int i) const;
253 T value(int i, const T &defaultValue) const;
254
255 // STL compatibility
256 typedef T value_type;
257 typedef value_type* pointer;
258 typedef const value_type* const_pointer;
259 typedef value_type& reference;
260 typedef const value_type& const_reference;
261 typedef qptrdiff difference_type;
262 typedef iterator Iterator;
263 typedef const_iterator ConstIterator;
264 typedef int size_type;
265 inline void push_back(const T &t) { append(t); }
266#if defined(Q_COMPILER_RVALUE_REFS) || defined(Q_CLANG_QDOC)
267 void push_back(T &&t) { append(std::move(t)); }
268 void push_front(T &&t) { prepend(std::move(t)); }
269#endif
270 inline void push_front(const T &t) { prepend(t); }
271 void pop_back() { removeLast(); }
272 void pop_front() { removeFirst(); }
273 inline bool empty() const
274 { return d->size == 0; }
275 inline T& front() { return first(); }
276 inline const_reference front() const { return first(); }
277 inline reference back() { return last(); }
278 inline const_reference back() const { return last(); }
279 void shrink_to_fit() { squeeze(); }
280
281 // comfort
282 QVector<T> &operator+=(const QVector<T> &l);
283 inline QVector<T> operator+(const QVector<T> &l) const
284 { QVector n = *this; n += l; return n; }
285 inline QVector<T> &operator+=(const T &t)
286 { append(t); return *this; }
287 inline QVector<T> &operator<< (const T &t)
288 { append(t); return *this; }
289 inline QVector<T> &operator<<(const QVector<T> &l)
290 { *this += l; return *this; }
291 inline QVector<T> &operator+=(T &&t)
292 { append(std::move(t)); return *this; }
293 inline QVector<T> &operator<<(T &&t)
294 { append(std::move(t)); return *this; }
295
296 QList<T> toList() const;
297
298 static QVector<T> fromList(const QList<T> &list);
299
300 static inline QVector<T> fromStdVector(const std::vector<T> &vector)
301 { QVector<T> tmp; tmp.reserve(int(vector.size())); std::copy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; }
302 inline std::vector<T> toStdVector() const
303 { return std::vector<T>(d->begin(), d->end()); }
304private:
305 // ### Qt6: remove methods, they are unused
306 void reallocData(const int size, const int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
307 void reallocData(const int sz) { reallocData(sz, d->alloc); }
308 void realloc(int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
309 void freeData(Data *d);
310 void defaultConstruct(T *from, T *to);
311 void copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom);
312 void destruct(T *from, T *to);
313 bool isValidIterator(const iterator &i) const
314 {
315 const std::less<const T*> less = {};
316 return !less(d->end(), i) && !less(i, d->begin());
317 }
318 class AlignmentDummy { Data header; T array[1]; };
319};
320
321#ifdef Q_CC_MSVC
322// behavior change: an object of POD type constructed with an initializer of the form ()
323// will be default-initialized
324# pragma warning ( push )
325# pragma warning ( disable : 4345 )
326# pragma warning(disable : 4127) // conditional expression is constant
327#endif
328
329template <typename T>
330void QVector<T>::defaultConstruct(T *from, T *to)
331{
332 if (QTypeInfo<T>::isComplex) {
333 while (from != to) {
334 new (from++) T();
335 }
336 } else {
337 ::memset(static_cast<void *>(from), 0, (to - from) * sizeof(T));
338 }
339}
340
341template <typename T>
342void QVector<T>::copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom)
343{
344 if (QTypeInfo<T>::isComplex) {
345 while (srcFrom != srcTo)
346 new (dstFrom++) T(*srcFrom++);
347 } else {
348 ::memcpy(static_cast<void *>(dstFrom), static_cast<const void *>(srcFrom), (srcTo - srcFrom) * sizeof(T));
349 }
350}
351
352template <typename T>
353void QVector<T>::destruct(T *from, T *to)
354{
355 if (QTypeInfo<T>::isComplex) {
356 while (from != to) {
357 from++->~T();
358 }
359 }
360}
361
362template <typename T>
363inline QVector<T>::QVector(const QVector<T> &v)
364{
365 if (v.d->ref.ref()) {
366 d = v.d;
367 } else {
368 if (v.d->capacityReserved) {
369 d = Data::allocate(v.d->alloc);
370 Q_CHECK_PTR(d);
371 d->capacityReserved = true;
372 } else {
373 d = Data::allocate(v.d->size);
374 Q_CHECK_PTR(d);
375 }
376 if (d->alloc) {
377 copyConstruct(v.d->begin(), v.d->end(), d->begin());
378 d->size = v.d->size;
379 }
380 }
381}
382
383#if defined(Q_CC_MSVC)
384#pragma warning( pop )
385#endif
386
387template <typename T>
388void QVector<T>::detach()
389{
390 if (!isDetached()) {
391#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
392 if (!d->alloc)
393 d = Data::unsharableEmpty();
394 else
395#endif
396 realloc(int(d->alloc));
397 }
398 Q_ASSERT(isDetached());
399}
400
401template <typename T>
402void QVector<T>::reserve(int asize)
403{
404 if (asize > int(d->alloc))
405 realloc(asize);
406 if (isDetached()
407#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
408 && d != Data::unsharableEmpty()
409#endif
410 )
411 d->capacityReserved = 1;
412 Q_ASSERT(capacity() >= asize);
413}
414
415template <typename T>
416void QVector<T>::resize(int asize)
417{
418 if (asize == d->size)
419 return;
420 if (asize > int(d->alloc) || !isDetached()) { // there is not enough space
421 QArrayData::AllocationOptions opt = asize > int(d->alloc) ? QArrayData::Grow : QArrayData::Default;
422 realloc(qMax(int(d->alloc), asize), opt);
423 }
424 if (asize < d->size)
425 destruct(begin() + asize, end());
426 else
427 defaultConstruct(end(), begin() + asize);
428 d->size = asize;
429}
430template <typename T>
431inline void QVector<T>::clear()
432{
433 if (!d->size)
434 return;
435 destruct(begin(), end());
436 d->size = 0;
437}
438template <typename T>
439inline const T &QVector<T>::at(int i) const
440{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
441 return d->begin()[i]; }
442template <typename T>
443inline const T &QVector<T>::operator[](int i) const
444{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
445 return d->begin()[i]; }
446template <typename T>
447inline T &QVector<T>::operator[](int i)
448{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
449 return data()[i]; }
450template <typename T>
451inline void QVector<T>::insert(int i, const T &t)
452{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
453 insert(begin() + i, 1, t); }
454template <typename T>
455inline void QVector<T>::insert(int i, int n, const T &t)
456{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
457 insert(begin() + i, n, t); }
458template <typename T>
459inline void QVector<T>::insert(int i, T &&t)
460{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
461 insert(begin() + i, std::move(t)); }
462template <typename T>
463inline void QVector<T>::remove(int i, int n)
464{ Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= d->size, "QVector<T>::remove", "index out of range");
465 erase(d->begin() + i, d->begin() + i + n); }
466template <typename T>
467inline void QVector<T>::remove(int i)
468{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::remove", "index out of range");
469 erase(d->begin() + i, d->begin() + i + 1); }
470template <typename T>
471inline void QVector<T>::prepend(const T &t)
472{ insert(begin(), 1, t); }
473template <typename T>
474inline void QVector<T>::prepend(T &&t)
475{ insert(begin(), std::move(t)); }
476
477template <typename T>
478inline void QVector<T>::replace(int i, const T &t)
479{
480 Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::replace", "index out of range");
481 const T copy(t);
482 data()[i] = copy;
483}
484
485template <typename T>
486QVector<T> &QVector<T>::operator=(const QVector<T> &v)
487{
488 if (v.d != d) {
489 QVector<T> tmp(v);
490 tmp.swap(*this);
491 }
492 return *this;
493}
494
495template <typename T>
496QVector<T>::QVector(int asize)
497{
498 Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
499 if (Q_LIKELY(asize > 0)) {
500 d = Data::allocate(asize);
501 Q_CHECK_PTR(d);
502 d->size = asize;
503 defaultConstruct(d->begin(), d->end());
504 } else {
505 d = Data::sharedNull();
506 }
507}
508
509template <typename T>
510QVector<T>::QVector(int asize, const T &t)
511{
512 Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
513 if (asize > 0) {
514 d = Data::allocate(asize);
515 Q_CHECK_PTR(d);
516 d->size = asize;
517 T* i = d->end();
518 while (i != d->begin())
519 new (--i) T(t);
520 } else {
521 d = Data::sharedNull();
522 }
523}
524
525#ifdef Q_COMPILER_INITIALIZER_LISTS
526# if defined(Q_CC_MSVC)
527QT_WARNING_PUSH
528QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
529# endif // Q_CC_MSVC
530
531template <typename T>
532QVector<T>::QVector(std::initializer_list<T> args)
533{
534 if (args.size() > 0) {
535 d = Data::allocate(args.size());
536 Q_CHECK_PTR(d);
537 // std::initializer_list<T>::iterator is guaranteed to be
538 // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct
539 copyConstruct(args.begin(), args.end(), d->begin());
540 d->size = int(args.size());
541 } else {
542 d = Data::sharedNull();
543 }
544}
545# if defined(Q_CC_MSVC)
546QT_WARNING_POP
547# endif // Q_CC_MSVC
548#endif // Q_COMPILER_INITALIZER_LISTS
549
550template <typename T>
551void QVector<T>::freeData(Data *x)
552{
553 destruct(x->begin(), x->end());
554 Data::deallocate(x);
555}
556
557#if defined(Q_CC_MSVC)
558QT_WARNING_PUSH
559QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
560#endif
561
562template <typename T>
563void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::AllocationOptions options)
564{
565 Q_ASSERT(asize >= 0 && asize <= aalloc);
566 Data *x = d;
567
568 const bool isShared = d->ref.isShared();
569
570 if (aalloc != 0) {
571 if (aalloc != int(d->alloc) || isShared) {
572 QT_TRY {
573 // allocate memory
574 x = Data::allocate(aalloc, options);
575 Q_CHECK_PTR(x);
576 // aalloc is bigger then 0 so it is not [un]sharedEmpty
577#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
578 Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable));
579#endif
580 Q_ASSERT(!x->ref.isStatic());
581 x->size = asize;
582
583 T *srcBegin = d->begin();
584 T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
585 T *dst = x->begin();
586
587 if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
588 QT_TRY {
589 if (isShared || !std::is_nothrow_move_constructible<T>::value) {
590 // we can not move the data, we need to copy construct it
591 while (srcBegin != srcEnd)
592 new (dst++) T(*srcBegin++);
593 } else {
594 while (srcBegin != srcEnd)
595 new (dst++) T(std::move(*srcBegin++));
596 }
597 } QT_CATCH (...) {
598 // destruct already copied objects
599 destruct(x->begin(), dst);
600 QT_RETHROW;
601 }
602 } else {
603 ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
604 dst += srcEnd - srcBegin;
605
606 // destruct unused / not moved data
607 if (asize < d->size)
608 destruct(d->begin() + asize, d->end());
609 }
610
611 if (asize > d->size) {
612 // construct all new objects when growing
613 if (!QTypeInfo<T>::isComplex) {
614 ::memset(static_cast<void *>(dst), 0, (static_cast<T *>(x->end()) - dst) * sizeof(T));
615 } else {
616 QT_TRY {
617 while (dst != x->end())
618 new (dst++) T();
619 } QT_CATCH (...) {
620 // destruct already copied objects
621 destruct(x->begin(), dst);
622 QT_RETHROW;
623 }
624 }
625 }
626 } QT_CATCH (...) {
627 Data::deallocate(x);
628 QT_RETHROW;
629 }
630 x->capacityReserved = d->capacityReserved;
631 } else {
632 Q_ASSERT(int(d->alloc) == aalloc); // resize, without changing allocation size
633 Q_ASSERT(isDetached()); // can be done only on detached d
634 Q_ASSERT(x == d); // in this case we do not need to allocate anything
635 if (asize <= d->size) {
636 destruct(x->begin() + asize, x->end()); // from future end to current end
637 } else {
638 defaultConstruct(x->end(), x->begin() + asize); // from current end to future end
639 }
640 x->size = asize;
641 }
642 } else {
643 x = Data::sharedNull();
644 }
645 if (d != x) {
646 if (!d->ref.deref()) {
647 if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
648 // data was copy constructed, we need to call destructors
649 // or if !alloc we did nothing to the old 'd'.
650 freeData(d);
651 } else {
652 Data::deallocate(d);
653 }
654 }
655 d = x;
656 }
657
658 Q_ASSERT(d->data());
659 Q_ASSERT(uint(d->size) <= d->alloc);
660#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
661 Q_ASSERT(d != Data::unsharableEmpty());
662#endif
663 Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull());
664 Q_ASSERT(d->alloc >= uint(aalloc));
665 Q_ASSERT(d->size == asize);
666}
667
668template<typename T>
669void QVector<T>::realloc(int aalloc, QArrayData::AllocationOptions options)
670{
671 Q_ASSERT(aalloc >= d->size);
672 Data *x = d;
673
674 const bool isShared = d->ref.isShared();
675 Q_ASSERT(aalloc != int(d->alloc) || isShared);
676
677 QT_TRY {
678 // allocate memory
679 x = Data::allocate(aalloc, options);
680 Q_CHECK_PTR(x);
681 // aalloc is bigger then 0 so it is not [un]sharedEmpty
682#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
683 Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable));
684#endif
685 Q_ASSERT(!x->ref.isStatic());
686 x->size = d->size;
687
688 T *srcBegin = d->begin();
689 T *srcEnd = d->end();
690 T *dst = x->begin();
691
692 if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
693 QT_TRY {
694 if (isShared || !std::is_nothrow_move_constructible<T>::value) {
695 // we can not move the data, we need to copy construct it
696 while (srcBegin != srcEnd)
697 new (dst++) T(*srcBegin++);
698 } else {
699 while (srcBegin != srcEnd)
700 new (dst++) T(std::move(*srcBegin++));
701 }
702 } QT_CATCH (...) {
703 // destruct already copied objects
704 destruct(x->begin(), dst);
705 QT_RETHROW;
706 }
707 } else {
708 ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
709 dst += srcEnd - srcBegin;
710 }
711
712 } QT_CATCH (...) {
713 Data::deallocate(x);
714 QT_RETHROW;
715 }
716 x->capacityReserved = d->capacityReserved;
717
718 Q_ASSERT(d != x);
719 if (!d->ref.deref()) {
720 if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
721 // data was copy constructed, we need to call destructors
722 // or if !alloc we did nothing to the old 'd'.
723 freeData(d);
724 } else {
725 Data::deallocate(d);
726 }
727 }
728 d = x;
729
730 Q_ASSERT(d->data());
731 Q_ASSERT(uint(d->size) <= d->alloc);
732#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
733 Q_ASSERT(d != Data::unsharableEmpty());
734#endif
735 Q_ASSERT(d != Data::sharedNull());
736 Q_ASSERT(d->alloc >= uint(aalloc));
737}
738
739#if defined(Q_CC_MSVC)
740QT_WARNING_POP
741#endif
742
743template<typename T>
744Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
745{
746 if (uint(i) >= uint(d->size)) {
747 return T();
748 }
749 return d->begin()[i];
750}
751template<typename T>
752Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
753{
754 return uint(i) >= uint(d->size) ? defaultValue : d->begin()[i];
755}
756
757template <typename T>
758void QVector<T>::append(const T &t)
759{
760 const bool isTooSmall = uint(d->size + 1) > d->alloc;
761 if (!isDetached() || isTooSmall) {
762 T copy(t);
763 QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
764 realloc(isTooSmall ? d->size + 1 : d->alloc, opt);
765
766 if (QTypeInfo<T>::isComplex)
767 new (d->end()) T(qMove(copy));
768 else
769 *d->end() = qMove(copy);
770
771 } else {
772 if (QTypeInfo<T>::isComplex)
773 new (d->end()) T(t);
774 else
775 *d->end() = t;
776 }
777 ++d->size;
778}
779
780#ifdef Q_COMPILER_RVALUE_REFS
781template <typename T>
782void QVector<T>::append(T &&t)
783{
784 const bool isTooSmall = uint(d->size + 1) > d->alloc;
785 if (!isDetached() || isTooSmall) {
786 QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
787 realloc(isTooSmall ? d->size + 1 : d->alloc, opt);
788 }
789
790 new (d->end()) T(std::move(t));
791
792 ++d->size;
793}
794#endif
795
796template <typename T>
797void QVector<T>::removeLast()
798{
799 Q_ASSERT(!isEmpty());
800 Q_ASSERT(d->alloc);
801
802 if (d->ref.isShared())
803 detach();
804 --d->size;
805 if (QTypeInfo<T>::isComplex)
806 (d->data() + d->size)->~T();
807}
808
809template <typename T>
810typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
811{
812 Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
813
814 const auto offset = std::distance(d->begin(), before);
815 if (n != 0) {
816 const T copy(t);
817 if (!isDetached() || d->size + n > int(d->alloc))
818 realloc(d->size + n, QArrayData::Grow);
819 if (!QTypeInfoQuery<T>::isRelocatable) {
820 T *b = d->end();
821 T *i = d->end() + n;
822 while (i != b)
823 new (--i) T;
824 i = d->end();
825 T *j = i + n;
826 b = d->begin() + offset;
827 while (i != b)
828 *--j = *--i;
829 i = b+n;
830 while (i != b)
831 *--i = copy;
832 } else {
833 T *b = d->begin() + offset;
834 T *i = b + n;
835 memmove(static_cast<void *>(i), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
836 while (i != b)
837 new (--i) T(copy);
838 }
839 d->size += n;
840 }
841 return d->begin() + offset;
842}
843
844template <typename T>
845typename QVector<T>::iterator QVector<T>::insert(iterator before, T &&t)
846{
847 Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
848
849 const auto offset = std::distance(d->begin(), before);
850 if (!isDetached() || d->size + 1 > int(d->alloc))
851 realloc(d->size + 1, QArrayData::Grow);
852 if (!QTypeInfoQuery<T>::isRelocatable) {
853 T *i = d->end();
854 T *j = i + 1;
855 T *b = d->begin() + offset;
856 // The new end-element needs to be constructed, the rest must be move assigned
857 if (i != b) {
858 new (--j) T(std::move(*--i));
859 while (i != b)
860 *--j = std::move(*--i);
861 *b = std::move(t);
862 } else {
863 new (b) T(std::move(t));
864 }
865 } else {
866 T *b = d->begin() + offset;
867 memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
868 new (b) T(std::move(t));
869 }
870 d->size += 1;
871 return d->begin() + offset;
872}
873
874template <typename T>
875typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
876{
877 Q_ASSERT_X(isValidIterator(abegin), "QVector::erase", "The specified iterator argument 'abegin' is invalid");
878 Q_ASSERT_X(isValidIterator(aend), "QVector::erase", "The specified iterator argument 'aend' is invalid");
879
880 const auto itemsToErase = aend - abegin;
881
882 if (!itemsToErase)
883 return abegin;
884
885 Q_ASSERT(abegin >= d->begin());
886 Q_ASSERT(aend <= d->end());
887 Q_ASSERT(abegin <= aend);
888
889 const auto itemsUntouched = abegin - d->begin();
890
891 // FIXME we could do a proper realloc, which copy constructs only needed data.
892 // FIXME we are about to delete data - maybe it is good time to shrink?
893 // FIXME the shrink is also an issue in removeLast, that is just a copy + reduce of this.
894 if (d->alloc) {
895 detach();
896 abegin = d->begin() + itemsUntouched;
897 aend = abegin + itemsToErase;
898 if (!QTypeInfoQuery<T>::isRelocatable) {
899 iterator moveBegin = abegin + itemsToErase;
900 iterator moveEnd = d->end();
901 while (moveBegin != moveEnd) {
902 if (QTypeInfo<T>::isComplex)
903 static_cast<T *>(abegin)->~T();
904 new (abegin++) T(*moveBegin++);
905 }
906 if (abegin < d->end()) {
907 // destroy rest of instances
908 destruct(abegin, d->end());
909 }
910 } else {
911 destruct(abegin, aend);
912 // QTBUG-53605: static_cast<void *> masks clang errors of the form
913 // error: destination for this 'memmove' call is a pointer to class containing a dynamic class
914 // FIXME maybe use std::is_polymorphic (as soon as allowed) to avoid the memmove
915 memmove(static_cast<void *>(abegin), static_cast<void *>(aend),
916 (d->size - itemsToErase - itemsUntouched) * sizeof(T));
917 }
918 d->size -= int(itemsToErase);
919 }
920 return d->begin() + itemsUntouched;
921}
922
923template <typename T>
924bool QVector<T>::operator==(const QVector<T> &v) const
925{
926 if (d == v.d)
927 return true;
928 if (d->size != v.d->size)
929 return false;
930 const T *vb = v.d->begin();
931 const T *b = d->begin();
932 const T *e = d->end();
933 return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(vb, v.d->size));
934}
935
936template <typename T>
937QVector<T> &QVector<T>::fill(const T &from, int asize)
938{
939 const T copy(from);
940 resize(asize < 0 ? d->size : asize);
941 if (d->size) {
942 T *i = d->end();
943 T *b = d->begin();
944 while (i != b)
945 *--i = copy;
946 }
947 return *this;
948}
949
950template <typename T>
951QVector<T> &QVector<T>::operator+=(const QVector &l)
952{
953 if (d->size == 0) {
954 *this = l;
955 } else {
956 uint newSize = d->size + l.d->size;
957 const bool isTooSmall = newSize > d->alloc;
958 if (!isDetached() || isTooSmall) {
959 QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
960 realloc(isTooSmall ? newSize : d->alloc, opt);
961 }
962
963 if (d->alloc) {
964 T *w = d->begin() + newSize;
965 T *i = l.d->end();
966 T *b = l.d->begin();
967 while (i != b) {
968 if (QTypeInfo<T>::isComplex)
969 new (--w) T(*--i);
970 else
971 *--w = *--i;
972 }
973 d->size = newSize;
974 }
975 }
976 return *this;
977}
978
979template <typename T>
980int QVector<T>::indexOf(const T &t, int from) const
981{
982 if (from < 0)
983 from = qMax(from + d->size, 0);
984 if (from < d->size) {
985 T* n = d->begin() + from - 1;
986 T* e = d->end();
987 while (++n != e)
988 if (*n == t)
989 return n - d->begin();
990 }
991 return -1;
992}
993
994template <typename T>
995int QVector<T>::lastIndexOf(const T &t, int from) const
996{
997 if (from < 0)
998 from += d->size;
999 else if (from >= d->size)
1000 from = d->size-1;
1001 if (from >= 0) {
1002 T* b = d->begin();
1003 T* n = d->begin() + from + 1;
1004 while (n != b) {
1005 if (*--n == t)
1006 return n - b;
1007 }
1008 }
1009 return -1;
1010}
1011
1012template <typename T>
1013bool QVector<T>::contains(const T &t) const
1014{
1015 const T *b = d->begin();
1016 const T *e = d->end();
1017 return std::find(b, e, t) != e;
1018}
1019
1020template <typename T>
1021int QVector<T>::count(const T &t) const
1022{
1023 const T *b = d->begin();
1024 const T *e = d->end();
1025 return int(std::count(b, e, t));
1026}
1027
1028template <typename T>
1029Q_OUTOFLINE_TEMPLATE QVector<T> QVector<T>::mid(int pos, int len) const
1030{
1031 using namespace QtPrivate;
1032 switch (QContainerImplHelper::mid(d->size, &pos, &len)) {
1033 case QContainerImplHelper::Null:
1034 case QContainerImplHelper::Empty:
1035 return QVector<T>();
1036 case QContainerImplHelper::Full:
1037 return *this;
1038 case QContainerImplHelper::Subset:
1039 break;
1040 }
1041
1042 QVector<T> midResult;
1043 midResult.realloc(len);
1044 T *srcFrom = d->begin() + pos;
1045 T *srcTo = d->begin() + pos + len;
1046 midResult.copyConstruct(srcFrom, srcTo, midResult.data());
1047 midResult.d->size = len;
1048 return midResult;
1049}
1050
1051Q_DECLARE_SEQUENTIAL_ITERATOR(Vector)
1052Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Vector)
1053
1054template <typename T>
1055uint qHash(const QVector<T> &key, uint seed = 0)
1056 Q_DECL_NOEXCEPT_EXPR(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
1057{
1058 return qHashRange(key.cbegin(), key.cend(), seed);
1059}
1060
1061template <typename T>
1062bool operator<(const QVector<T> &lhs, const QVector<T> &rhs)
1063 Q_DECL_NOEXCEPT_EXPR(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
1064 rhs.begin(), rhs.end())))
1065{
1066 return std::lexicographical_compare(lhs.begin(), lhs.end(),
1067 rhs.begin(), rhs.end());
1068}
1069
1070template <typename T>
1071inline bool operator>(const QVector<T> &lhs, const QVector<T> &rhs)
1072 Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs))
1073{
1074 return rhs < lhs;
1075}
1076
1077template <typename T>
1078inline bool operator<=(const QVector<T> &lhs, const QVector<T> &rhs)
1079 Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs))
1080{
1081 return !(lhs > rhs);
1082}
1083
1084template <typename T>
1085inline bool operator>=(const QVector<T> &lhs, const QVector<T> &rhs)
1086 Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs))
1087{
1088 return !(lhs < rhs);
1089}
1090
1091/*
1092 ### Qt 5:
1093 ### This needs to be removed for next releases of Qt. It is a workaround for vc++ because
1094 ### Qt exports QPolygon and QPolygonF that inherit QVector<QPoint> and
1095 ### QVector<QPointF> respectively.
1096*/
1097
1098#if defined(Q_CC_MSVC) && !defined(QT_BUILD_CORE_LIB)
1099QT_BEGIN_INCLUDE_NAMESPACE
1100#include <QtCore/qpoint.h>
1101QT_END_INCLUDE_NAMESPACE
1102extern template class Q_CORE_EXPORT QVector<QPointF>;
1103extern template class Q_CORE_EXPORT QVector<QPoint>;
1104#endif
1105
1106QVector<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*this); }
1107
1108QT_END_NAMESPACE
1109
1110#endif // QVECTOR_H
1111