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