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