Retain compiler warning state
[qt:qtbase.git] / src / corelib / tools / qvector.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QVECTOR_H
43 #define QVECTOR_H
44
45 #include <QtCore/qalgorithms.h>
46 #include <QtCore/qiterator.h>
47 #include <QtCore/qlist.h>
48 #include <QtCore/qrefcount.h>
49 #include <QtCore/qarraydata.h>
50
51 #include <iterator>
52 #include <vector>
53 #include <stdlib.h>
54 #include <string.h>
55 #ifdef Q_COMPILER_INITIALIZER_LISTS
56 #include <initializer_list>
57 #endif
58
59 #include <algorithm>
60
61 QT_BEGIN_NAMESPACE
62
63 class QRegion;
64
65 template <typename T>
66 class QVector
67 {
68     typedef QTypedArrayData<T> Data;
69     Data *d;
70
71 public:
72     inline QVector() : d(Data::sharedNull()) { }
73     explicit QVector(int size);
74     QVector(int size, const T &t);
75     inline QVector(const QVector<T> &v);
76     inline ~QVector() { if (!d->ref.deref()) freeData(d); }
77     QVector<T> &operator=(const QVector<T> &v);
78 #ifdef Q_COMPILER_RVALUE_REFS
79     inline QVector(QVector<T> &&other) : d(other.d) { other.d = Data::sharedNull(); }
80     inline QVector<T> operator=(QVector<T> &&other)
81     { qSwap(d, other.d); return *this; }
82 #endif
83     inline void swap(QVector<T> &other) { qSwap(d, other.d); }
84 #ifdef Q_COMPILER_INITIALIZER_LISTS
85     inline QVector(std::initializer_list<T> args);
86 #endif
87     bool operator==(const QVector<T> &v) const;
88     inline bool operator!=(const QVector<T> &v) const { return !(*this == v); }
89
90     inline int size() const { return d->size; }
91
92     inline bool isEmpty() const { return d->size == 0; }
93
94     void resize(int size);
95
96     inline int capacity() const { return int(d->alloc); }
97     void reserve(int size);
98     inline void squeeze()
99     {
100         reallocData(d->size, d->size);
101         if (d->capacityReserved) {
102             // capacity reserved in a read only memory would be useless
103             // this checks avoid writing to such memory.
104             d->capacityReserved = 0;
105         }
106     }
107
108     inline void detach();
109     inline bool isDetached() const { return !d->ref.isShared(); }
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
126     inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
127
128     inline T *data() { detach(); return d->begin(); }
129     inline const T *data() const { return d->begin(); }
130     inline const T *constData() const { return d->begin(); }
131     void clear();
132
133     const T &at(int i) const;
134     T &operator[](int i);
135     const T &operator[](int i) const;
136     void append(const T &t);
137     void prepend(const T &t);
138     void insert(int i, const T &t);
139     void insert(int i, int n, const T &t);
140     void replace(int i, const T &t);
141     void remove(int i);
142     void remove(int i, int n);
143     inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(d->begin()); }
144     inline void removeLast();
145     inline T takeFirst() { Q_ASSERT(!isEmpty()); T r = first(); removeFirst(); return r; }
146     inline T takeLast()  { Q_ASSERT(!isEmpty()); T r = last(); removeLast(); return r; }
147
148     QVector<T> &fill(const T &t, int size = -1);
149
150     int indexOf(const T &t, int from = 0) const;
151     int lastIndexOf(const T &t, int from = -1) const;
152     bool contains(const T &t) const;
153     int count(const T &t) const;
154
155     // QList compatibility
156     void removeAt(int i) { remove(i); }
157     int length() const { return size(); }
158     T takeAt(int i) { T t = at(i); remove(i); return t; }
159
160     // STL-style
161     typedef typename Data::iterator iterator;
162     typedef typename Data::const_iterator const_iterator;
163 #if !defined(QT_STRICT_ITERATORS) || defined(Q_QDOC)
164     inline iterator begin() { detach(); return d->begin(); }
165     inline const_iterator begin() const { return d->constBegin(); }
166     inline const_iterator cbegin() const { return d->constBegin(); }
167     inline const_iterator constBegin() const { return d->constBegin(); }
168     inline iterator end() { detach(); return d->end(); }
169     inline const_iterator end() const { return d->constEnd(); }
170     inline const_iterator cend() const { return d->constEnd(); }
171     inline const_iterator constEnd() const { return d->constEnd(); }
172 #else
173     inline iterator begin(iterator = iterator()) { detach(); return d->begin(); }
174     inline const_iterator begin(const_iterator = const_iterator()) const { return d->constBegin(); }
175     inline const_iterator cbegin(const_iterator = const_iterator()) const { return d->constBegin(); }
176     inline const_iterator constBegin(const_iterator = const_iterator()) const { return d->constBegin(); }
177     inline iterator end(iterator = iterator()) { detach(); return d->end(); }
178     inline const_iterator end(const_iterator = const_iterator()) const { return d->constEnd(); }
179     inline const_iterator cend(const_iterator = const_iterator()) const { return d->constEnd(); }
180     inline const_iterator constEnd(const_iterator = const_iterator()) const { return d->constEnd(); }
181 #endif
182     iterator insert(iterator before, int n, const T &x);
183     inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
184     iterator erase(iterator begin, iterator end);
185     inline iterator erase(iterator pos) { return erase(pos, pos+1); }
186
187     // more Qt
188     inline int count() const { return d->size; }
189     inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
190     inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); }
191     inline T& last() { Q_ASSERT(!isEmpty()); return *(end()-1); }
192     inline const T &last() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
193     inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
194     inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
195     QVector<T> mid(int pos, int len = -1) const;
196
197     T value(int i) const;
198     T value(int i, const T &defaultValue) const;
199
200     // STL compatibility
201     typedef T value_type;
202     typedef value_type* pointer;
203     typedef const value_type* const_pointer;
204     typedef value_type& reference;
205     typedef const value_type& const_reference;
206     typedef qptrdiff difference_type;
207     typedef iterator Iterator;
208     typedef const_iterator ConstIterator;
209     typedef int size_type;
210     inline void push_back(const T &t) { append(t); }
211     inline void push_front(const T &t) { prepend(t); }
212     void pop_back() { removeLast(); }
213     void pop_front() { removeFirst(); }
214     inline bool empty() const
215     { return d->size == 0; }
216     inline T& front() { return first(); }
217     inline const_reference front() const { return first(); }
218     inline reference back() { return last(); }
219     inline const_reference back() const { return last(); }
220
221     // comfort
222     QVector<T> &operator+=(const QVector<T> &l);
223     inline QVector<T> operator+(const QVector<T> &l) const
224     { QVector n = *this; n += l; return n; }
225     inline QVector<T> &operator+=(const T &t)
226     { append(t); return *this; }
227     inline QVector<T> &operator<< (const T &t)
228     { append(t); return *this; }
229     inline QVector<T> &operator<<(const QVector<T> &l)
230     { *this += l; return *this; }
231
232     QList<T> toList() const;
233
234     static QVector<T> fromList(const QList<T> &list);
235
236     static inline QVector<T> fromStdVector(const std::vector<T> &vector)
237     { QVector<T> tmp; tmp.reserve(int(vector.size())); std::copy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; }
238     inline std::vector<T> toStdVector() const
239     { std::vector<T> tmp; tmp.reserve(size()); std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; }
240 private:
241     friend class QRegion; // Optimization for QRegion::rects()
242
243     void reallocData(const int size, const int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
244     void reallocData(const int sz) { reallocData(sz, d->alloc); }
245     void freeData(Data *d);
246     void defaultConstruct(T *from, T *to);
247     void copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom);
248     void destruct(T *from, T *to);
249     bool isValidIterator(const iterator &i) const
250     {
251         return (i <= d->end()) && (d->begin() <= i);
252     }
253     class AlignmentDummy { Data header; T array[1]; };
254 };
255
256 #ifdef Q_CC_MSVC
257 // behavior change: an object of POD type constructed with an initializer of the form ()
258 // will be default-initialized
259 #   pragma warning ( push )
260 #   pragma warning ( disable : 4345 )
261 #endif
262
263 template <typename T>
264 void QVector<T>::defaultConstruct(T *from, T *to)
265 {
266     if (QTypeInfo<T>::isComplex) {
267         while (from != to) {
268             new (from++) T();
269         }
270     } else {
271         ::memset(static_cast<void *>(from), 0, (to - from) * sizeof(T));
272     }
273 }
274
275 #ifdef Q_CC_MSVC
276 #   pragma warning ( pop )
277 #endif
278
279 template <typename T>
280 void QVector<T>::copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom)
281 {
282     if (QTypeInfo<T>::isComplex) {
283         while (srcFrom != srcTo)
284             new (dstFrom++) T(*srcFrom++);
285     } else {
286         ::memcpy(static_cast<void *>(dstFrom), static_cast<const void *>(srcFrom), (srcTo - srcFrom) * sizeof(T));
287     }
288 }
289
290 template <typename T>
291 void QVector<T>::destruct(T *from, T *to)
292 {
293     if (QTypeInfo<T>::isComplex) {
294         while (from != to) {
295             from++->~T();
296         }
297     }
298 }
299
300 template <typename T>
301 inline QVector<T>::QVector(const QVector<T> &v)
302 {
303     if (v.d->ref.ref()) {
304         d = v.d;
305     } else {
306         if (v.d->capacityReserved) {
307             d = Data::allocate(v.d->alloc);
308             d->capacityReserved = true;
309         } else {
310             d = Data::allocate(v.d->size);
311         }
312         if (d->alloc) {
313             copyConstruct(v.d->begin(), v.d->end(), d->begin());
314             d->size = v.d->size;
315         }
316     }
317 }
318
319 template <typename T>
320 void QVector<T>::detach()
321 {
322     if (!isDetached()) {
323         if (d->alloc)
324             reallocData(d->size, int(d->alloc));
325         else
326             d = Data::unsharableEmpty();
327     }
328     Q_ASSERT(isDetached());
329 }
330
331 template <typename T>
332 void QVector<T>::reserve(int asize)
333 {
334     if (asize > int(d->alloc))
335         reallocData(d->size, asize);
336     if (isDetached())
337         d->capacityReserved = 1;
338     Q_ASSERT(capacity() >= asize);
339 }
340
341 template <typename T>
342 void QVector<T>::resize(int asize)
343 {
344     int newAlloc;
345     const int oldAlloc = int(d->alloc);
346     QArrayData::AllocationOptions opt;
347
348     if (asize > oldAlloc) { // there is not enough space
349         newAlloc = asize;
350         opt = QArrayData::Grow;
351     } else if (!d->capacityReserved && asize < d->size && asize < (oldAlloc >> 1)) { // we want to shrink
352         newAlloc = asize;
353         opt = QArrayData::Grow;
354     } else {
355         newAlloc = oldAlloc;
356     }
357     reallocData(asize, newAlloc, opt);
358 }
359 template <typename T>
360 inline void QVector<T>::clear()
361 { *this = QVector<T>(); }
362 template <typename T>
363 inline const T &QVector<T>::at(int i) const
364 { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
365   return d->begin()[i]; }
366 template <typename T>
367 inline const T &QVector<T>::operator[](int i) const
368 { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
369   return d->begin()[i]; }
370 template <typename T>
371 inline T &QVector<T>::operator[](int i)
372 { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
373   return data()[i]; }
374 template <typename T>
375 inline void QVector<T>::insert(int i, const T &t)
376 { Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
377   insert(begin() + i, 1, t); }
378 template <typename T>
379 inline void QVector<T>::insert(int i, int n, const T &t)
380 { Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
381   insert(begin() + i, n, t); }
382 template <typename T>
383 inline void QVector<T>::remove(int i, int n)
384 { Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= d->size, "QVector<T>::remove", "index out of range");
385   erase(d->begin() + i, d->begin() + i + n); }
386 template <typename T>
387 inline void QVector<T>::remove(int i)
388 { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::remove", "index out of range");
389   erase(d->begin() + i, d->begin() + i + 1); }
390 template <typename T>
391 inline void QVector<T>::prepend(const T &t)
392 { insert(begin(), 1, t); }
393
394 template <typename T>
395 inline void QVector<T>::replace(int i, const T &t)
396 {
397     Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::replace", "index out of range");
398     const T copy(t);
399     data()[i] = copy;
400 }
401
402 template <typename T>
403 QVector<T> &QVector<T>::operator=(const QVector<T> &v)
404 {
405     if (v.d != d) {
406         QVector<T> tmp(v);
407         tmp.swap(*this);
408     }
409     return *this;
410 }
411
412 template <typename T>
413 QVector<T>::QVector(int asize)
414 {
415     Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
416     if (Q_LIKELY(asize > 0)) {
417         d = Data::allocate(asize);
418         d->size = asize;
419         defaultConstruct(d->begin(), d->end());
420     } else {
421         d = Data::sharedNull();
422     }
423 }
424
425 template <typename T>
426 QVector<T>::QVector(int asize, const T &t)
427 {
428     Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
429     if (asize > 0) {
430         d = Data::allocate(asize);
431         d->size = asize;
432         T* i = d->end();
433         while (i != d->begin())
434             new (--i) T(t);
435     } else {
436         d = Data::sharedNull();
437     }
438 }
439
440 #ifdef Q_COMPILER_INITIALIZER_LISTS
441 template <typename T>
442 QVector<T>::QVector(std::initializer_list<T> args)
443 {
444     if (args.size() > 0) {
445         d = Data::allocate(args.size());
446         // std::initializer_list<T>::iterator is guaranteed to be
447         // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct
448         copyConstruct(args.begin(), args.end(), d->begin());
449         d->size = int(args.size());
450     } else {
451         d = Data::sharedNull();
452     }
453 }
454 #endif
455
456 template <typename T>
457 void QVector<T>::freeData(Data *x)
458 {
459     destruct(x->begin(), x->end());
460     Data::deallocate(x);
461 }
462
463 template <typename T>
464 void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::AllocationOptions options)
465 {
466     Q_ASSERT(asize >= 0 && asize <= aalloc);
467     Data *x = d;
468
469     const bool isShared = d->ref.isShared();
470
471     if (aalloc != 0) {
472         if (aalloc != int(d->alloc) || isShared) {
473             QT_TRY {
474                 // allocate memory
475                 x = Data::allocate(aalloc, options);
476                 Q_CHECK_PTR(x);
477                 // aalloc is bigger then 0 so it is not [un]sharedEmpty
478                 Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable));
479                 Q_ASSERT(!x->ref.isStatic());
480                 x->size = asize;
481
482                 T *srcBegin = d->begin();
483                 T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
484                 T *dst = x->begin();
485
486                 if (QTypeInfo<T>::isStatic || (isShared && QTypeInfo<T>::isComplex)) {
487                     // we can not move the data, we need to copy construct it
488                     while (srcBegin != srcEnd) {
489                         new (dst++) T(*srcBegin++);
490                     }
491                 } else {
492                     ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
493                     dst += srcEnd - srcBegin;
494
495                     // destruct unused / not moved data
496                     if (asize < d->size)
497                         destruct(d->begin() + asize, d->end());
498                 }
499
500                 if (asize > d->size) {
501                     // construct all new objects when growing
502                     QT_TRY {
503                         defaultConstruct(dst, x->end());
504                     } QT_CATCH (...) {
505                         // destruct already copied objects
506                         destruct(x->begin(), dst);
507                         QT_RETHROW;
508                     }
509                 }
510             } QT_CATCH (...) {
511                 Data::deallocate(x);
512                 QT_RETHROW;
513             }
514             x->capacityReserved = d->capacityReserved;
515         } else {
516             Q_ASSERT(int(d->alloc) == aalloc); // resize, without changing allocation size
517             Q_ASSERT(isDetached());       // can be done only on detached d
518             Q_ASSERT(x == d);             // in this case we do not need to allocate anything
519             if (asize <= d->size) {
520                 destruct(x->begin() + asize, x->end()); // from future end to current end
521             } else {
522                 defaultConstruct(x->end(), x->begin() + asize); // from current end to future end
523             }
524             x->size = asize;
525         }
526     } else {
527         x = Data::sharedNull();
528     }
529     if (d != x) {
530         if (!d->ref.deref()) {
531             if (QTypeInfo<T>::isStatic || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
532                 // data was copy constructed, we need to call destructors
533                 // or if !alloc we did nothing to the old 'd'.
534                 freeData(d);
535             } else {
536                 Data::deallocate(d);
537             }
538         }
539         d = x;
540     }
541
542     Q_ASSERT(d->data());
543     Q_ASSERT(uint(d->size) <= d->alloc);
544     Q_ASSERT(d != Data::unsharableEmpty());
545     Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull());
546     Q_ASSERT(d->alloc >= uint(aalloc));
547     Q_ASSERT(d->size == asize);
548 }
549
550 template<typename T>
551 Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
552 {
553     if (uint(i) >= uint(d->size)) {
554         return T();
555     }
556     return d->begin()[i];
557 }
558 template<typename T>
559 Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
560 {
561     return uint(i) >= uint(d->size) ? defaultValue : d->begin()[i];
562 }
563
564 template <typename T>
565 void QVector<T>::append(const T &t)
566 {
567     const T copy(t);
568     const bool isTooSmall = uint(d->size + 1) > d->alloc;
569     if (!isDetached() || isTooSmall) {
570         QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
571         reallocData(d->size, isTooSmall ? d->size + 1 : d->alloc, opt);
572     }
573     if (QTypeInfo<T>::isComplex)
574         new (d->end()) T(copy);
575     else
576         *d->end() = copy;
577     ++d->size;
578 }
579
580 template <typename T>
581 void QVector<T>::removeLast()
582 {
583     Q_ASSERT(!isEmpty());
584     Q_ASSERT(d->alloc);
585
586     if (!d->ref.isShared()) {
587         --d->size;
588         if (QTypeInfo<T>::isComplex)
589             (d->data() + d->size)->~T();
590     } else {
591         reallocData(d->size - 1);
592     }
593 }
594
595 template <typename T>
596 typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
597 {
598     Q_ASSERT_X(isValidIterator(before),  "QVector::insert", "The specified iterator argument 'before' is invalid");
599
600     int offset = std::distance(d->begin(), before);
601     if (n != 0) {
602         const T copy(t);
603         if (!isDetached() || d->size + n > int(d->alloc))
604             reallocData(d->size, d->size + n, QArrayData::Grow);
605         if (QTypeInfo<T>::isStatic) {
606             T *b = d->end();
607             T *i = d->end() + n;
608             while (i != b)
609                 new (--i) T;
610             i = d->end();
611             T *j = i + n;
612             b = d->begin() + offset;
613             while (i != b)
614                 *--j = *--i;
615             i = b+n;
616             while (i != b)
617                 *--i = copy;
618         } else {
619             T *b = d->begin() + offset;
620             T *i = b + n;
621             memmove(i, b, (d->size - offset) * sizeof(T));
622             while (i != b)
623                 new (--i) T(copy);
624         }
625         d->size += n;
626     }
627     return d->begin() + offset;
628 }
629
630 template <typename T>
631 typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
632 {
633     Q_ASSERT_X(isValidIterator(abegin), "QVector::erase", "The specified iterator argument 'abegin' is invalid");
634     Q_ASSERT_X(isValidIterator(aend), "QVector::erase", "The specified iterator argument 'aend' is invalid");
635
636     const int itemsToErase = aend - abegin;
637
638     if (!itemsToErase)
639         return abegin;
640
641     Q_ASSERT(abegin >= d->begin());
642     Q_ASSERT(aend <= d->end());
643     Q_ASSERT(abegin <= aend);
644
645     const int itemsUntouched = abegin - d->begin();
646
647     // FIXME we could do a proper realloc, which copy constructs only needed data.
648     // FIXME we ara about to delete data maybe it is good time to shrink?
649     // FIXME the shrink is also an issue in removeLast, that is just a copy + reduce of this.
650     if (d->alloc) {
651         detach();
652         abegin = d->begin() + itemsUntouched;
653         aend = abegin + itemsToErase;
654         if (QTypeInfo<T>::isStatic) {
655             iterator moveBegin = abegin + itemsToErase;
656             iterator moveEnd = d->end();
657             while (moveBegin != moveEnd) {
658                 if (QTypeInfo<T>::isComplex)
659                     static_cast<T *>(abegin)->~T();
660                 new (abegin++) T(*moveBegin++);
661             }
662             if (abegin < d->end()) {
663                 // destroy rest of instances
664                 destruct(abegin, d->end());
665             }
666         } else {
667             destruct(abegin, aend);
668             memmove(abegin, aend, (d->size - itemsToErase - itemsUntouched) * sizeof(T));
669         }
670         d->size -= itemsToErase;
671     }
672     return d->begin() + itemsUntouched;
673 }
674
675 template <typename T>
676 bool QVector<T>::operator==(const QVector<T> &v) const
677 {
678     if (d->size != v.d->size)
679         return false;
680     if (d == v.d)
681         return true;
682     T* b = d->begin();
683     T* i = b + d->size;
684     T* j = v.d->end();
685     while (i != b)
686         if (!(*--i == *--j))
687             return false;
688     return true;
689 }
690
691 template <typename T>
692 QVector<T> &QVector<T>::fill(const T &from, int asize)
693 {
694     const T copy(from);
695     resize(asize < 0 ? d->size : asize);
696     if (d->size) {
697         T *i = d->end();
698         T *b = d->begin();
699         while (i != b)
700             *--i = copy;
701     }
702     return *this;
703 }
704
705 template <typename T>
706 QVector<T> &QVector<T>::operator+=(const QVector &l)
707 {
708     uint newSize = d->size + l.d->size;
709     const bool isTooSmall = newSize > d->alloc;
710     if (!isDetached() || isTooSmall) {
711         QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
712         reallocData(d->size, isTooSmall ? newSize : d->alloc, opt);
713     }
714
715     if (d->alloc) {
716         T *w = d->begin() + newSize;
717         T *i = l.d->end();
718         T *b = l.d->begin();
719         while (i != b) {
720             if (QTypeInfo<T>::isComplex)
721                 new (--w) T(*--i);
722             else
723                 *--w = *--i;
724         }
725         d->size = newSize;
726     }
727     return *this;
728 }
729
730 template <typename T>
731 int QVector<T>::indexOf(const T &t, int from) const
732 {
733     if (from < 0)
734         from = qMax(from + d->size, 0);
735     if (from < d->size) {
736         T* n = d->begin() + from - 1;
737         T* e = d->end();
738         while (++n != e)
739             if (*n == t)
740                 return n - d->begin();
741     }
742     return -1;
743 }
744
745 template <typename T>
746 int QVector<T>::lastIndexOf(const T &t, int from) const
747 {
748     if (from < 0)
749         from += d->size;
750     else if (from >= d->size)
751         from = d->size-1;
752     if (from >= 0) {
753         T* b = d->begin();
754         T* n = d->begin() + from + 1;
755         while (n != b) {
756             if (*--n == t)
757                 return n - b;
758         }
759     }
760     return -1;
761 }
762
763 template <typename T>
764 bool QVector<T>::contains(const T &t) const
765 {
766     T* b = d->begin();
767     T* i = d->end();
768     while (i != b)
769         if (*--i == t)
770             return true;
771     return false;
772 }
773
774 template <typename T>
775 int QVector<T>::count(const T &t) const
776 {
777     int c = 0;
778     T* b = d->begin();
779     T* i = d->end();
780     while (i != b)
781         if (*--i == t)
782             ++c;
783     return c;
784 }
785
786 template <typename T>
787 Q_OUTOFLINE_TEMPLATE QVector<T> QVector<T>::mid(int pos, int len) const
788 {
789     if (len < 0)
790         len = size() - pos;
791     if (pos == 0 && len == size())
792         return *this;
793     if (pos + len > size())
794         len = size() - pos;
795     QVector<T> copy;
796     copy.reserve(len);
797     for (int i = pos; i < pos + len; ++i)
798         copy += at(i);
799     return copy;
800 }
801
802 template <typename T>
803 Q_OUTOFLINE_TEMPLATE QList<T> QVector<T>::toList() const
804 {
805     QList<T> result;
806     result.reserve(size());
807     for (int i = 0; i < size(); ++i)
808         result.append(at(i));
809     return result;
810 }
811
812 template <typename T>
813 Q_OUTOFLINE_TEMPLATE QVector<T> QList<T>::toVector() const
814 {
815     QVector<T> result(size());
816     for (int i = 0; i < size(); ++i)
817         result[i] = at(i);
818     return result;
819 }
820
821 template <typename T>
822 QVector<T> QVector<T>::fromList(const QList<T> &list)
823 {
824     return list.toVector();
825 }
826
827 template <typename T>
828 QList<T> QList<T>::fromVector(const QVector<T> &vector)
829 {
830     return vector.toList();
831 }
832
833 Q_DECLARE_SEQUENTIAL_ITERATOR(Vector)
834 Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Vector)
835
836 /*
837    ### Qt 5:
838    ### This needs to be removed for next releases of Qt. It is a workaround for vc++ because
839    ### Qt exports QPolygon and QPolygonF that inherit QVector<QPoint> and
840    ### QVector<QPointF> respectively.
841 */
842
843 #ifdef Q_CC_MSVC
844 QT_BEGIN_INCLUDE_NAMESPACE
845 #include <QtCore/qpoint.h>
846 QT_END_INCLUDE_NAMESPACE
847
848 #if defined(QT_BUILD_CORE_LIB)
849 #define Q_TEMPLATE_EXTERN
850 #else
851 #define Q_TEMPLATE_EXTERN extern
852 #endif
853 Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPointF>;
854 Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPoint>;
855 #endif
856
857 QT_END_NAMESPACE
858
859 #endif // QVECTOR_H