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