/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QLIST_H #define QLIST_H #include #include #include #include #include #include #include #include #ifdef Q_COMPILER_INITIALIZER_LISTS #include #endif #include #include #include #include #ifdef Q_CC_MSVC #pragma warning( push ) #pragma warning( disable : 4127 ) // "conditional expression is constant" #endif QT_BEGIN_NAMESPACE template class QVector; template class QSet; template struct QListSpecialMethods { protected: ~QListSpecialMethods() {} }; template <> struct QListSpecialMethods; template <> struct QListSpecialMethods; struct Q_CORE_EXPORT QListData { // tags for tag-dispatching of QList implementations, // based on QList's three different memory layouts: struct NotArrayCompatibleLayout {}; struct NotIndirectLayout {}; struct ArrayCompatibleLayout : NotIndirectLayout {}; // data laid out like a C array struct InlineWithPaddingLayout : NotArrayCompatibleLayout, NotIndirectLayout {}; // data laid out like a C array with padding struct IndirectLayout : NotArrayCompatibleLayout {}; // data allocated on the heap struct Data { QtPrivate::RefCount ref; int alloc, begin, end; void *array[1]; }; enum { DataHeaderSize = sizeof(Data) - sizeof(void *) }; Data *detach(int alloc); Data *detach_grow(int *i, int n); void realloc(int alloc); void realloc_grow(int growth); inline void dispose() { dispose(d); } static void dispose(Data *d); static const Data shared_null; Data *d; void **erase(void **xi); void **append(int n); void **append(); void **append(const QListData &l); void **prepend(); void **insert(int i); void remove(int i); void remove(int i, int n); void move(int from, int to); inline int size() const Q_DECL_NOTHROW { return d->end - d->begin; } inline bool isEmpty() const Q_DECL_NOTHROW { return d->end == d->begin; } inline void **at(int i) const Q_DECL_NOTHROW { return d->array + d->begin + i; } inline void **begin() const Q_DECL_NOTHROW { return d->array + d->begin; } inline void **end() const Q_DECL_NOTHROW { return d->array + d->end; } }; template class QList : public QListSpecialMethods { public: struct MemoryLayout : QtPrivate::if_< QTypeInfo::isStatic || QTypeInfo::isLarge, QListData::IndirectLayout, typename QtPrivate::if_< sizeof(T) == sizeof(void*), QListData::ArrayCompatibleLayout, QListData::InlineWithPaddingLayout >::type>::type {}; private: struct Node { void *v; #if defined(Q_CC_BOR) Q_INLINE_TEMPLATE T &t(); #else Q_INLINE_TEMPLATE T &t() { return *reinterpret_cast(QTypeInfo::isLarge || QTypeInfo::isStatic ? v : this); } #endif }; union { QListData p; QListData::Data *d; }; public: inline QList() Q_DECL_NOTHROW : d(const_cast(&QListData::shared_null)) { } QList(const QList &l); ~QList(); QList &operator=(const QList &l); #ifdef Q_COMPILER_RVALUE_REFS inline QList(QList &&other) Q_DECL_NOTHROW : d(other.d) { other.d = const_cast(&QListData::shared_null); } inline QList &operator=(QList &&other) Q_DECL_NOTHROW { QList moved(std::move(other)); swap(moved); return *this; } #endif inline void swap(QList &other) Q_DECL_NOTHROW { qSwap(d, other.d); } #ifdef Q_COMPILER_INITIALIZER_LISTS inline QList(std::initializer_list args) : d(const_cast(&QListData::shared_null)) { reserve(int(args.size())); std::copy(args.begin(), args.end(), std::back_inserter(*this)); } #endif bool operator==(const QList &l) const; inline bool operator!=(const QList &l) const { return !(*this == l); } inline int size() const Q_DECL_NOTHROW { return p.size(); } inline void detach() { if (d->ref.isShared()) detach_helper(); } inline void detachShared() { // The "this->" qualification is needed for GCCE. if (d->ref.isShared() && this->d != &QListData::shared_null) detach_helper(); } inline bool isDetached() const { return !d->ref.isShared(); } #if !defined(QT_NO_UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (sharable == d->ref.isSharable()) return; if (!sharable) detach(); if (d != &QListData::shared_null) d->ref.setSharable(sharable); } #endif inline bool isSharedWith(const QList &other) const Q_DECL_NOTHROW { return d == other.d; } inline bool isEmpty() const Q_DECL_NOTHROW { return p.isEmpty(); } void clear(); const T &at(int i) const; const T &operator[](int i) const; T &operator[](int i); void reserve(int size); void append(const T &t); void append(const QList &t); void prepend(const T &t); void insert(int i, const T &t); void replace(int i, const T &t); void removeAt(int i); int removeAll(const T &t); bool removeOne(const T &t); T takeAt(int i); T takeFirst(); T takeLast(); void move(int from, int to); void swap(int i, int j); int indexOf(const T &t, int from = 0) const; int lastIndexOf(const T &t, int from = -1) const; bool contains(const T &t) const; int count(const T &t) const; class const_iterator; class iterator { public: Node *i; typedef std::random_access_iterator_tag iterator_category; // ### Qt6: use int typedef qptrdiff difference_type; typedef T value_type; typedef T *pointer; typedef T &reference; inline iterator() Q_DECL_NOTHROW : i(Q_NULLPTR) {} inline iterator(Node *n) Q_DECL_NOTHROW : i(n) {} #if QT_VERSION < QT_VERSION_CHECK(6,0,0) // can't remove it in Qt 5, since doing so would make the type trivial, // which changes the way it's passed to functions by value. inline iterator(const iterator &o) Q_DECL_NOTHROW : i(o.i){} #endif inline T &operator*() const { return i->t(); } inline T *operator->() const { return &i->t(); } inline T &operator[](difference_type j) const { return i[j].t(); } inline bool operator==(const iterator &o) const Q_DECL_NOTHROW { return i == o.i; } inline bool operator!=(const iterator &o) const Q_DECL_NOTHROW { return i != o.i; } inline bool operator<(const iterator& other) const Q_DECL_NOTHROW { return i < other.i; } inline bool operator<=(const iterator& other) const Q_DECL_NOTHROW { return i <= other.i; } inline bool operator>(const iterator& other) const Q_DECL_NOTHROW { return i > other.i; } inline bool operator>=(const iterator& other) const Q_DECL_NOTHROW { return i >= other.i; } #ifndef QT_STRICT_ITERATORS inline bool operator==(const const_iterator &o) const Q_DECL_NOTHROW { return i == o.i; } inline bool operator!=(const const_iterator &o) const Q_DECL_NOTHROW { return i != o.i; } inline bool operator<(const const_iterator& other) const Q_DECL_NOTHROW { return i < other.i; } inline bool operator<=(const const_iterator& other) const Q_DECL_NOTHROW { return i <= other.i; } inline bool operator>(const const_iterator& other) const Q_DECL_NOTHROW { return i > other.i; } inline bool operator>=(const const_iterator& other) const Q_DECL_NOTHROW { return i >= other.i; } #endif inline iterator &operator++() { ++i; return *this; } inline iterator operator++(int) { Node *n = i; ++i; return n; } inline iterator &operator--() { i--; return *this; } inline iterator operator--(int) { Node *n = i; i--; return n; } inline iterator &operator+=(difference_type j) { i+=j; return *this; } inline iterator &operator-=(difference_type j) { i-=j; return *this; } inline iterator operator+(difference_type j) const { return iterator(i+j); } inline iterator operator-(difference_type j) const { return iterator(i-j); } inline int operator-(iterator j) const { return int(i - j.i); } }; friend class iterator; class const_iterator { public: Node *i; typedef std::random_access_iterator_tag iterator_category; // ### Qt6: use int typedef qptrdiff difference_type; typedef T value_type; typedef const T *pointer; typedef const T &reference; inline const_iterator() Q_DECL_NOTHROW : i(Q_NULLPTR) {} inline const_iterator(Node *n) Q_DECL_NOTHROW : i(n) {} #if QT_VERSION < QT_VERSION_CHECK(6,0,0) // can't remove it in Qt 5, since doing so would make the type trivial, // which changes the way it's passed to functions by value. inline const_iterator(const const_iterator &o) Q_DECL_NOTHROW : i(o.i) {} #endif #ifdef QT_STRICT_ITERATORS inline explicit const_iterator(const iterator &o) Q_DECL_NOTHROW : i(o.i) {} #else inline const_iterator(const iterator &o) Q_DECL_NOTHROW : i(o.i) {} #endif inline const T &operator*() const { return i->t(); } inline const T *operator->() const { return &i->t(); } inline const T &operator[](difference_type j) const { return i[j].t(); } inline bool operator==(const const_iterator &o) const Q_DECL_NOTHROW { return i == o.i; } inline bool operator!=(const const_iterator &o) const Q_DECL_NOTHROW { return i != o.i; } inline bool operator<(const const_iterator& other) const Q_DECL_NOTHROW { return i < other.i; } inline bool operator<=(const const_iterator& other) const Q_DECL_NOTHROW { return i <= other.i; } inline bool operator>(const const_iterator& other) const Q_DECL_NOTHROW { return i > other.i; } inline bool operator>=(const const_iterator& other) const Q_DECL_NOTHROW { return i >= other.i; } inline const_iterator &operator++() { ++i; return *this; } inline const_iterator operator++(int) { Node *n = i; ++i; return n; } inline const_iterator &operator--() { i--; return *this; } inline const_iterator operator--(int) { Node *n = i; i--; return n; } inline const_iterator &operator+=(difference_type j) { i+=j; return *this; } inline const_iterator &operator-=(difference_type j) { i-=j; return *this; } inline const_iterator operator+(difference_type j) const { return const_iterator(i+j); } inline const_iterator operator-(difference_type j) const { return const_iterator(i-j); } inline int operator-(const_iterator j) const { return int(i - j.i); } }; friend class const_iterator; // stl style typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; inline iterator begin() { detach(); return reinterpret_cast(p.begin()); } inline const_iterator begin() const Q_DECL_NOTHROW { return reinterpret_cast(p.begin()); } inline const_iterator cbegin() const Q_DECL_NOTHROW { return reinterpret_cast(p.begin()); } inline const_iterator constBegin() const Q_DECL_NOTHROW { return reinterpret_cast(p.begin()); } inline iterator end() { detach(); return reinterpret_cast(p.end()); } inline const_iterator end() const Q_DECL_NOTHROW { return reinterpret_cast(p.end()); } inline const_iterator cend() const Q_DECL_NOTHROW { return reinterpret_cast(p.end()); } inline const_iterator constEnd() const Q_DECL_NOTHROW { return reinterpret_cast(p.end()); } reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } const_reverse_iterator crend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } iterator insert(iterator before, const T &t); iterator erase(iterator pos); iterator erase(iterator first, iterator last); // more Qt typedef iterator Iterator; typedef const_iterator ConstIterator; inline int count() const { return p.size(); } inline int length() const { return p.size(); } // Same as count() inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); } inline const T& constFirst() const { return first(); } inline const T& first() const { Q_ASSERT(!isEmpty()); return at(0); } T& last() { Q_ASSERT(!isEmpty()); return *(--end()); } const T& last() const { Q_ASSERT(!isEmpty()); return at(count() - 1); } inline const T& constLast() const { return last(); } inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(begin()); } inline void removeLast() { Q_ASSERT(!isEmpty()); erase(--end()); } inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; } inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; } QList mid(int pos, int length = -1) const; T value(int i) const; T value(int i, const T &defaultValue) const; // stl compatibility inline void push_back(const T &t) { append(t); } inline void push_front(const T &t) { prepend(t); } inline T& front() { return first(); } inline const T& front() const { return first(); } inline T& back() { return last(); } inline const T& back() const { return last(); } inline void pop_front() { removeFirst(); } inline void pop_back() { removeLast(); } inline bool empty() const { return isEmpty(); } typedef int size_type; typedef T value_type; typedef value_type *pointer; typedef const value_type *const_pointer; typedef value_type &reference; typedef const value_type &const_reference; // ### Qt6: use int typedef qptrdiff difference_type; // comfort QList &operator+=(const QList &l); inline QList operator+(const QList &l) const { QList n = *this; n += l; return n; } inline QList &operator+=(const T &t) { append(t); return *this; } inline QList &operator<< (const T &t) { append(t); return *this; } inline QList &operator<<(const QList &l) { *this += l; return *this; } QVector toVector() const; QSet toSet() const; static QList fromVector(const QVector &vector); static QList fromSet(const QSet &set); static inline QList fromStdList(const std::list &list) { QList tmp; std::copy(list.begin(), list.end(), std::back_inserter(tmp)); return tmp; } inline std::list toStdList() const { std::list tmp; std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; } private: Node *detach_helper_grow(int i, int n); void detach_helper(int alloc); void detach_helper(); void dealloc(QListData::Data *d); void node_construct(Node *n, const T &t); void node_destruct(Node *n); void node_copy(Node *from, Node *to, Node *src); void node_destruct(Node *from, Node *to); bool isValidIterator(const iterator &i) const Q_DECL_NOTHROW { return (constBegin().i <= i.i) && (i.i <= constEnd().i); } private: inline bool op_eq_impl(const QList &other, QListData::NotArrayCompatibleLayout) const; inline bool op_eq_impl(const QList &other, QListData::ArrayCompatibleLayout) const; inline bool contains_impl(const T &, QListData::NotArrayCompatibleLayout) const; inline bool contains_impl(const T &, QListData::ArrayCompatibleLayout) const; inline int count_impl(const T &, QListData::NotArrayCompatibleLayout) const; inline int count_impl(const T &, QListData::ArrayCompatibleLayout) const; }; #if defined(Q_CC_BOR) template Q_INLINE_TEMPLATE T &QList::Node::t() { return QTypeInfo::isLarge || QTypeInfo::isStatic ? *(T*)v:*(T*)this; } #endif template Q_INLINE_TEMPLATE void QList::node_construct(Node *n, const T &t) { if (QTypeInfo::isLarge || QTypeInfo::isStatic) n->v = new T(t); else if (QTypeInfo::isComplex) new (n) T(t); #if (defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__IBMCPP__)) && !defined(__OPTIMIZE__) // This violates pointer aliasing rules, but it is known to be safe (and silent) // in unoptimized GCC builds (-fno-strict-aliasing). The other compilers which // set the same define are assumed to be safe. else *reinterpret_cast(n) = t; #else // This is always safe, but penaltizes unoptimized builds a lot. else ::memcpy(n, static_cast(&t), sizeof(T)); #endif } template Q_INLINE_TEMPLATE void QList::node_destruct(Node *n) { if (QTypeInfo::isLarge || QTypeInfo::isStatic) delete reinterpret_cast(n->v); else if (QTypeInfo::isComplex) reinterpret_cast(n)->~T(); } template Q_INLINE_TEMPLATE void QList::node_copy(Node *from, Node *to, Node *src) { Node *current = from; if (QTypeInfo::isLarge || QTypeInfo::isStatic) { QT_TRY { while(current != to) { current->v = new T(*reinterpret_cast(src->v)); ++current; ++src; } } QT_CATCH(...) { while (current-- != from) delete reinterpret_cast(current->v); QT_RETHROW; } } else if (QTypeInfo::isComplex) { QT_TRY { while(current != to) { new (current) T(*reinterpret_cast(src)); ++current; ++src; } } QT_CATCH(...) { while (current-- != from) (reinterpret_cast(current))->~T(); QT_RETHROW; } } else { if (src != from && to - from > 0) memcpy(from, src, (to - from) * sizeof(Node)); } } template Q_INLINE_TEMPLATE void QList::node_destruct(Node *from, Node *to) { if (QTypeInfo::isLarge || QTypeInfo::isStatic) while(from != to) --to, delete reinterpret_cast(to->v); else if (QTypeInfo::isComplex) while (from != to) --to, reinterpret_cast(to)->~T(); } template Q_INLINE_TEMPLATE QList &QList::operator=(const QList &l) { if (d != l.d) { QList tmp(l); tmp.swap(*this); } return *this; } template inline typename QList::iterator QList::insert(iterator before, const T &t) { Q_ASSERT_X(isValidIterator(before), "QList::insert", "The specified iterator argument 'before' is invalid"); int iBefore = int(before.i - reinterpret_cast(p.begin())); Node *n = 0; if (d->ref.isShared()) n = detach_helper_grow(iBefore, 1); else n = reinterpret_cast(p.insert(iBefore)); QT_TRY { node_construct(n, t); } QT_CATCH(...) { p.remove(iBefore); QT_RETHROW; } return n; } template inline typename QList::iterator QList::erase(iterator it) { Q_ASSERT_X(isValidIterator(it), "QList::erase", "The specified iterator argument 'it' is invalid"); if (d->ref.isShared()) { int offset = int(it.i - reinterpret_cast(p.begin())); it = begin(); // implies detach() it += offset; } node_destruct(it.i); return reinterpret_cast(p.erase(reinterpret_cast(it.i))); } template inline const T &QList::at(int i) const { Q_ASSERT_X(i >= 0 && i < p.size(), "QList::at", "index out of range"); return reinterpret_cast(p.at(i))->t(); } template inline const T &QList::operator[](int i) const { Q_ASSERT_X(i >= 0 && i < p.size(), "QList::operator[]", "index out of range"); return reinterpret_cast(p.at(i))->t(); } template inline T &QList::operator[](int i) { Q_ASSERT_X(i >= 0 && i < p.size(), "QList::operator[]", "index out of range"); detach(); return reinterpret_cast(p.at(i))->t(); } template inline void QList::removeAt(int i) { if(i >= 0 && i < p.size()) { detach(); node_destruct(reinterpret_cast(p.at(i))); p.remove(i); } } template inline T QList::takeAt(int i) { Q_ASSERT_X(i >= 0 && i < p.size(), "QList::take", "index out of range"); detach(); Node *n = reinterpret_cast(p.at(i)); T t = n->t(); node_destruct(n); p.remove(i); return t; } template inline T QList::takeFirst() { T t = first(); removeFirst(); return t; } template inline T QList::takeLast() { T t = last(); removeLast(); return t; } template Q_OUTOFLINE_TEMPLATE void QList::reserve(int alloc) { if (d->alloc < alloc) { if (d->ref.isShared()) detach_helper(alloc); else p.realloc(alloc); } } template Q_OUTOFLINE_TEMPLATE void QList::append(const T &t) { if (d->ref.isShared()) { Node *n = detach_helper_grow(INT_MAX, 1); QT_TRY { node_construct(n, t); } QT_CATCH(...) { --d->end; QT_RETHROW; } } else { if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.append()); QT_TRY { node_construct(n, t); } QT_CATCH(...) { --d->end; QT_RETHROW; } } else { Node *n, copy; node_construct(©, t); // t might be a reference to an object in the array QT_TRY { n = reinterpret_cast(p.append());; } QT_CATCH(...) { node_destruct(©); QT_RETHROW; } *n = copy; } } } template inline void QList::prepend(const T &t) { if (d->ref.isShared()) { Node *n = detach_helper_grow(0, 1); QT_TRY { node_construct(n, t); } QT_CATCH(...) { ++d->begin; QT_RETHROW; } } else { if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.prepend()); QT_TRY { node_construct(n, t); } QT_CATCH(...) { ++d->begin; QT_RETHROW; } } else { Node *n, copy; node_construct(©, t); // t might be a reference to an object in the array QT_TRY { n = reinterpret_cast(p.prepend());; } QT_CATCH(...) { node_destruct(©); QT_RETHROW; } *n = copy; } } } template inline void QList::insert(int i, const T &t) { if (d->ref.isShared()) { Node *n = detach_helper_grow(i, 1); QT_TRY { node_construct(n, t); } QT_CATCH(...) { p.remove(i); QT_RETHROW; } } else { if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.insert(i)); QT_TRY { node_construct(n, t); } QT_CATCH(...) { p.remove(i); QT_RETHROW; } } else { Node *n, copy; node_construct(©, t); // t might be a reference to an object in the array QT_TRY { n = reinterpret_cast(p.insert(i));; } QT_CATCH(...) { node_destruct(©); QT_RETHROW; } *n = copy; } } } template inline void QList::replace(int i, const T &t) { Q_ASSERT_X(i >= 0 && i < p.size(), "QList::replace", "index out of range"); detach(); reinterpret_cast(p.at(i))->t() = t; } template inline void QList::swap(int i, int j) { Q_ASSERT_X(i >= 0 && i < p.size() && j >= 0 && j < p.size(), "QList::swap", "index out of range"); detach(); std::swap(d->array[d->begin + i], d->array[d->begin + j]); } template inline void QList::move(int from, int to) { Q_ASSERT_X(from >= 0 && from < p.size() && to >= 0 && to < p.size(), "QList::move", "index out of range"); detach(); p.move(from, to); } template Q_OUTOFLINE_TEMPLATE QList QList::mid(int pos, int alength) const { using namespace QtPrivate; switch (QContainerImplHelper::mid(size(), &pos, &alength)) { case QContainerImplHelper::Null: case QContainerImplHelper::Empty: return QList(); case QContainerImplHelper::Full: return *this; case QContainerImplHelper::Subset: break; } QList cpy; if (alength <= 0) return cpy; cpy.reserve(alength); cpy.d->end = alength; QT_TRY { cpy.node_copy(reinterpret_cast(cpy.p.begin()), reinterpret_cast(cpy.p.end()), reinterpret_cast(p.begin() + pos)); } QT_CATCH(...) { // restore the old end cpy.d->end = 0; QT_RETHROW; } return cpy; } template Q_OUTOFLINE_TEMPLATE T QList::value(int i) const { if (i < 0 || i >= p.size()) { return T(); } return reinterpret_cast(p.at(i))->t(); } template Q_OUTOFLINE_TEMPLATE T QList::value(int i, const T& defaultValue) const { return ((i < 0 || i >= p.size()) ? defaultValue : reinterpret_cast(p.at(i))->t()); } template Q_OUTOFLINE_TEMPLATE typename QList::Node *QList::detach_helper_grow(int i, int c) { Node *n = reinterpret_cast(p.begin()); QListData::Data *x = p.detach_grow(&i, c); QT_TRY { node_copy(reinterpret_cast(p.begin()), reinterpret_cast(p.begin() + i), n); } QT_CATCH(...) { p.dispose(); d = x; QT_RETHROW; } QT_TRY { node_copy(reinterpret_cast(p.begin() + i + c), reinterpret_cast(p.end()), n + i); } QT_CATCH(...) { node_destruct(reinterpret_cast(p.begin()), reinterpret_cast(p.begin() + i)); p.dispose(); d = x; QT_RETHROW; } if (!x->ref.deref()) dealloc(x); return reinterpret_cast(p.begin() + i); } template Q_OUTOFLINE_TEMPLATE void QList::detach_helper(int alloc) { Node *n = reinterpret_cast(p.begin()); QListData::Data *x = p.detach(alloc); QT_TRY { node_copy(reinterpret_cast(p.begin()), reinterpret_cast(p.end()), n); } QT_CATCH(...) { p.dispose(); d = x; QT_RETHROW; } if (!x->ref.deref()) dealloc(x); } template Q_OUTOFLINE_TEMPLATE void QList::detach_helper() { detach_helper(d->alloc); } template Q_OUTOFLINE_TEMPLATE QList::QList(const QList &l) : QListSpecialMethods(l), d(l.d) { if (!d->ref.ref()) { p.detach(d->alloc); QT_TRY { node_copy(reinterpret_cast(p.begin()), reinterpret_cast(p.end()), reinterpret_cast(l.p.begin())); } QT_CATCH(...) { QListData::dispose(d); QT_RETHROW; } } } template Q_OUTOFLINE_TEMPLATE QList::~QList() { if (!d->ref.deref()) dealloc(d); } template Q_OUTOFLINE_TEMPLATE bool QList::operator==(const QList &l) const { if (d == l.d) return true; if (p.size() != l.p.size()) return false; return this->op_eq_impl(l, MemoryLayout()); } template inline bool QList::op_eq_impl(const QList &l, QListData::NotArrayCompatibleLayout) const { Node *i = reinterpret_cast(p.begin()); Node *e = reinterpret_cast(p.end()); Node *li = reinterpret_cast(l.p.begin()); for (; i != e; ++i, ++li) { if (!(i->t() == li->t())) return false; } return true; } template inline bool QList::op_eq_impl(const QList &l, QListData::ArrayCompatibleLayout) const { const T *lb = reinterpret_cast(l.p.begin()); const T *b = reinterpret_cast(p.begin()); const T *e = reinterpret_cast(p.end()); return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(lb, l.p.size())); } template Q_OUTOFLINE_TEMPLATE void QList::dealloc(QListData::Data *data) { node_destruct(reinterpret_cast(data->array + data->begin), reinterpret_cast(data->array + data->end)); QListData::dispose(data); } template Q_OUTOFLINE_TEMPLATE void QList::clear() { *this = QList(); } template Q_OUTOFLINE_TEMPLATE int QList::removeAll(const T &_t) { int index = indexOf(_t); if (index == -1) return 0; const T t = _t; detach(); Node *i = reinterpret_cast(p.at(index)); Node *e = reinterpret_cast(p.end()); Node *n = i; node_destruct(i); while (++i != e) { if (i->t() == t) node_destruct(i); else *n++ = *i; } int removedCount = e - n; d->end -= removedCount; return removedCount; } template Q_OUTOFLINE_TEMPLATE bool QList::removeOne(const T &_t) { int index = indexOf(_t); if (index != -1) { removeAt(index); return true; } return false; } template Q_OUTOFLINE_TEMPLATE typename QList::iterator QList::erase(typename QList::iterator afirst, typename QList::iterator alast) { Q_ASSERT_X(isValidIterator(afirst), "QList::erase", "The specified iterator argument 'afirst' is invalid"); Q_ASSERT_X(isValidIterator(alast), "QList::erase", "The specified iterator argument 'alast' is invalid"); if (d->ref.isShared()) { // ### A block is erased and a detach is needed. We should shrink and only copy relevant items. int offsetfirst = int(afirst.i - reinterpret_cast(p.begin())); int offsetlast = int(alast.i - reinterpret_cast(p.begin())); afirst = begin(); // implies detach() alast = afirst; afirst += offsetfirst; alast += offsetlast; } for (Node *n = afirst.i; n < alast.i; ++n) node_destruct(n); int idx = afirst - begin(); p.remove(idx, alast - afirst); return begin() + idx; } template Q_OUTOFLINE_TEMPLATE QList &QList::operator+=(const QList &l) { if (!l.isEmpty()) { if (d == &QListData::shared_null) { *this = l; } else { Node *n = (d->ref.isShared()) ? detach_helper_grow(INT_MAX, l.size()) : reinterpret_cast(p.append(l.p)); QT_TRY { node_copy(n, reinterpret_cast(p.end()), reinterpret_cast(l.p.begin())); } QT_CATCH(...) { // restore the old end d->end -= int(reinterpret_cast(p.end()) - n); QT_RETHROW; } } } return *this; } template inline void QList::append(const QList &t) { *this += t; } template Q_OUTOFLINE_TEMPLATE int QList::indexOf(const T &t, int from) const { if (from < 0) from = qMax(from + p.size(), 0); if (from < p.size()) { Node *n = reinterpret_cast(p.at(from -1)); Node *e = reinterpret_cast(p.end()); while (++n != e) if (n->t() == t) return int(n - reinterpret_cast(p.begin())); } return -1; } template Q_OUTOFLINE_TEMPLATE int QList::lastIndexOf(const T &t, int from) const { if (from < 0) from += p.size(); else if (from >= p.size()) from = p.size()-1; if (from >= 0) { Node *b = reinterpret_cast(p.begin()); Node *n = reinterpret_cast(p.at(from + 1)); while (n-- != b) { if (n->t() == t) return n - b; } } return -1; } template Q_OUTOFLINE_TEMPLATE bool QList::contains(const T &t) const { return contains_impl(t, MemoryLayout()); } template inline bool QList::contains_impl(const T &t, QListData::NotArrayCompatibleLayout) const { Node *e = reinterpret_cast(p.end()); Node *i = reinterpret_cast(p.begin()); for (; i != e; ++i) if (i->t() == t) return true; return false; } template inline bool QList::contains_impl(const T &t, QListData::ArrayCompatibleLayout) const { const T *b = reinterpret_cast(p.begin()); const T *e = reinterpret_cast(p.end()); return std::find(b, e, t) != e; } template Q_OUTOFLINE_TEMPLATE int QList::count(const T &t) const { return this->count_impl(t, MemoryLayout()); } template inline int QList::count_impl(const T &t, QListData::NotArrayCompatibleLayout) const { int c = 0; Node *e = reinterpret_cast(p.end()); Node *i = reinterpret_cast(p.begin()); for (; i != e; ++i) if (i->t() == t) ++c; return c; } template inline int QList::count_impl(const T &t, QListData::ArrayCompatibleLayout) const { return int(std::count(reinterpret_cast(p.begin()), reinterpret_cast(p.end()), t)); } Q_DECLARE_SEQUENTIAL_ITERATOR(List) Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(List) template uint qHash(const QList &key, uint seed = 0) Q_DECL_NOEXCEPT_EXPR(noexcept(qHashRange(key.cbegin(), key.cend(), seed))) { return qHashRange(key.cbegin(), key.cend(), seed); } template bool operator<(const QList &lhs, const QList &rhs) Q_DECL_NOEXCEPT_EXPR(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()))) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template inline bool operator>(const QList &lhs, const QList &rhs) Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs)) { return rhs < lhs; } template inline bool operator<=(const QList &lhs, const QList &rhs) Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs)) { return !(lhs > rhs); } template inline bool operator>=(const QList &lhs, const QList &rhs) Q_DECL_NOEXCEPT_EXPR(noexcept(lhs < rhs)) { return !(lhs < rhs); } QT_END_NAMESPACE #include #include #ifdef Q_CC_MSVC #pragma warning( pop ) #endif #endif // QLIST_H