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, qsizetype Prealloc>
61class QVarLengthArray
62{
63 static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
64
65public:
66 QVarLengthArray() : QVarLengthArray(0) {}
67
68 inline explicit QVarLengthArray(qsizetype size);
69
70 inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
71 : a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
72 {
73 append(other.constData(), other.size());
74 }
75
76 QVarLengthArray(QVarLengthArray &&other)
77 noexcept(std::is_nothrow_move_constructible_v<T>)
78 : a{other.a},
79 s{other.s},
80 ptr{other.ptr}
81 {
82 const auto otherInlineStorage = reinterpret_cast<T*>(other.array);
83 if (ptr == otherInlineStorage) {
84 // inline buffer - move into our inline buffer:
85 ptr = reinterpret_cast<T*>(array);
86 QtPrivate::q_uninitialized_relocate_n(otherInlineStorage, s, ptr);
87 } else {
88 // heap buffer - we just stole the memory
89 }
90 // reset other to internal storage:
91 other.a = Prealloc;
92 other.s = 0;
93 other.ptr = otherInlineStorage;
94 }
95
96 QVarLengthArray(std::initializer_list<T> args)
97 : QVarLengthArray(args.begin(), args.end())
98 {
99 }
100
101 template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
102 inline QVarLengthArray(InputIterator first, InputIterator last)
103 : QVarLengthArray()
104 {
105 QtPrivate::reserveIfForwardIterator(this, first, last);
106 std::copy(first, last, std::back_inserter(*this));
107 }
108
109 inline ~QVarLengthArray()
110 {
111 if constexpr (QTypeInfo<T>::isComplex)
112 std::destroy_n(ptr, s);
113 if (ptr != reinterpret_cast<T *>(array))
114 free(ptr);
115 }
116 inline QVarLengthArray<T, Prealloc> &operator=(const QVarLengthArray<T, Prealloc> &other)
117 {
118 if (this != &other) {
119 clear();
120 append(other.constData(), other.size());
121 }
122 return *this;
123 }
124
125 QVarLengthArray &operator=(QVarLengthArray &&other)
126 noexcept(std::is_nothrow_move_constructible_v<T>)
127 {
128 // we're only required to be self-move-assignment-safe
129 // when we're in the moved-from state (Hinnant criterion)
130 // the moved-from state is the empty state, so we're good with the clear() here:
131 clear();
132 Q_ASSERT(capacity() >= Prealloc);
133 const auto otherInlineStorage = reinterpret_cast<T *>(other.array);
134 if (other.ptr != otherInlineStorage) {
135 // heap storage: steal the external buffer, reset other to otherInlineStorage
136 a = std::exchange(other.a, Prealloc);
137 ptr = std::exchange(other.ptr, otherInlineStorage);
138 } else {
139 // inline storage: move into our storage (doesn't matter whether inline or external)
140 QtPrivate::q_uninitialized_relocate_n(other.ptr, other.s, ptr);
141 }
142 s = std::exchange(other.s, 0);
143 return *this;
144 }
145
146 QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
147 {
148 resize(qsizetype(list.size()));
149 std::copy(list.begin(), list.end(),
150 QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
151 return *this;
152 }
153
154 inline void removeLast()
155 {
156 Q_ASSERT(s > 0);
157 if constexpr (QTypeInfo<T>::isComplex)
158 ptr[s - 1].~T();
159 --s;
160 }
161 inline qsizetype size() const { return s; }
162 inline qsizetype count() const { return s; }
163 inline qsizetype length() const { return s; }
164 inline T &first()
165 {
166 Q_ASSERT(!isEmpty());
167 return *begin();
168 }
169 inline const T &first() const
170 {
171 Q_ASSERT(!isEmpty());
172 return *begin();
173 }
174 T &last()
175 {
176 Q_ASSERT(!isEmpty());
177 return *(end() - 1);
178 }
179 const T &last() const
180 {
181 Q_ASSERT(!isEmpty());
182 return *(end() - 1);
183 }
184 inline bool isEmpty() const { return (s == 0); }
185 inline void resize(qsizetype size);
186 inline void clear() { resize(0); }
187 inline void squeeze();
188
189 inline qsizetype capacity() const { return a; }
190 inline void reserve(qsizetype size);
191
192 template <typename AT = T>
193 inline qsizetype indexOf(const AT &t, qsizetype from = 0) const;
194 template <typename AT = T>
195 inline qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const;
196 template <typename AT = T>
197 inline bool contains(const AT &t) const;
198
199 inline T &operator[](qsizetype idx)
200 {
201 Q_ASSERT(idx >= 0 && idx < s);
202 return ptr[idx];
203 }
204 inline const T &operator[](qsizetype idx) const
205 {
206 Q_ASSERT(idx >= 0 && idx < s);
207 return ptr[idx];
208 }
209 inline const T &at(qsizetype idx) const { return operator[](idx); }
210
211 T value(qsizetype i) const;
212 T value(qsizetype i, const T &defaultValue) const;
213
214 inline void append(const T &t)
215 {
216 if (s == a) { // i.e. s != 0
217 T copy(t);
218 reallocate(s, s << 1);
219 const qsizetype idx = s++;
220 new (ptr + idx) T(std::move(copy));
221 } else {
222 const qsizetype idx = s++;
223 new (ptr + idx) T(t);
224 }
225 }
226
227 void append(T &&t)
228 {
229 if (s == a)
230 reallocate(s, s << 1);
231 const qsizetype idx = s++;
232 new (ptr + idx) T(std::move(t));
233 }
234
235 void append(const T *buf, qsizetype size);
236 inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
237 { append(t); return *this; }
238 inline QVarLengthArray<T, Prealloc> &operator<<(T &&t)
239 { append(std::move(t)); return *this; }
240 inline QVarLengthArray<T, Prealloc> &operator+=(const T &t)
241 { append(t); return *this; }
242 inline QVarLengthArray<T, Prealloc> &operator+=(T &&t)
243 { append(std::move(t)); return *this; }
244
245 void prepend(T &&t);
246 void prepend(const T &t);
247 void insert(qsizetype i, T &&t);
248 void insert(qsizetype i, const T &t);
249 void insert(qsizetype i, qsizetype n, const T &t);
250 void replace(qsizetype i, const T &t);
251 void remove(qsizetype i);
252 void remove(qsizetype i, qsizetype n);
253 template <typename AT = T>
254 qsizetype removeAll(const AT &t);
255 template <typename AT = T>
256 bool removeOne(const AT &t);
257 template <typename Predicate>
258 qsizetype removeIf(Predicate pred);
259
260 inline T *data() { return ptr; }
261 inline const T *data() const { return ptr; }
262 inline const T *constData() const { return ptr; }
263 typedef qsizetype size_type;
264 typedef T value_type;
265 typedef value_type *pointer;
266 typedef const value_type *const_pointer;
267 typedef value_type &reference;
268 typedef const value_type &const_reference;
269 typedef qptrdiff difference_type;
270
271 typedef T *iterator;
272 typedef const T *const_iterator;
273 typedef std::reverse_iterator<iterator> reverse_iterator;
274 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
275
276 inline iterator begin() { return ptr; }
277 inline const_iterator begin() const { return ptr; }
278 inline const_iterator cbegin() const { return ptr; }
279 inline const_iterator constBegin() const { return ptr; }
280 inline iterator end() { return ptr + s; }
281 inline const_iterator end() const { return ptr + s; }
282 inline const_iterator cend() const { return ptr + s; }
283 inline const_iterator constEnd() const { return ptr + s; }
284 reverse_iterator rbegin() { return reverse_iterator(end()); }
285 reverse_iterator rend() { return reverse_iterator(begin()); }
286 const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
287 const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
288 const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }
289 const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }
290 iterator insert(const_iterator before, qsizetype n, const T &x);
291 iterator insert(const_iterator before, T &&x);
292 inline iterator insert(const_iterator before, const T &x) { return insert(before, 1, x); }
293 iterator erase(const_iterator begin, const_iterator end);
294 inline iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
295
296 // STL compatibility:
297 inline bool empty() const { return isEmpty(); }
298 inline void push_back(const T &t) { append(t); }
299 void push_back(T &&t) { append(std::move(t)); }
300 inline void pop_back() { removeLast(); }
301 inline T &front() { return first(); }
302 inline const T &front() const { return first(); }
303 inline T &back() { return last(); }
304 inline const T &back() const { return last(); }
305 void shrink_to_fit() { squeeze(); }
306
307#ifdef Q_QDOC
308 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
309 friend inline bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
310 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
311 friend inline bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
312 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
313 friend inline bool operator< (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
314 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
315 friend inline bool operator> (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
316 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
317 friend inline bool operator<=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
318 template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
319 friend inline bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
320#else
321 template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
322 QTypeTraits::compare_eq_result<U> operator==(const QVarLengthArray<T, Prealloc> &l, const QVarLengthArray<T, Prealloc2> &r)
323 {
324 if (l.size() != r.size())
325 return false;
326 const T *rb = r.begin();
327 const T *b = l.begin();
328 const T *e = l.end();
329 return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(rb, r.size()));
330 }
331
332 template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
333 QTypeTraits::compare_eq_result<U> operator!=(const QVarLengthArray<T, Prealloc> &l, const QVarLengthArray<T, Prealloc2> &r)
334 {
335 return !(l == r);
336 }
337
338 template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
339 QTypeTraits::compare_lt_result<U> operator<(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
340 noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
341 rhs.begin(), rhs.end())))
342 {
343 return std::lexicographical_compare(lhs.begin(), lhs.end(),
344 rhs.begin(), rhs.end());
345 }
346
347 template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
348 QTypeTraits::compare_lt_result<U> operator>(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
349 noexcept(noexcept(lhs < rhs))
350 {
351 return rhs < lhs;
352 }
353
354 template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
355 QTypeTraits::compare_lt_result<U> operator<=(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
356 noexcept(noexcept(lhs < rhs))
357 {
358 return !(lhs > rhs);
359 }
360
361 template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
362 QTypeTraits::compare_lt_result<U> operator>=(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
363 noexcept(noexcept(lhs < rhs))
364 {
365 return !(lhs < rhs);
366 }
367#endif
368
369private:
370 void reallocate(qsizetype size, qsizetype alloc);
371
372 qsizetype a; // capacity
373 qsizetype s; // size
374 T *ptr; // data
375 std::aligned_storage_t<sizeof(T), alignof(T)> array[Prealloc];
376
377 bool isValidIterator(const const_iterator &i) const
378 {
379 const std::less<const T *> less = {};
380 return !less(cend(), i) && !less(i, cbegin());
381 }
382};
383
384#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
385template <typename InputIterator,
386 typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
387 QtPrivate::IfIsInputIterator<InputIterator> = true>
388QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray<ValueType>;
389#endif
390
391template <class T, qsizetype Prealloc>
392Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype asize)
393 : s(asize) {
394 static_assert(Prealloc > 0, "QVarLengthArray Prealloc must be greater than 0.");
395 Q_ASSERT_X(s >= 0, "QVarLengthArray::QVarLengthArray()", "Size must be greater than or equal to 0.");
396 if (s > Prealloc) {
397 ptr = reinterpret_cast<T *>(malloc(s * sizeof(T)));
398 Q_CHECK_PTR(ptr);
399 a = s;
400 } else {
401 ptr = reinterpret_cast<T *>(array);
402 a = Prealloc;
403 }
404 if (QTypeInfo<T>::isComplex) {
405 T *i = ptr + s;
406 while (i != ptr)
407 new (--i) T;
408 }
409}
410
411template <class T, qsizetype Prealloc>
412Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::resize(qsizetype asize)
413{ reallocate(asize, qMax(asize, a)); }
414
415template <class T, qsizetype Prealloc>
416Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(qsizetype asize)
417{ if (asize > a) reallocate(s, asize); }
418
419template <class T, qsizetype Prealloc>
420template <typename AT>
421Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::indexOf(const AT &t, qsizetype from) const
422{
423 if (from < 0)
424 from = qMax(from + s, qsizetype(0));
425 if (from < s) {
426 T *n = ptr + from - 1;
427 T *e = ptr + s;
428 while (++n != e)
429 if (*n == t)
430 return n - ptr;
431 }
432 return -1;
433}
434
435template <class T, qsizetype Prealloc>
436template <typename AT>
437Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const AT &t, qsizetype from) const
438{
439 if (from < 0)
440 from += s;
441 else if (from >= s)
442 from = s - 1;
443 if (from >= 0) {
444 T *b = ptr;
445 T *n = ptr + from + 1;
446 while (n != b) {
447 if (*--n == t)
448 return n - b;
449 }
450 }
451 return -1;
452}
453
454template <class T, qsizetype Prealloc>
455template <typename AT>
456Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const AT &t) const
457{
458 T *b = ptr;
459 T *i = ptr + s;
460 while (i != b) {
461 if (*--i == t)
462 return true;
463 }
464 return false;
465}
466
467template <class T, qsizetype Prealloc>
468Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, qsizetype increment)
469{
470 Q_ASSERT(abuf);
471 if (increment <= 0)
472 return;
473
474 const qsizetype asize = s + increment;
475
476 if (asize >= a)
477 reallocate(s, qMax(s * 2, asize));
478
479 if constexpr (QTypeInfo<T>::isComplex)
480 std::uninitialized_copy_n(abuf, increment, ptr + s);
481 else
482 memcpy(static_cast<void *>(&ptr[s]), static_cast<const void *>(abuf), increment * sizeof(T));
483
484 s = asize;
485}
486
487template <class T, qsizetype Prealloc>
488Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::squeeze()
489{ reallocate(s, s); }
490
491template <class T, qsizetype Prealloc>
492Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reallocate(qsizetype asize, qsizetype aalloc)
493{
494 Q_ASSERT(aalloc >= asize);
495 Q_ASSERT(ptr);
496 T *oldPtr = ptr;
497 qsizetype osize = s;
498
499 const qsizetype copySize = qMin(asize, osize);
500 Q_ASSUME(copySize >= 0);
501 if (aalloc != a) {
502 if (aalloc > Prealloc) {
503 T *newPtr = reinterpret_cast<T *>(malloc(aalloc * sizeof(T)));
504 Q_CHECK_PTR(newPtr); // could throw
505 // by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here
506 ptr = newPtr;
507 a = aalloc;
508 } else {
509 ptr = reinterpret_cast<T *>(array);
510 a = Prealloc;
511 }
512 s = 0;
513 if (!QTypeInfo<T>::isRelocatable) {
514 QT_TRY {
515 // move all the old elements
516 while (s < copySize) {
517 new (ptr+s) T(std::move(*(oldPtr+s)));
518 (oldPtr+s)->~T();
519 s++;
520 }
521 } QT_CATCH(...) {
522 // clean up all the old objects and then free the old ptr
523 qsizetype sClean = s;
524 while (sClean < osize)
525 (oldPtr+(sClean++))->~T();
526 if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
527 free(oldPtr);
528 QT_RETHROW;
529 }
530 } else {
531 memcpy(static_cast<void *>(ptr), static_cast<const void *>(oldPtr), copySize * sizeof(T));
532 }
533 }
534 s = copySize;
535
536 // destroy remaining old objects
537 if constexpr (QTypeInfo<T>::isComplex) {
538 if (osize > asize)
539 std::destroy(oldPtr + asize, oldPtr + osize);
540 }
541
542 if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
543 free(oldPtr);
544
545 if (QTypeInfo<T>::isComplex) {
546 // call default constructor for new objects (which can throw)
547 while (s < asize)
548 new (ptr+(s++)) T;
549 } else {
550 s = asize;
551 }
552}
553
554template <class T, qsizetype Prealloc>
555Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(qsizetype i) const
556{
557 if (size_t(i) >= size_t(size()))
558 return T();
559 return at(i);
560}
561template <class T, qsizetype Prealloc>
562Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(qsizetype i, const T &defaultValue) const
563{
564 return (size_t(i) >= size_t(size())) ? defaultValue : at(i);
565}
566
567template <class T, qsizetype Prealloc>
568inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, T &&t)
569{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
570 insert(cbegin() + i, std::move(t)); }
571template <class T, qsizetype Prealloc>
572inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, const T &t)
573{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
574 insert(begin() + i, 1, t); }
575template <class T, qsizetype Prealloc>
576inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, qsizetype n, const T &t)
577{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
578 insert(begin() + i, n, t); }
579template <class T, qsizetype Prealloc>
580inline void QVarLengthArray<T, Prealloc>::remove(qsizetype i, qsizetype n)
581{ Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= s, "QVarLengthArray::remove", "index out of range");
582 erase(begin() + i, begin() + i + n); }
583template <class T, qsizetype Prealloc>
584inline void QVarLengthArray<T, Prealloc>::remove(qsizetype i)
585{ Q_ASSERT_X(i >= 0 && i < s, "QVarLengthArray::remove", "index out of range");
586 erase(begin() + i, begin() + i + 1); }
587template <class T, qsizetype Prealloc>
588template <typename AT>
589inline qsizetype QVarLengthArray<T, Prealloc>::removeAll(const AT &t)
590{ return QtPrivate::sequential_erase_with_copy(*this, t); }
591template <class T, qsizetype Prealloc>
592template <typename AT>
593inline bool QVarLengthArray<T, Prealloc>::removeOne(const AT &t)
594{ return QtPrivate::sequential_erase_one(*this, t); }
595template <class T, qsizetype Prealloc>
596template <typename Predicate>
597inline qsizetype QVarLengthArray<T, Prealloc>::removeIf(Predicate pred)
598{ return QtPrivate::sequential_erase_if(*this, pred); }
599template <class T, qsizetype Prealloc>
600inline void QVarLengthArray<T, Prealloc>::prepend(T &&t)
601{ insert(cbegin(), std::move(t)); }
602template <class T, qsizetype Prealloc>
603inline void QVarLengthArray<T, Prealloc>::prepend(const T &t)
604{ insert(begin(), 1, t); }
605
606template <class T, qsizetype Prealloc>
607inline void QVarLengthArray<T, Prealloc>::replace(qsizetype i, const T &t)
608{
609 Q_ASSERT_X(i >= 0 && i < s, "QVarLengthArray::replace", "index out of range");
610 const T copy(t);
611 data()[i] = copy;
612}
613
614template <class T, qsizetype Prealloc>
615Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&t)
616{
617 Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
618
619 qsizetype offset = qsizetype(before - ptr);
620 reserve(s + 1);
621 if (!QTypeInfo<T>::isRelocatable) {
622 T *b = ptr + offset;
623 T *i = ptr + s;
624 T *j = i + 1;
625 // The new end-element needs to be constructed, the rest must be move assigned
626 if (i != b) {
627 new (--j) T(std::move(*--i));
628 while (i != b)
629 *--j = std::move(*--i);
630 *b = std::move(t);
631 } else {
632 new (b) T(std::move(t));
633 }
634 } else {
635 T *b = ptr + offset;
636 memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (s - offset) * sizeof(T));
637 new (b) T(std::move(t));
638 }
639 s += 1;
640 return ptr + offset;
641}
642
643template <class T, qsizetype Prealloc>
644Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, size_type n, const T &t)
645{
646 Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
647
648 qsizetype offset = qsizetype(before - ptr);
649 if (n != 0) {
650 resize(s + n);
651 const T copy(t);
652 if (!QTypeInfo<T>::isRelocatable) {
653 T *b = ptr + offset;
654 T *j = ptr + s;
655 T *i = j - n;
656 while (i != b)
657 *--j = *--i;
658 i = b + n;
659 while (i != b)
660 *--i = copy;
661 } else {
662 T *b = ptr + offset;
663 T *i = b + n;
664 memmove(static_cast<void *>(i), static_cast<const void *>(b), (s - offset - n) * sizeof(T));
665 while (i != b)
666 new (--i) T(copy);
667 }
668 }
669 return ptr + offset;
670}
671
672template <class T, qsizetype Prealloc>
673Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator abegin, const_iterator aend)
674{
675 Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::insert", "The specified const_iterator argument 'abegin' is invalid");
676 Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::insert", "The specified const_iterator argument 'aend' is invalid");
677
678 qsizetype f = qsizetype(abegin - ptr);
679 qsizetype l = qsizetype(aend - ptr);
680 qsizetype n = l - f;
681
682 if constexpr (QTypeInfo<T>::isComplex) {
683 std::move(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f));
684 std::destroy(ptr + s - n, ptr + s);
685 } else {
686 memmove(static_cast<void *>(ptr + f), static_cast<const void *>(ptr + l), (s - l) * sizeof(T));
687 }
688 s -= n;
689 return ptr + f;
690}
691
692#ifdef Q_QDOC
693// Fake definitions for qdoc, only the redeclaration is used.
694template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
695bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
696{ return bool{}; }
697template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
698bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
699{ return bool{}; }
700template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
701bool operator< (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
702{ return bool{}; }
703template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
704bool operator> (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
705{ return bool{}; }
706template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
707bool operator<=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
708{ return bool{}; }
709template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
710bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
711{ return bool{}; }
712#endif
713
714template <typename T, qsizetype Prealloc>
715size_t qHash(const QVarLengthArray<T, Prealloc> &key, size_t seed = 0)
716 noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
717{
718 return qHashRange(key.cbegin(), key.cend(), seed);
719}
720
721template <typename T, qsizetype Prealloc, typename AT>
722qsizetype erase(QVarLengthArray<T, Prealloc> &array, const AT &t)
723{
724 return QtPrivate::sequential_erase(array, t);
725}
726
727template <typename T, qsizetype Prealloc, typename Predicate>
728qsizetype erase_if(QVarLengthArray<T, Prealloc> &array, Predicate pred)
729{
730 return QtPrivate::sequential_erase_if(array, pred);
731}
732
733QT_END_NAMESPACE
734
735#endif // QVARLENGTHARRAY_H
736