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 QVARLENGTHARRAY_H
41#define QVARLENGTHARRAY_H
42
43#include <QtCore/qcontainerfwd.h>
44#include <QtCore/qglobal.h>
45#include <QtCore/qalgorithms.h>
46#include <QtCore/qcontainertools_impl.h>
47#include <QtCore/qhashfunctions.h>
48
49#include <algorithm>
50#include <initializer_list>
51#include <iterator>
52#include <new>
53#include <string.h>
54#include <stdlib.h>
55
56QT_BEGIN_NAMESPACE
57
58
59// Prealloc = 256 by default, specified in qcontainerfwd.h
60template<class T, int Prealloc>
61class QVarLengthArray
62{
63public:
64 QVarLengthArray() : QVarLengthArray(0) {}
65
66 inline explicit QVarLengthArray(int size);
67
68 inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
69 : a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
70 {
71 append(other.constData(), other.size());
72 }
73
74 QVarLengthArray(std::initializer_list<T> args)
75 : QVarLengthArray(args.begin(), args.end())
76 {
77 }
78
79 template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
80 inline QVarLengthArray(InputIterator first, InputIterator last)
81 : QVarLengthArray()
82 {
83 QtPrivate::reserveIfForwardIterator(this, first, last);
84 std::copy(first, last, std::back_inserter(*this));
85 }
86
87 inline ~QVarLengthArray() {
88 if (QTypeInfo<T>::isComplex) {
89 T *i = ptr + s;
90 while (i-- != ptr)
91 i->~T();
92 }
93 if (ptr != reinterpret_cast<T *>(array))
94 free(ptr);
95 }
96 inline QVarLengthArray<T, Prealloc> &operator=(const QVarLengthArray<T, Prealloc> &other)
97 {
98 if (this != &other) {
99 clear();
100 append(other.constData(), other.size());
101 }
102 return *this;
103 }
104
105 QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
106 {
107 resize(size: int(list.size())); // ### q6sizetype
108 std::copy(list.begin(), list.end(),
109 QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
110 return *this;
111 }
112
113 inline void removeLast() {
114 Q_ASSERT(s > 0);
115 if (QTypeInfo<T>::isComplex)
116 ptr[s - 1].~T();
117 --s;
118 }
119 inline int size() const { return s; }
120 inline int count() const { return s; }
121 inline int length() const { return s; }
122 inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
123 inline const T& first() const { Q_ASSERT(!isEmpty()); return *begin(); }
124 T& last() { Q_ASSERT(!isEmpty()); return *(end() - 1); }
125 const T& last() const { Q_ASSERT(!isEmpty()); return *(end() - 1); }
126 inline bool isEmpty() const { return (s == 0); }
127 inline void resize(int size);
128 inline void clear() { resize(size: 0); }
129 inline void squeeze();
130
131 inline int capacity() const { return a; }
132 inline void reserve(int size);
133
134 inline int indexOf(const T &t, int from = 0) const;
135 inline int lastIndexOf(const T &t, int from = -1) const;
136 inline bool contains(const T &t) const;
137
138 inline T &operator[](int idx) {
139 Q_ASSERT(idx >= 0 && idx < s);
140 return ptr[idx];
141 }
142 inline const T &operator[](int idx) const {
143 Q_ASSERT(idx >= 0 && idx < s);
144 return ptr[idx];
145 }
146 inline const T &at(int idx) const { return operator[](idx); }
147
148 T value(int i) const;
149 T value(int i, const T &defaultValue) const;
150
151 inline void append(const T &t) {
152 if (s == a) { // i.e. s != 0
153 T copy(t);
154 realloc(size: s, alloc: s<<1);
155 new (end()) T(std::move(copy));
156 } else {
157 new (end()) T(t);
158 }
159 ++s;
160 }
161
162 void append(T &&t) {
163 if (s == a)
164 realloc(size: s, alloc: s << 1);
165 new (end()) T(std::move(t));
166 ++s;
167 }
168
169 void append(const T *buf, int size);
170 inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
171 { append(t); return *this; }
172 inline QVarLengthArray<T, Prealloc> &operator<<(T &&t)
173 { append(std::move(t)); return *this; }
174 inline QVarLengthArray<T, Prealloc> &operator+=(const T &t)
175 { append(t); return *this; }
176 inline QVarLengthArray<T, Prealloc> &operator+=(T &&t)
177 { append(std::move(t)); return *this; }
178
179 void prepend(T &&t);
180 void prepend(const T &t);
181 void insert(int i, T &&t);
182 void insert(int i, const T &t);
183 void insert(int i, int n, const T &t);
184 void replace(int i, const T &t);
185 void remove(int i);
186 void remove(int i, int n);
187
188
189 inline T *data() { return ptr; }
190 inline const T *data() const { return ptr; }
191 inline const T * constData() const { return ptr; }
192 typedef int size_type;
193 typedef T value_type;
194 typedef value_type *pointer;
195 typedef const value_type *const_pointer;
196 typedef value_type &reference;
197 typedef const value_type &const_reference;
198 typedef qptrdiff difference_type;
199
200
201 typedef T* iterator;
202 typedef const T* const_iterator;
203 typedef std::reverse_iterator<iterator> reverse_iterator;
204 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
205
206 inline iterator begin() { return ptr; }
207 inline const_iterator begin() const { return ptr; }
208 inline const_iterator cbegin() const { return ptr; }
209 inline const_iterator constBegin() const { return ptr; }
210 inline iterator end() { return ptr + s; }
211 inline const_iterator end() const { return ptr + s; }
212 inline const_iterator cend() const { return ptr + s; }
213 inline const_iterator constEnd() const { return ptr + s; }
214 reverse_iterator rbegin() { return reverse_iterator(end()); }
215 reverse_iterator rend() { return reverse_iterator(begin()); }
216 const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
217 const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
218 const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }
219 const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }
220 iterator insert(const_iterator before, int n, const T &x);
221 iterator insert(const_iterator before, T &&x);
222 inline iterator insert(const_iterator before, const T &x) { return insert(before, 1, x); }
223 iterator erase(const_iterator begin, const_iterator end);
224 inline iterator erase(const_iterator pos) { return erase(pos, pos+1); }
225
226 // STL compatibility:
227 inline bool empty() const { return isEmpty(); }
228 inline void push_back(const T &t) { append(t); }
229 void push_back(T &&t) { append(std::move(t)); }
230 inline void pop_back() { removeLast(); }
231 inline T &front() { return first(); }
232 inline const T &front() const { return first(); }
233 inline T &back() { return last(); }
234 inline const T &back() const { return last(); }
235 void shrink_to_fit() { squeeze(); }
236
237private:
238 void realloc(int size, int alloc);
239
240 int a; // capacity
241 int s; // size
242 T *ptr; // data
243 union {
244 char array[Prealloc * sizeof(T)];
245 qint64 q_for_alignment_1;
246 double q_for_alignment_2;
247 };
248
249 bool isValidIterator(const const_iterator &i) const
250 {
251 const std::less<const T*> less = {};
252 return !less(cend(), i) && !less(i, cbegin());
253 }
254};
255
256#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
257template <typename InputIterator,
258 typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
259 QtPrivate::IfIsInputIterator<InputIterator> = true>
260QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray<ValueType>;
261#endif
262
263template <class T, int Prealloc>
264Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(int asize)
265 : s(asize) {
266 Q_STATIC_ASSERT_X(Prealloc > 0, "QVarLengthArray Prealloc must be greater than 0.");
267 Q_ASSERT_X(s >= 0, "QVarLengthArray::QVarLengthArray()", "Size must be greater than or equal to 0.");
268 if (s > Prealloc) {
269 ptr = reinterpret_cast<T *>(malloc(size: s * sizeof(T)));
270 Q_CHECK_PTR(ptr);
271 a = s;
272 } else {
273 ptr = reinterpret_cast<T *>(array);
274 a = Prealloc;
275 }
276 if (QTypeInfo<T>::isComplex) {
277 T *i = ptr + s;
278 while (i != ptr)
279 new (--i) T;
280 }
281}
282
283template <class T, int Prealloc>
284Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::resize(int asize)
285{ realloc(size: asize, alloc: qMax(a: asize, b: a)); }
286
287template <class T, int Prealloc>
288Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(int asize)
289{ if (asize > a) realloc(size: s, alloc: asize); }
290
291template <class T, int Prealloc>
292Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::indexOf(const T &t, int from) const
293{
294 if (from < 0)
295 from = qMax(a: from + s, b: 0);
296 if (from < s) {
297 T *n = ptr + from - 1;
298 T *e = ptr + s;
299 while (++n != e)
300 if (*n == t)
301 return n - ptr;
302 }
303 return -1;
304}
305
306template <class T, int Prealloc>
307Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t, int from) const
308{
309 if (from < 0)
310 from += s;
311 else if (from >= s)
312 from = s - 1;
313 if (from >= 0) {
314 T *b = ptr;
315 T *n = ptr + from + 1;
316 while (n != b) {
317 if (*--n == t)
318 return n - b;
319 }
320 }
321 return -1;
322}
323
324template <class T, int Prealloc>
325Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const T &t) const
326{
327 T *b = ptr;
328 T *i = ptr + s;
329 while (i != b) {
330 if (*--i == t)
331 return true;
332 }
333 return false;
334}
335
336template <class T, int Prealloc>
337Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, int increment)
338{
339 Q_ASSERT(abuf);
340 if (increment <= 0)
341 return;
342
343 const int asize = s + increment;
344
345 if (asize >= a)
346 realloc(size: s, alloc: qMax(a: s*2, b: asize));
347
348 if (QTypeInfo<T>::isComplex) {
349 // call constructor for new objects (which can throw)
350 while (s < asize)
351 new (ptr+(s++)) T(*abuf++);
352 } else {
353 memcpy(dest: static_cast<void *>(&ptr[s]), src: static_cast<const void *>(abuf), n: increment * sizeof(T));
354 s = asize;
355 }
356}
357
358template <class T, int Prealloc>
359Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::squeeze()
360{ realloc(size: s, alloc: s); }
361
362template <class T, int Prealloc>
363Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int aalloc)
364{
365 Q_ASSERT(aalloc >= asize);
366 T *oldPtr = ptr;
367 int osize = s;
368
369 const int copySize = qMin(a: asize, b: osize);
370 Q_ASSUME(copySize >= 0);
371 if (aalloc != a) {
372 if (aalloc > Prealloc) {
373 T* newPtr = reinterpret_cast<T *>(malloc(size: aalloc * sizeof(T)));
374 Q_CHECK_PTR(newPtr); // could throw
375 // by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here
376 ptr = newPtr;
377 a = aalloc;
378 } else {
379 ptr = reinterpret_cast<T *>(array);
380 a = Prealloc;
381 }
382 s = 0;
383 if (!QTypeInfoQuery<T>::isRelocatable) {
384 QT_TRY {
385 // move all the old elements
386 while (s < copySize) {
387 new (ptr+s) T(std::move(*(oldPtr+s)));
388 (oldPtr+s)->~T();
389 s++;
390 }
391 } QT_CATCH(...) {
392 // clean up all the old objects and then free the old ptr
393 int sClean = s;
394 while (sClean < osize)
395 (oldPtr+(sClean++))->~T();
396 if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
397 free(oldPtr);
398 QT_RETHROW;
399 }
400 } else {
401 memcpy(dest: static_cast<void *>(ptr), src: static_cast<const void *>(oldPtr), n: copySize * sizeof(T));
402 }
403 }
404 s = copySize;
405
406 if (QTypeInfo<T>::isComplex) {
407 // destroy remaining old objects
408 while (osize > asize)
409 (oldPtr+(--osize))->~T();
410 }
411
412 if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
413 free(oldPtr);
414
415 if (QTypeInfo<T>::isComplex) {
416 // call default constructor for new objects (which can throw)
417 while (s < asize)
418 new (ptr+(s++)) T;
419 } else {
420 s = asize;
421 }
422}
423
424template <class T, int Prealloc>
425Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i) const
426{
427 if (uint(i) >= uint(size())) {
428 return T();
429 }
430 return at(idx: i);
431}
432template <class T, int Prealloc>
433Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i, const T &defaultValue) const
434{
435 return (uint(i) >= uint(size())) ? defaultValue : at(idx: i);
436}
437
438template <class T, int Prealloc>
439inline void QVarLengthArray<T, Prealloc>::insert(int i, T &&t)
440{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
441 insert(cbegin() + i, std::move(t)); }
442template <class T, int Prealloc>
443inline void QVarLengthArray<T, Prealloc>::insert(int i, const T &t)
444{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
445 insert(begin() + i, 1, t); }
446template <class T, int Prealloc>
447inline void QVarLengthArray<T, Prealloc>::insert(int i, int n, const T &t)
448{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
449 insert(begin() + i, n, t); }
450template <class T, int Prealloc>
451inline void QVarLengthArray<T, Prealloc>::remove(int i, int n)
452{ Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= s, "QVarLengthArray::remove", "index out of range");
453 erase(begin() + i, begin() + i + n); }
454template <class T, int Prealloc>
455inline void QVarLengthArray<T, Prealloc>::remove(int i)
456{ Q_ASSERT_X(i >= 0 && i < s, "QVarLengthArray::remove", "index out of range");
457 erase(begin() + i, begin() + i + 1); }
458template <class T, int Prealloc>
459inline void QVarLengthArray<T, Prealloc>::prepend(T &&t)
460{ insert(cbegin(), std::move(t)); }
461template <class T, int Prealloc>
462inline void QVarLengthArray<T, Prealloc>::prepend(const T &t)
463{ insert(begin(), 1, t); }
464
465template <class T, int Prealloc>
466inline void QVarLengthArray<T, Prealloc>::replace(int i, const T &t)
467{
468 Q_ASSERT_X(i >= 0 && i < s, "QVarLengthArray::replace", "index out of range");
469 const T copy(t);
470 data()[i] = copy;
471}
472
473template <class T, int Prealloc>
474Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&t)
475{
476 Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
477
478 int offset = int(before - ptr);
479 reserve(asize: s + 1);
480 if (!QTypeInfo<T>::isRelocatable) {
481 T *b = ptr + offset;
482 T *i = ptr + s;
483 T *j = i + 1;
484 // The new end-element needs to be constructed, the rest must be move assigned
485 if (i != b) {
486 new (--j) T(std::move(*--i));
487 while (i != b)
488 *--j = std::move(*--i);
489 *b = std::move(t);
490 } else {
491 new (b) T(std::move(t));
492 }
493 } else {
494 T *b = ptr + offset;
495 memmove(dest: static_cast<void *>(b + 1), src: static_cast<const void *>(b), n: (s - offset) * sizeof(T));
496 new (b) T(std::move(t));
497 }
498 s += 1;
499 return ptr + offset;
500}
501
502template <class T, int Prealloc>
503Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, int n, const T &t)
504{
505 Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
506
507 int offset = int(before - ptr);
508 if (n != 0) {
509 const T copy(t); // `t` could alias an element in [begin(), end()[
510 resize(asize: s + n);
511 if (!QTypeInfoQuery<T>::isRelocatable) {
512 T *b = ptr + offset;
513 T *j = ptr + s;
514 T *i = j - n;
515 while (i != b)
516 *--j = *--i;
517 i = b + n;
518 while (i != b)
519 *--i = copy;
520 } else {
521 T *b = ptr + offset;
522 T *i = b + n;
523 memmove(dest: static_cast<void *>(i), src: static_cast<const void *>(b), n: (s - offset - n) * sizeof(T));
524 while (i != b)
525 new (--i) T(copy);
526 }
527 }
528 return ptr + offset;
529}
530
531template <class T, int Prealloc>
532Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator abegin, const_iterator aend)
533{
534 Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::insert", "The specified const_iterator argument 'abegin' is invalid");
535 Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::insert", "The specified const_iterator argument 'aend' is invalid");
536
537 int f = int(abegin - ptr);
538 int l = int(aend - ptr);
539 int n = l - f;
540
541 if (n == 0) // avoid UB in std::copy() below
542 return data() + f;
543
544 Q_ASSERT(n > 0); // aend must be reachable from abegin
545
546 if (QTypeInfo<T>::isComplex) {
547 std::copy(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f));
548 T *i = ptr + s;
549 T *b = ptr + s - n;
550 while (i != b) {
551 --i;
552 i->~T();
553 }
554 } else {
555 memmove(dest: static_cast<void *>(ptr + f), src: static_cast<const void *>(ptr + l), n: (s - l) * sizeof(T));
556 }
557 s -= n;
558 return ptr + f;
559}
560
561template <typename T, int Prealloc1, int Prealloc2>
562bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
563{
564 if (l.size() != r.size())
565 return false;
566 const T *rb = r.begin();
567 const T *b = l.begin();
568 const T *e = l.end();
569 return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(rb, r.size()));
570}
571
572template <typename T, int Prealloc1, int Prealloc2>
573bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
574{
575 return !(l == r);
576}
577
578template <typename T, int Prealloc1, int Prealloc2>
579bool operator<(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
580 noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
581 rhs.begin(), rhs.end())))
582{
583 return std::lexicographical_compare(lhs.begin(), lhs.end(),
584 rhs.begin(), rhs.end());
585}
586
587template <typename T, int Prealloc1, int Prealloc2>
588inline bool operator>(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
589 noexcept(noexcept(lhs < rhs))
590{
591 return rhs < lhs;
592}
593
594template <typename T, int Prealloc1, int Prealloc2>
595inline bool operator<=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
596 noexcept(noexcept(lhs < rhs))
597{
598 return !(lhs > rhs);
599}
600
601template <typename T, int Prealloc1, int Prealloc2>
602inline bool operator>=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
603 noexcept(noexcept(lhs < rhs))
604{
605 return !(lhs < rhs);
606}
607
608template <typename T, int Prealloc>
609uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0)
610 noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
611{
612 return qHashRange(key.cbegin(), key.cend(), seed);
613}
614
615QT_END_NAMESPACE
616
617#endif // QVARLENGTHARRAY_H
618

source code of qtbase/src/corelib/tools/qvarlengtharray.h