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