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