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 QLIST_H |
41 | #define QLIST_H |
42 | |
43 | #include <QtCore/qalgorithms.h> |
44 | #include <QtCore/qiterator.h> |
45 | #include <QtCore/qrefcount.h> |
46 | #include <QtCore/qarraydata.h> |
47 | #include <QtCore/qhashfunctions.h> |
48 | |
49 | #include <iterator> |
50 | #include <list> |
51 | #include <algorithm> |
52 | #ifdef Q_COMPILER_INITIALIZER_LISTS |
53 | #include <initializer_list> |
54 | #endif |
55 | |
56 | #include <stdlib.h> |
57 | #include <new> |
58 | #include <limits.h> |
59 | #include <string.h> |
60 | |
61 | #ifdef Q_CC_MSVC |
62 | #pragma warning( push ) |
63 | #pragma warning( disable : 4127 ) // "conditional expression is constant" |
64 | #endif |
65 | |
66 | QT_BEGIN_NAMESPACE |
67 | |
68 | |
69 | template <typename T> class QVector; |
70 | template <typename T> class QSet; |
71 | |
72 | template <typename T> struct QListSpecialMethods |
73 | { |
74 | protected: |
75 | ~QListSpecialMethods() {} |
76 | }; |
77 | template <> struct QListSpecialMethods<QByteArray>; |
78 | template <> struct QListSpecialMethods<QString>; |
79 | |
80 | struct Q_CORE_EXPORT QListData { |
81 | // tags for tag-dispatching of QList implementations, |
82 | // based on QList's three different memory layouts: |
83 | struct NotArrayCompatibleLayout {}; |
84 | struct NotIndirectLayout {}; |
85 | struct ArrayCompatibleLayout : NotIndirectLayout {}; // data laid out like a C array |
86 | struct InlineWithPaddingLayout : NotArrayCompatibleLayout, NotIndirectLayout {}; // data laid out like a C array with padding |
87 | struct IndirectLayout : NotArrayCompatibleLayout {}; // data allocated on the heap |
88 | |
89 | struct Data { |
90 | QtPrivate::RefCount ref; |
91 | int alloc, begin, end; |
92 | void *array[1]; |
93 | }; |
94 | enum { = sizeof(Data) - sizeof(void *) }; |
95 | |
96 | Data *detach(int alloc); |
97 | Data *detach_grow(int *i, int n); |
98 | void realloc(int alloc); |
99 | void realloc_grow(int growth); |
100 | inline void dispose() { dispose(d); } |
101 | static void dispose(Data *d); |
102 | static const Data shared_null; |
103 | Data *d; |
104 | void **erase(void **xi); |
105 | void **append(int n); |
106 | void **append(); |
107 | void **append(const QListData &l); |
108 | void **prepend(); |
109 | void **insert(int i); |
110 | void remove(int i); |
111 | void remove(int i, int n); |
112 | void move(int from, int to); |
113 | inline int size() const Q_DECL_NOTHROW { return d->end - d->begin; } |
114 | inline bool isEmpty() const Q_DECL_NOTHROW { return d->end == d->begin; } |
115 | inline void **at(int i) const Q_DECL_NOTHROW { return d->array + d->begin + i; } |
116 | inline void **begin() const Q_DECL_NOTHROW { return d->array + d->begin; } |
117 | inline void **end() const Q_DECL_NOTHROW { return d->array + d->end; } |
118 | }; |
119 | |
120 | template <typename T> |
121 | class QList |
122 | #ifndef Q_QDOC |
123 | : public QListSpecialMethods<T> |
124 | #endif |
125 | { |
126 | public: |
127 | struct MemoryLayout |
128 | : std::conditional< |
129 | // must stay isStatic until ### Qt 6 for BC reasons (don't use !isRelocatable)! |
130 | QTypeInfo<T>::isStatic || QTypeInfo<T>::isLarge, |
131 | QListData::IndirectLayout, |
132 | typename std::conditional< |
133 | sizeof(T) == sizeof(void*), |
134 | QListData::ArrayCompatibleLayout, |
135 | QListData::InlineWithPaddingLayout |
136 | >::type>::type {}; |
137 | private: |
138 | struct Node { void *v; |
139 | #if defined(Q_CC_BOR) |
140 | Q_INLINE_TEMPLATE T &t(); |
141 | #else |
142 | Q_INLINE_TEMPLATE T &t() |
143 | { return *reinterpret_cast<T*>(QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic |
144 | ? v : this); } |
145 | #endif |
146 | }; |
147 | |
148 | union { QListData p; QListData::Data *d; }; |
149 | |
150 | public: |
151 | inline QList() Q_DECL_NOTHROW : d(const_cast<QListData::Data *>(&QListData::shared_null)) { } |
152 | QList(const QList<T> &l); |
153 | ~QList(); |
154 | QList<T> &operator=(const QList<T> &l); |
155 | #ifdef Q_COMPILER_RVALUE_REFS |
156 | inline QList(QList<T> &&other) Q_DECL_NOTHROW |
157 | : d(other.d) { other.d = const_cast<QListData::Data *>(&QListData::shared_null); } |
158 | inline QList &operator=(QList<T> &&other) Q_DECL_NOTHROW |
159 | { QList moved(std::move(other)); swap(moved); return *this; } |
160 | #endif |
161 | inline void swap(QList<T> &other) Q_DECL_NOTHROW { qSwap(d, other.d); } |
162 | #ifdef Q_COMPILER_INITIALIZER_LISTS |
163 | inline QList(std::initializer_list<T> args) |
164 | : d(const_cast<QListData::Data *>(&QListData::shared_null)) |
165 | { reserve(int(args.size())); std::copy(args.begin(), args.end(), std::back_inserter(*this)); } |
166 | #endif |
167 | bool operator==(const QList<T> &l) const; |
168 | inline bool operator!=(const QList<T> &l) const { return !(*this == l); } |
169 | |
170 | inline int size() const Q_DECL_NOTHROW { return p.size(); } |
171 | |
172 | inline void detach() { if (d->ref.isShared()) detach_helper(); } |
173 | |
174 | inline void detachShared() |
175 | { |
176 | // The "this->" qualification is needed for GCCE. |
177 | if (d->ref.isShared() && this->d != &QListData::shared_null) |
178 | detach_helper(); |
179 | } |
180 | |
181 | inline bool isDetached() const { return !d->ref.isShared(); } |
182 | #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
183 | inline void setSharable(bool sharable) |
184 | { |
185 | if (sharable == d->ref.isSharable()) |
186 | return; |
187 | if (!sharable) |
188 | detach(); |
189 | if (d != &QListData::shared_null) |
190 | d->ref.setSharable(sharable); |
191 | } |
192 | #endif |
193 | inline bool isSharedWith(const QList<T> &other) const Q_DECL_NOTHROW { return d == other.d; } |
194 | |
195 | inline bool isEmpty() const Q_DECL_NOTHROW { return p.isEmpty(); } |
196 | |
197 | void clear(); |
198 | |
199 | const T &at(int i) const; |
200 | const T &operator[](int i) const; |
201 | T &operator[](int i); |
202 | |
203 | void reserve(int size); |
204 | void append(const T &t); |
205 | void append(const QList<T> &t); |
206 | void prepend(const T &t); |
207 | void insert(int i, const T &t); |
208 | void replace(int i, const T &t); |
209 | void removeAt(int i); |
210 | int removeAll(const T &t); |
211 | bool removeOne(const T &t); |
212 | T takeAt(int i); |
213 | T takeFirst(); |
214 | T takeLast(); |
215 | void move(int from, int to); |
216 | void swap(int i, int j); |
217 | int indexOf(const T &t, int from = 0) const; |
218 | int lastIndexOf(const T &t, int from = -1) const; |
219 | bool contains(const T &t) const; |
220 | int count(const T &t) const; |
221 | |
222 | class const_iterator; |
223 | |
224 | class iterator { |
225 | public: |
226 | Node *i; |
227 | typedef std::random_access_iterator_tag iterator_category; |
228 | // ### Qt6: use int |
229 | typedef qptrdiff difference_type; |
230 | typedef T value_type; |
231 | typedef T *pointer; |
232 | typedef T &reference; |
233 | |
234 | inline iterator() Q_DECL_NOTHROW : i(nullptr) {} |
235 | inline iterator(Node *n) Q_DECL_NOTHROW : i(n) {} |
236 | #if QT_VERSION < QT_VERSION_CHECK(6,0,0) |
237 | // can't remove it in Qt 5, since doing so would make the type trivial, |
238 | // which changes the way it's passed to functions by value. |
239 | inline iterator(const iterator &o) Q_DECL_NOTHROW : i(o.i){} |
240 | #endif |
241 | inline T &operator*() const { return i->t(); } |
242 | inline T *operator->() const { return &i->t(); } |
243 | inline T &operator[](difference_type j) const { return i[j].t(); } |
244 | inline bool operator==(const iterator &o) const Q_DECL_NOTHROW { return i == o.i; } |
245 | inline bool operator!=(const iterator &o) const Q_DECL_NOTHROW { return i != o.i; } |
246 | inline bool operator<(const iterator& other) const Q_DECL_NOTHROW { return i < other.i; } |
247 | inline bool operator<=(const iterator& other) const Q_DECL_NOTHROW { return i <= other.i; } |
248 | inline bool operator>(const iterator& other) const Q_DECL_NOTHROW { return i > other.i; } |
249 | inline bool operator>=(const iterator& other) const Q_DECL_NOTHROW { return i >= other.i; } |
250 | #ifndef QT_STRICT_ITERATORS |
251 | inline bool operator==(const const_iterator &o) const Q_DECL_NOTHROW |
252 | { return i == o.i; } |
253 | inline bool operator!=(const const_iterator &o) const Q_DECL_NOTHROW |
254 | { return i != o.i; } |
255 | inline bool operator<(const const_iterator& other) const Q_DECL_NOTHROW |
256 | { return i < other.i; } |
257 | inline bool operator<=(const const_iterator& other) const Q_DECL_NOTHROW |
258 | { return i <= other.i; } |
259 | inline bool operator>(const const_iterator& other) const Q_DECL_NOTHROW |
260 | { return i > other.i; } |
261 | inline bool operator>=(const const_iterator& other) const Q_DECL_NOTHROW |
262 | { return i >= other.i; } |
263 | #endif |
264 | inline iterator &operator++() { ++i; return *this; } |
265 | inline iterator operator++(int) { Node *n = i; ++i; return n; } |
266 | inline iterator &operator--() { i--; return *this; } |
267 | inline iterator operator--(int) { Node *n = i; i--; return n; } |
268 | inline iterator &operator+=(difference_type j) { i+=j; return *this; } |
269 | inline iterator &operator-=(difference_type j) { i-=j; return *this; } |
270 | inline iterator operator+(difference_type j) const { return iterator(i+j); } |
271 | inline iterator operator-(difference_type j) const { return iterator(i-j); } |
272 | friend inline iterator operator+(difference_type j, iterator k) { return k + j; } |
273 | inline int operator-(iterator j) const { return int(i - j.i); } |
274 | }; |
275 | friend class iterator; |
276 | |
277 | class const_iterator { |
278 | public: |
279 | Node *i; |
280 | typedef std::random_access_iterator_tag iterator_category; |
281 | // ### Qt6: use int |
282 | typedef qptrdiff difference_type; |
283 | typedef T value_type; |
284 | typedef const T *pointer; |
285 | typedef const T &reference; |
286 | |
287 | inline const_iterator() Q_DECL_NOTHROW : i(nullptr) {} |
288 | inline const_iterator(Node *n) Q_DECL_NOTHROW : i(n) {} |
289 | #if QT_VERSION < QT_VERSION_CHECK(6,0,0) |
290 | // can't remove it in Qt 5, since doing so would make the type trivial, |
291 | // which changes the way it's passed to functions by value. |
292 | inline const_iterator(const const_iterator &o) Q_DECL_NOTHROW : i(o.i) {} |
293 | #endif |
294 | #ifdef QT_STRICT_ITERATORS |
295 | inline explicit const_iterator(const iterator &o) Q_DECL_NOTHROW : i(o.i) {} |
296 | #else |
297 | inline const_iterator(const iterator &o) Q_DECL_NOTHROW : i(o.i) {} |
298 | #endif |
299 | inline const T &operator*() const { return i->t(); } |
300 | inline const T *operator->() const { return &i->t(); } |
301 | inline const T &operator[](difference_type j) const { return i[j].t(); } |
302 | inline bool operator==(const const_iterator &o) const Q_DECL_NOTHROW { return i == o.i; } |
303 | inline bool operator!=(const const_iterator &o) const Q_DECL_NOTHROW { return i != o.i; } |
304 | inline bool operator<(const const_iterator& other) const Q_DECL_NOTHROW { return i < other.i; } |
305 | inline bool operator<=(const const_iterator& other) const Q_DECL_NOTHROW { return i <= other.i; } |
306 | inline bool operator>(const const_iterator& other) const Q_DECL_NOTHROW { return i > other.i; } |
307 | inline bool operator>=(const const_iterator& other) const Q_DECL_NOTHROW { return i >= other.i; } |
308 | inline const_iterator &operator++() { ++i; return *this; } |
309 | inline const_iterator operator++(int) { Node *n = i; ++i; return n; } |
310 | inline const_iterator &operator--() { i--; return *this; } |
311 | inline const_iterator operator--(int) { Node *n = i; i--; return n; } |
312 | inline const_iterator &operator+=(difference_type j) { i+=j; return *this; } |
313 | inline const_iterator &operator-=(difference_type j) { i-=j; return *this; } |
314 | inline const_iterator operator+(difference_type j) const { return const_iterator(i+j); } |
315 | inline const_iterator operator-(difference_type j) const { return const_iterator(i-j); } |
316 | friend inline const_iterator operator+(difference_type j, const_iterator k) { return k + j; } |
317 | inline int operator-(const_iterator j) const { return int(i - j.i); } |
318 | }; |
319 | friend class const_iterator; |
320 | |
321 | // stl style |
322 | typedef std::reverse_iterator<iterator> reverse_iterator; |
323 | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; |
324 | inline iterator begin() { detach(); return reinterpret_cast<Node *>(p.begin()); } |
325 | inline const_iterator begin() const Q_DECL_NOTHROW { return reinterpret_cast<Node *>(p.begin()); } |
326 | inline const_iterator cbegin() const Q_DECL_NOTHROW { return reinterpret_cast<Node *>(p.begin()); } |
327 | inline const_iterator constBegin() const Q_DECL_NOTHROW { return reinterpret_cast<Node *>(p.begin()); } |
328 | inline iterator end() { detach(); return reinterpret_cast<Node *>(p.end()); } |
329 | inline const_iterator end() const Q_DECL_NOTHROW { return reinterpret_cast<Node *>(p.end()); } |
330 | inline const_iterator cend() const Q_DECL_NOTHROW { return reinterpret_cast<Node *>(p.end()); } |
331 | inline const_iterator constEnd() const Q_DECL_NOTHROW { return reinterpret_cast<Node *>(p.end()); } |
332 | reverse_iterator rbegin() { return reverse_iterator(end()); } |
333 | reverse_iterator rend() { return reverse_iterator(begin()); } |
334 | const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } |
335 | const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } |
336 | const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } |
337 | const_reverse_iterator crend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } |
338 | iterator insert(iterator before, const T &t); |
339 | iterator erase(iterator pos); |
340 | iterator erase(iterator first, iterator last); |
341 | |
342 | // more Qt |
343 | typedef iterator Iterator; |
344 | typedef const_iterator ConstIterator; |
345 | inline int count() const { return p.size(); } |
346 | inline int length() const { return p.size(); } // Same as count() |
347 | inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); } |
348 | inline const T& constFirst() const { return first(); } |
349 | inline const T& first() const { Q_ASSERT(!isEmpty()); return at(0); } |
350 | T& last() { Q_ASSERT(!isEmpty()); return *(--end()); } |
351 | const T& last() const { Q_ASSERT(!isEmpty()); return at(count() - 1); } |
352 | inline const T& constLast() const { return last(); } |
353 | inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(begin()); } |
354 | inline void removeLast() { Q_ASSERT(!isEmpty()); erase(--end()); } |
355 | inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; } |
356 | inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; } |
357 | QList<T> mid(int pos, int length = -1) const; |
358 | |
359 | T value(int i) const; |
360 | T value(int i, const T &defaultValue) const; |
361 | |
362 | // stl compatibility |
363 | inline void push_back(const T &t) { append(t); } |
364 | inline void push_front(const T &t) { prepend(t); } |
365 | inline T& front() { return first(); } |
366 | inline const T& front() const { return first(); } |
367 | inline T& back() { return last(); } |
368 | inline const T& back() const { return last(); } |
369 | inline void pop_front() { removeFirst(); } |
370 | inline void pop_back() { removeLast(); } |
371 | inline bool empty() const { return isEmpty(); } |
372 | typedef int size_type; |
373 | typedef T value_type; |
374 | typedef value_type *pointer; |
375 | typedef const value_type *const_pointer; |
376 | typedef value_type &reference; |
377 | typedef const value_type &const_reference; |
378 | // ### Qt6: use int |
379 | typedef qptrdiff difference_type; |
380 | |
381 | // comfort |
382 | QList<T> &operator+=(const QList<T> &l); |
383 | inline QList<T> operator+(const QList<T> &l) const |
384 | { QList n = *this; n += l; return n; } |
385 | inline QList<T> &operator+=(const T &t) |
386 | { append(t); return *this; } |
387 | inline QList<T> &operator<< (const T &t) |
388 | { append(t); return *this; } |
389 | inline QList<T> &operator<<(const QList<T> &l) |
390 | { *this += l; return *this; } |
391 | |
392 | QVector<T> toVector() const; |
393 | QSet<T> toSet() const; |
394 | |
395 | static QList<T> fromVector(const QVector<T> &vector); |
396 | static QList<T> fromSet(const QSet<T> &set); |
397 | |
398 | static inline QList<T> fromStdList(const std::list<T> &list) |
399 | { QList<T> tmp; std::copy(list.begin(), list.end(), std::back_inserter(tmp)); return tmp; } |
400 | inline std::list<T> toStdList() const |
401 | { std::list<T> tmp; std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; } |
402 | |
403 | private: |
404 | Node *detach_helper_grow(int i, int n); |
405 | void detach_helper(int alloc); |
406 | void detach_helper(); |
407 | void dealloc(QListData::Data *d); |
408 | |
409 | void node_construct(Node *n, const T &t); |
410 | void node_destruct(Node *n); |
411 | void node_copy(Node *from, Node *to, Node *src); |
412 | void node_destruct(Node *from, Node *to); |
413 | |
414 | bool isValidIterator(const iterator &i) const Q_DECL_NOTHROW |
415 | { |
416 | const std::less<const Node *> less = {}; |
417 | return !less(i.i, cbegin().i) && !less(cend().i, i.i); |
418 | } |
419 | |
420 | private: |
421 | inline bool op_eq_impl(const QList &other, QListData::NotArrayCompatibleLayout) const; |
422 | inline bool op_eq_impl(const QList &other, QListData::ArrayCompatibleLayout) const; |
423 | inline bool contains_impl(const T &, QListData::NotArrayCompatibleLayout) const; |
424 | inline bool contains_impl(const T &, QListData::ArrayCompatibleLayout) const; |
425 | inline int count_impl(const T &, QListData::NotArrayCompatibleLayout) const; |
426 | inline int count_impl(const T &, QListData::ArrayCompatibleLayout) const; |
427 | }; |
428 | |
429 | #if defined(Q_CC_BOR) |
430 | template <typename T> |
431 | Q_INLINE_TEMPLATE T &QList<T>::Node::t() |
432 | { return QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic ? *(T*)v:*(T*)this; } |
433 | #endif |
434 | |
435 | template <typename T> |
436 | Q_INLINE_TEMPLATE void QList<T>::node_construct(Node *n, const T &t) |
437 | { |
438 | if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) n->v = new T(t); |
439 | else if (QTypeInfo<T>::isComplex) new (n) T(t); |
440 | #if (defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__IBMCPP__)) && !defined(__OPTIMIZE__) |
441 | // This violates pointer aliasing rules, but it is known to be safe (and silent) |
442 | // in unoptimized GCC builds (-fno-strict-aliasing). The other compilers which |
443 | // set the same define are assumed to be safe. |
444 | else *reinterpret_cast<T*>(n) = t; |
445 | #else |
446 | // This is always safe, but penaltizes unoptimized builds a lot. |
447 | else ::memcpy(n, static_cast<const void *>(&t), sizeof(T)); |
448 | #endif |
449 | } |
450 | |
451 | template <typename T> |
452 | Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *n) |
453 | { |
454 | if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) delete reinterpret_cast<T*>(n->v); |
455 | else if (QTypeInfo<T>::isComplex) reinterpret_cast<T*>(n)->~T(); |
456 | } |
457 | |
458 | template <typename T> |
459 | Q_INLINE_TEMPLATE void QList<T>::node_copy(Node *from, Node *to, Node *src) |
460 | { |
461 | Node *current = from; |
462 | if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { |
463 | QT_TRY { |
464 | while(current != to) { |
465 | current->v = new T(*reinterpret_cast<T*>(src->v)); |
466 | ++current; |
467 | ++src; |
468 | } |
469 | } QT_CATCH(...) { |
470 | while (current-- != from) |
471 | delete reinterpret_cast<T*>(current->v); |
472 | QT_RETHROW; |
473 | } |
474 | |
475 | } else if (QTypeInfo<T>::isComplex) { |
476 | QT_TRY { |
477 | while(current != to) { |
478 | new (current) T(*reinterpret_cast<T*>(src)); |
479 | ++current; |
480 | ++src; |
481 | } |
482 | } QT_CATCH(...) { |
483 | while (current-- != from) |
484 | (reinterpret_cast<T*>(current))->~T(); |
485 | QT_RETHROW; |
486 | } |
487 | } else { |
488 | if (src != from && to - from > 0) |
489 | memcpy(from, src, (to - from) * sizeof(Node)); |
490 | } |
491 | } |
492 | |
493 | template <typename T> |
494 | Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *from, Node *to) |
495 | { |
496 | if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) |
497 | while(from != to) --to, delete reinterpret_cast<T*>(to->v); |
498 | else if (QTypeInfo<T>::isComplex) |
499 | while (from != to) --to, reinterpret_cast<T*>(to)->~T(); |
500 | } |
501 | |
502 | template <typename T> |
503 | Q_INLINE_TEMPLATE QList<T> &QList<T>::operator=(const QList<T> &l) |
504 | { |
505 | if (d != l.d) { |
506 | QList<T> tmp(l); |
507 | tmp.swap(*this); |
508 | } |
509 | return *this; |
510 | } |
511 | template <typename T> |
512 | inline typename QList<T>::iterator QList<T>::insert(iterator before, const T &t) |
513 | { |
514 | Q_ASSERT_X(isValidIterator(before), "QList::insert" , "The specified iterator argument 'before' is invalid" ); |
515 | |
516 | int iBefore = int(before.i - reinterpret_cast<Node *>(p.begin())); |
517 | Node *n = 0; |
518 | if (d->ref.isShared()) |
519 | n = detach_helper_grow(iBefore, 1); |
520 | else |
521 | n = reinterpret_cast<Node *>(p.insert(iBefore)); |
522 | QT_TRY { |
523 | node_construct(n, t); |
524 | } QT_CATCH(...) { |
525 | p.remove(iBefore); |
526 | QT_RETHROW; |
527 | } |
528 | return n; |
529 | } |
530 | template <typename T> |
531 | inline typename QList<T>::iterator QList<T>::erase(iterator it) |
532 | { |
533 | Q_ASSERT_X(isValidIterator(it), "QList::erase" , "The specified iterator argument 'it' is invalid" ); |
534 | if (d->ref.isShared()) { |
535 | int offset = int(it.i - reinterpret_cast<Node *>(p.begin())); |
536 | it = begin(); // implies detach() |
537 | it += offset; |
538 | } |
539 | node_destruct(it.i); |
540 | return reinterpret_cast<Node *>(p.erase(reinterpret_cast<void**>(it.i))); |
541 | } |
542 | template <typename T> |
543 | inline const T &QList<T>::at(int i) const |
544 | { Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::at" , "index out of range" ); |
545 | return reinterpret_cast<Node *>(p.at(i))->t(); } |
546 | template <typename T> |
547 | inline const T &QList<T>::operator[](int i) const |
548 | { Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::operator[]" , "index out of range" ); |
549 | return reinterpret_cast<Node *>(p.at(i))->t(); } |
550 | template <typename T> |
551 | inline T &QList<T>::operator[](int i) |
552 | { Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::operator[]" , "index out of range" ); |
553 | detach(); return reinterpret_cast<Node *>(p.at(i))->t(); } |
554 | template <typename T> |
555 | inline void QList<T>::removeAt(int i) |
556 | { if(i >= 0 && i < p.size()) { detach(); |
557 | node_destruct(reinterpret_cast<Node *>(p.at(i))); p.remove(i); } } |
558 | template <typename T> |
559 | inline T QList<T>::takeAt(int i) |
560 | { Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::take" , "index out of range" ); |
561 | detach(); Node *n = reinterpret_cast<Node *>(p.at(i)); T t = std::move(n->t()); node_destruct(n); |
562 | p.remove(i); return t; } |
563 | template <typename T> |
564 | inline T QList<T>::takeFirst() |
565 | { T t = std::move(first()); removeFirst(); return t; } |
566 | template <typename T> |
567 | inline T QList<T>::takeLast() |
568 | { T t = std::move(last()); removeLast(); return t; } |
569 | |
570 | template <typename T> |
571 | Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc) |
572 | { |
573 | if (d->alloc < alloc) { |
574 | if (d->ref.isShared()) |
575 | detach_helper(alloc); |
576 | else |
577 | p.realloc(alloc); |
578 | } |
579 | } |
580 | |
581 | template <typename T> |
582 | Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t) |
583 | { |
584 | if (d->ref.isShared()) { |
585 | Node *n = detach_helper_grow(INT_MAX, 1); |
586 | QT_TRY { |
587 | node_construct(n, t); |
588 | } QT_CATCH(...) { |
589 | --d->end; |
590 | QT_RETHROW; |
591 | } |
592 | } else { |
593 | if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { |
594 | Node *n = reinterpret_cast<Node *>(p.append()); |
595 | QT_TRY { |
596 | node_construct(n, t); |
597 | } QT_CATCH(...) { |
598 | --d->end; |
599 | QT_RETHROW; |
600 | } |
601 | } else { |
602 | Node *n, copy; |
603 | node_construct(©, t); // t might be a reference to an object in the array |
604 | QT_TRY { |
605 | n = reinterpret_cast<Node *>(p.append());; |
606 | } QT_CATCH(...) { |
607 | node_destruct(©); |
608 | QT_RETHROW; |
609 | } |
610 | *n = copy; |
611 | } |
612 | } |
613 | } |
614 | |
615 | template <typename T> |
616 | inline void QList<T>::prepend(const T &t) |
617 | { |
618 | if (d->ref.isShared()) { |
619 | Node *n = detach_helper_grow(0, 1); |
620 | QT_TRY { |
621 | node_construct(n, t); |
622 | } QT_CATCH(...) { |
623 | ++d->begin; |
624 | QT_RETHROW; |
625 | } |
626 | } else { |
627 | if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { |
628 | Node *n = reinterpret_cast<Node *>(p.prepend()); |
629 | QT_TRY { |
630 | node_construct(n, t); |
631 | } QT_CATCH(...) { |
632 | ++d->begin; |
633 | QT_RETHROW; |
634 | } |
635 | } else { |
636 | Node *n, copy; |
637 | node_construct(©, t); // t might be a reference to an object in the array |
638 | QT_TRY { |
639 | n = reinterpret_cast<Node *>(p.prepend());; |
640 | } QT_CATCH(...) { |
641 | node_destruct(©); |
642 | QT_RETHROW; |
643 | } |
644 | *n = copy; |
645 | } |
646 | } |
647 | } |
648 | |
649 | template <typename T> |
650 | inline void QList<T>::insert(int i, const T &t) |
651 | { |
652 | if (d->ref.isShared()) { |
653 | Node *n = detach_helper_grow(i, 1); |
654 | QT_TRY { |
655 | node_construct(n, t); |
656 | } QT_CATCH(...) { |
657 | p.remove(i); |
658 | QT_RETHROW; |
659 | } |
660 | } else { |
661 | if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { |
662 | Node *n = reinterpret_cast<Node *>(p.insert(i)); |
663 | QT_TRY { |
664 | node_construct(n, t); |
665 | } QT_CATCH(...) { |
666 | p.remove(i); |
667 | QT_RETHROW; |
668 | } |
669 | } else { |
670 | Node *n, copy; |
671 | node_construct(©, t); // t might be a reference to an object in the array |
672 | QT_TRY { |
673 | n = reinterpret_cast<Node *>(p.insert(i));; |
674 | } QT_CATCH(...) { |
675 | node_destruct(©); |
676 | QT_RETHROW; |
677 | } |
678 | *n = copy; |
679 | } |
680 | } |
681 | } |
682 | |
683 | template <typename T> |
684 | inline void QList<T>::replace(int i, const T &t) |
685 | { |
686 | Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::replace" , "index out of range" ); |
687 | detach(); |
688 | reinterpret_cast<Node *>(p.at(i))->t() = t; |
689 | } |
690 | |
691 | template <typename T> |
692 | inline void QList<T>::swap(int i, int j) |
693 | { |
694 | Q_ASSERT_X(i >= 0 && i < p.size() && j >= 0 && j < p.size(), |
695 | "QList<T>::swap" , "index out of range" ); |
696 | detach(); |
697 | std::swap(d->array[d->begin + i], d->array[d->begin + j]); |
698 | } |
699 | |
700 | template <typename T> |
701 | inline void QList<T>::move(int from, int to) |
702 | { |
703 | Q_ASSERT_X(from >= 0 && from < p.size() && to >= 0 && to < p.size(), |
704 | "QList<T>::move" , "index out of range" ); |
705 | detach(); |
706 | p.move(from, to); |
707 | } |
708 | |
709 | template<typename T> |
710 | Q_OUTOFLINE_TEMPLATE QList<T> QList<T>::mid(int pos, int alength) const |
711 | { |
712 | using namespace QtPrivate; |
713 | switch (QContainerImplHelper::mid(size(), &pos, &alength)) { |
714 | case QContainerImplHelper::Null: |
715 | case QContainerImplHelper::Empty: |
716 | return QList<T>(); |
717 | case QContainerImplHelper::Full: |
718 | return *this; |
719 | case QContainerImplHelper::Subset: |
720 | break; |
721 | } |
722 | |
723 | QList<T> cpy; |
724 | if (alength <= 0) |
725 | return cpy; |
726 | cpy.reserve(alength); |
727 | cpy.d->end = alength; |
728 | QT_TRY { |
729 | cpy.node_copy(reinterpret_cast<Node *>(cpy.p.begin()), |
730 | reinterpret_cast<Node *>(cpy.p.end()), |
731 | reinterpret_cast<Node *>(p.begin() + pos)); |
732 | } QT_CATCH(...) { |
733 | // restore the old end |
734 | cpy.d->end = 0; |
735 | QT_RETHROW; |
736 | } |
737 | return cpy; |
738 | } |
739 | |
740 | template<typename T> |
741 | Q_OUTOFLINE_TEMPLATE T QList<T>::value(int i) const |
742 | { |
743 | if (i < 0 || i >= p.size()) { |
744 | return T(); |
745 | } |
746 | return reinterpret_cast<Node *>(p.at(i))->t(); |
747 | } |
748 | |
749 | template<typename T> |
750 | Q_OUTOFLINE_TEMPLATE T QList<T>::value(int i, const T& defaultValue) const |
751 | { |
752 | return ((i < 0 || i >= p.size()) ? defaultValue : reinterpret_cast<Node *>(p.at(i))->t()); |
753 | } |
754 | |
755 | template <typename T> |
756 | Q_OUTOFLINE_TEMPLATE typename QList<T>::Node *QList<T>::detach_helper_grow(int i, int c) |
757 | { |
758 | Node *n = reinterpret_cast<Node *>(p.begin()); |
759 | QListData::Data *x = p.detach_grow(&i, c); |
760 | QT_TRY { |
761 | node_copy(reinterpret_cast<Node *>(p.begin()), |
762 | reinterpret_cast<Node *>(p.begin() + i), n); |
763 | } QT_CATCH(...) { |
764 | p.dispose(); |
765 | d = x; |
766 | QT_RETHROW; |
767 | } |
768 | QT_TRY { |
769 | node_copy(reinterpret_cast<Node *>(p.begin() + i + c), |
770 | reinterpret_cast<Node *>(p.end()), n + i); |
771 | } QT_CATCH(...) { |
772 | node_destruct(reinterpret_cast<Node *>(p.begin()), |
773 | reinterpret_cast<Node *>(p.begin() + i)); |
774 | p.dispose(); |
775 | d = x; |
776 | QT_RETHROW; |
777 | } |
778 | |
779 | if (!x->ref.deref()) |
780 | dealloc(x); |
781 | |
782 | return reinterpret_cast<Node *>(p.begin() + i); |
783 | } |
784 | |
785 | template <typename T> |
786 | Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper(int alloc) |
787 | { |
788 | Node *n = reinterpret_cast<Node *>(p.begin()); |
789 | QListData::Data *x = p.detach(alloc); |
790 | QT_TRY { |
791 | node_copy(reinterpret_cast<Node *>(p.begin()), reinterpret_cast<Node *>(p.end()), n); |
792 | } QT_CATCH(...) { |
793 | p.dispose(); |
794 | d = x; |
795 | QT_RETHROW; |
796 | } |
797 | |
798 | if (!x->ref.deref()) |
799 | dealloc(x); |
800 | } |
801 | |
802 | template <typename T> |
803 | Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper() |
804 | { |
805 | detach_helper(d->alloc); |
806 | } |
807 | |
808 | template <typename T> |
809 | Q_OUTOFLINE_TEMPLATE QList<T>::QList(const QList<T> &l) |
810 | : QListSpecialMethods<T>(l), d(l.d) |
811 | { |
812 | if (!d->ref.ref()) { |
813 | p.detach(d->alloc); |
814 | |
815 | QT_TRY { |
816 | node_copy(reinterpret_cast<Node *>(p.begin()), |
817 | reinterpret_cast<Node *>(p.end()), |
818 | reinterpret_cast<Node *>(l.p.begin())); |
819 | } QT_CATCH(...) { |
820 | QListData::dispose(d); |
821 | QT_RETHROW; |
822 | } |
823 | } |
824 | } |
825 | |
826 | template <typename T> |
827 | Q_OUTOFLINE_TEMPLATE QList<T>::~QList() |
828 | { |
829 | if (!d->ref.deref()) |
830 | dealloc(d); |
831 | } |
832 | |
833 | template <typename T> |
834 | Q_OUTOFLINE_TEMPLATE bool QList<T>::operator==(const QList<T> &l) const |
835 | { |
836 | if (d == l.d) |
837 | return true; |
838 | if (p.size() != l.p.size()) |
839 | return false; |
840 | return this->op_eq_impl(l, MemoryLayout()); |
841 | } |
842 | |
843 | template <typename T> |
844 | inline bool QList<T>::op_eq_impl(const QList &l, QListData::NotArrayCompatibleLayout) const |
845 | { |
846 | Node *i = reinterpret_cast<Node *>(p.begin()); |
847 | Node *e = reinterpret_cast<Node *>(p.end()); |
848 | Node *li = reinterpret_cast<Node *>(l.p.begin()); |
849 | for (; i != e; ++i, ++li) { |
850 | if (!(i->t() == li->t())) |
851 | return false; |
852 | } |
853 | return true; |
854 | } |
855 | |
856 | template <typename T> |
857 | inline bool QList<T>::op_eq_impl(const QList &l, QListData::ArrayCompatibleLayout) const |
858 | { |
859 | const T *lb = reinterpret_cast<const T*>(l.p.begin()); |
860 | const T *b = reinterpret_cast<const T*>(p.begin()); |
861 | const T *e = reinterpret_cast<const T*>(p.end()); |
862 | return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(lb, l.p.size())); |
863 | } |
864 | |
865 | template <typename T> |
866 | Q_OUTOFLINE_TEMPLATE void QList<T>::dealloc(QListData::Data *data) |
867 | { |
868 | node_destruct(reinterpret_cast<Node *>(data->array + data->begin), |
869 | reinterpret_cast<Node *>(data->array + data->end)); |
870 | QListData::dispose(data); |
871 | } |
872 | |
873 | |
874 | template <typename T> |
875 | Q_OUTOFLINE_TEMPLATE void QList<T>::clear() |
876 | { |
877 | *this = QList<T>(); |
878 | } |
879 | |
880 | template <typename T> |
881 | Q_OUTOFLINE_TEMPLATE int QList<T>::removeAll(const T &_t) |
882 | { |
883 | int index = indexOf(_t); |
884 | if (index == -1) |
885 | return 0; |
886 | |
887 | const T t = _t; |
888 | detach(); |
889 | |
890 | Node *i = reinterpret_cast<Node *>(p.at(index)); |
891 | Node *e = reinterpret_cast<Node *>(p.end()); |
892 | Node *n = i; |
893 | node_destruct(i); |
894 | while (++i != e) { |
895 | if (i->t() == t) |
896 | node_destruct(i); |
897 | else |
898 | *n++ = *i; |
899 | } |
900 | |
901 | int removedCount = int(e - n); |
902 | d->end -= removedCount; |
903 | return removedCount; |
904 | } |
905 | |
906 | template <typename T> |
907 | Q_OUTOFLINE_TEMPLATE bool QList<T>::removeOne(const T &_t) |
908 | { |
909 | int index = indexOf(_t); |
910 | if (index != -1) { |
911 | removeAt(index); |
912 | return true; |
913 | } |
914 | return false; |
915 | } |
916 | |
917 | template <typename T> |
918 | Q_OUTOFLINE_TEMPLATE typename QList<T>::iterator QList<T>::erase(typename QList<T>::iterator afirst, |
919 | typename QList<T>::iterator alast) |
920 | { |
921 | Q_ASSERT_X(isValidIterator(afirst), "QList::erase" , "The specified iterator argument 'afirst' is invalid" ); |
922 | Q_ASSERT_X(isValidIterator(alast), "QList::erase" , "The specified iterator argument 'alast' is invalid" ); |
923 | |
924 | if (d->ref.isShared()) { |
925 | // ### A block is erased and a detach is needed. We should shrink and only copy relevant items. |
926 | int offsetfirst = int(afirst.i - reinterpret_cast<Node *>(p.begin())); |
927 | int offsetlast = int(alast.i - reinterpret_cast<Node *>(p.begin())); |
928 | afirst = begin(); // implies detach() |
929 | alast = afirst; |
930 | afirst += offsetfirst; |
931 | alast += offsetlast; |
932 | } |
933 | |
934 | for (Node *n = afirst.i; n < alast.i; ++n) |
935 | node_destruct(n); |
936 | int idx = afirst - begin(); |
937 | p.remove(idx, alast - afirst); |
938 | return begin() + idx; |
939 | } |
940 | |
941 | template <typename T> |
942 | Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l) |
943 | { |
944 | if (!l.isEmpty()) { |
945 | if (d == &QListData::shared_null) { |
946 | *this = l; |
947 | } else { |
948 | Node *n = (d->ref.isShared()) |
949 | ? detach_helper_grow(INT_MAX, l.size()) |
950 | : reinterpret_cast<Node *>(p.append(l.p)); |
951 | QT_TRY { |
952 | node_copy(n, reinterpret_cast<Node *>(p.end()), |
953 | reinterpret_cast<Node *>(l.p.begin())); |
954 | } QT_CATCH(...) { |
955 | // restore the old end |
956 | d->end -= int(reinterpret_cast<Node *>(p.end()) - n); |
957 | QT_RETHROW; |
958 | } |
959 | } |
960 | } |
961 | return *this; |
962 | } |
963 | |
964 | template <typename T> |
965 | inline void QList<T>::append(const QList<T> &t) |
966 | { |
967 | *this += t; |
968 | } |
969 | |
970 | template <typename T> |
971 | Q_OUTOFLINE_TEMPLATE int QList<T>::indexOf(const T &t, int from) const |
972 | { |
973 | if (from < 0) |
974 | from = qMax(from + p.size(), 0); |
975 | if (from < p.size()) { |
976 | Node *n = reinterpret_cast<Node *>(p.at(from -1)); |
977 | Node *e = reinterpret_cast<Node *>(p.end()); |
978 | while (++n != e) |
979 | if (n->t() == t) |
980 | return int(n - reinterpret_cast<Node *>(p.begin())); |
981 | } |
982 | return -1; |
983 | } |
984 | |
985 | template <typename T> |
986 | Q_OUTOFLINE_TEMPLATE int QList<T>::lastIndexOf(const T &t, int from) const |
987 | { |
988 | if (from < 0) |
989 | from += p.size(); |
990 | else if (from >= p.size()) |
991 | from = p.size()-1; |
992 | if (from >= 0) { |
993 | Node *b = reinterpret_cast<Node *>(p.begin()); |
994 | Node *n = reinterpret_cast<Node *>(p.at(from + 1)); |
995 | while (n-- != b) { |
996 | if (n->t() == t) |
997 | return n - b; |
998 | } |
999 | } |
1000 | return -1; |
1001 | } |
1002 | |
1003 | template <typename T> |
1004 | Q_OUTOFLINE_TEMPLATE bool QList<T>::contains(const T &t) const |
1005 | { |
1006 | return contains_impl(t, MemoryLayout()); |
1007 | } |
1008 | |
1009 | template <typename T> |
1010 | inline bool QList<T>::contains_impl(const T &t, QListData::NotArrayCompatibleLayout) const |
1011 | { |
1012 | Node *e = reinterpret_cast<Node *>(p.end()); |
1013 | Node *i = reinterpret_cast<Node *>(p.begin()); |
1014 | for (; i != e; ++i) |
1015 | if (i->t() == t) |
1016 | return true; |
1017 | return false; |
1018 | } |
1019 | |
1020 | template <typename T> |
1021 | inline bool QList<T>::contains_impl(const T &t, QListData::ArrayCompatibleLayout) const |
1022 | { |
1023 | const T *b = reinterpret_cast<const T*>(p.begin()); |
1024 | const T *e = reinterpret_cast<const T*>(p.end()); |
1025 | return std::find(b, e, t) != e; |
1026 | } |
1027 | |
1028 | template <typename T> |
1029 | Q_OUTOFLINE_TEMPLATE int QList<T>::count(const T &t) const |
1030 | { |
1031 | return this->count_impl(t, MemoryLayout()); |
1032 | } |
1033 | |
1034 | template <typename T> |
1035 | inline int QList<T>::count_impl(const T &t, QListData::NotArrayCompatibleLayout) const |
1036 | { |
1037 | int c = 0; |
1038 | Node *e = reinterpret_cast<Node *>(p.end()); |
1039 | Node *i = reinterpret_cast<Node *>(p.begin()); |
1040 | for (; i != e; ++i) |
1041 | if (i->t() == t) |
1042 | ++c; |
1043 | return c; |
1044 | } |
1045 | |
1046 | template <typename T> |
1047 | inline int QList<T>::count_impl(const T &t, QListData::ArrayCompatibleLayout) const |
1048 | { |
1049 | return int(std::count(reinterpret_cast<const T*>(p.begin()), |
1050 | reinterpret_cast<const T*>(p.end()), |
1051 | t)); |
1052 | } |
1053 | |
1054 | Q_DECLARE_SEQUENTIAL_ITERATOR(List) |
1055 | Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(List) |
1056 | |
1057 | template <typename T> |
1058 | uint qHash(const QList<T> &key, uint seed = 0) |
1059 | Q_DECL_NOEXCEPT_EXPR(noexcept(qHashRange(key.cbegin(), key.cend(), seed))) |
1060 | { |
1061 | return qHashRange(key.cbegin(), key.cend(), seed); |
1062 | } |
1063 | |
1064 | template <typename T> |
1065 | bool operator<(const QList<T> &lhs, const QList<T> &rhs) |
1066 | Q_DECL_NOEXCEPT_EXPR(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(), |
1067 | rhs.begin(), rhs.end()))) |
1068 | { |
1069 | return std::lexicographical_compare(lhs.begin(), lhs.end(), |
1070 | rhs.begin(), rhs.end()); |
1071 | } |
1072 | |
1073 | template <typename T> |
1074 | inline bool operator>(const QList<T> &lhs, const QList<T> &rhs) |
1075 | Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs)) |
1076 | { |
1077 | return rhs < lhs; |
1078 | } |
1079 | |
1080 | template <typename T> |
1081 | inline bool operator<=(const QList<T> &lhs, const QList<T> &rhs) |
1082 | Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs)) |
1083 | { |
1084 | return !(lhs > rhs); |
1085 | } |
1086 | |
1087 | template <typename T> |
1088 | inline bool operator>=(const QList<T> &lhs, const QList<T> &rhs) |
1089 | Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs)) |
1090 | { |
1091 | return !(lhs < rhs); |
1092 | } |
1093 | |
1094 | QT_END_NAMESPACE |
1095 | |
1096 | #include <QtCore/qbytearraylist.h> |
1097 | #include <QtCore/qstringlist.h> |
1098 | |
1099 | #ifdef Q_CC_MSVC |
1100 | #pragma warning( pop ) |
1101 | #endif |
1102 | |
1103 | #endif // QLIST_H |
1104 | |