/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QLIST_H #define QLIST_H #include #include #include #ifndef QT_NO_STL #include #include #endif #include #include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Core) template class QVector; template class QSet; struct Q_CORE_EXPORT QListData { struct Data { QBasicAtomicInt ref; int alloc, begin, end; uint sharable : 1; void *array[1]; }; enum { DataHeaderSize = sizeof(Data) - sizeof(void *) }; Data *detach(); // remove in 5.0 Data *detach2(); // remove in 5.0 Data *detach3(); void realloc(int alloc); static Data shared_null; Data *d; void **erase(void **xi); void **append(); void **append(const QListData &l); void **append2(const QListData &l); // remove in 5.0 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 { return d->end - d->begin; } inline bool isEmpty() const { return d->end == d->begin; } inline void **at(int i) const { return d->array + d->begin + i; } inline void **begin() const { return d->array + d->begin; } inline void **end() const { return d->array + d->end; } }; template class QList { 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() : d(&QListData::shared_null) { d->ref.ref(); current_index=0; } inline QList(const QList &l) : d(l.d) { d->ref.ref(); if (!d->sharable) detach_helper(); current_index=0; } ~QList(); QList &operator=(const QList &l); bool operator==(const QList &l) const; inline bool operator!=(const QList &l) const { return !(*this == l); } operator bool() const; inline operator const QList *() const { return const_cast *>(this); } inline operator QList *() const { return const_cast *>(this); } inline int size() const { return p.size(); } inline void detach() { if (d->ref != 1) detach_helper(); } inline void detachShared() { // The "this->" qualification is needed for GCCE. if (d->ref != 1 && this->d != &QListData::shared_null) detach_helper(); } inline bool isDetached() const { return d->ref == 1; } inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } inline bool isEmpty() const { return p.isEmpty(); } void clear(); const T &at(int i) const; const T &operator[](int i) const; T &operator[](int i); 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; QBool contains(const T &t) const; inline uint containsRef( const T &t ) { return count(t); }; int count(const T &t) const; inline T next() { current_index++; return *this[current_index]; } inline T prev() { current_index--; return *this[current_index]; } class const_iterator; class iterator { public: Node *i; typedef std::random_access_iterator_tag iterator_category; typedef ptrdiff_t difference_type; typedef T value_type; typedef T *pointer; typedef T &reference; inline iterator() : i(0) {} inline iterator(Node *n) : i(n) {} inline iterator(const iterator &o): i(o.i){} inline T &operator*() const { return i->t(); } inline T *operator->() const { return &i->t(); } inline T &operator[](int j) const { return i[j].t(); } inline bool operator==(const iterator &o) const { return i == o.i; } inline bool operator!=(const iterator &o) const { return i != o.i; } inline bool operator<(const iterator& other) const { return i < other.i; } inline bool operator<=(const iterator& other) const { return i <= other.i; } inline bool operator>(const iterator& other) const { return i > other.i; } inline bool operator>=(const iterator& other) const { return i >= other.i; } #ifndef QT_STRICT_ITERATORS inline bool operator==(const const_iterator &o) const { return i == o.i; } inline bool operator!=(const const_iterator &o) const { return i != o.i; } inline bool operator<(const const_iterator& other) const { return i < other.i; } inline bool operator<=(const const_iterator& other) const { return i <= other.i; } inline bool operator>(const const_iterator& other) const { return i > other.i; } inline bool operator>=(const const_iterator& other) const { 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+=(int j) { i+=j; return *this; } inline iterator &operator-=(int j) { i-=j; return *this; } inline iterator operator+(int j) const { return iterator(i+j); } inline iterator operator-(int 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; typedef ptrdiff_t difference_type; typedef T value_type; typedef const T *pointer; typedef const T &reference; inline const_iterator() : i(0) {} inline const_iterator(Node *n) : i(n) {} inline const_iterator(const const_iterator &o): i(o.i) {} #ifdef QT_STRICT_ITERATORS inline explicit const_iterator(const iterator &o): i(o.i) {} #else inline const_iterator(const iterator &o): i(o.i) {} #endif inline const T &operator*() const { return i->t(); } inline const T *operator->() const { return &i->t(); } inline const T &operator[](int j) const { return i[j].t(); } inline bool operator==(const const_iterator &o) const { return i == o.i; } inline bool operator!=(const const_iterator &o) const { return i != o.i; } inline bool operator<(const const_iterator& other) const { return i < other.i; } inline bool operator<=(const const_iterator& other) const { return i <= other.i; } inline bool operator>(const const_iterator& other) const { return i > other.i; } inline bool operator>=(const const_iterator& other) const { 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+=(int j) { i+=j; return *this; } inline const_iterator &operator-=(int j) { i-=j; return *this; } inline const_iterator operator+(int j) const { return const_iterator(i+j); } inline const_iterator operator-(int j) const { return const_iterator(i-j); } inline int operator-(const_iterator j) const { return i - j.i; } }; friend class const_iterator; // stl style inline iterator begin() { detach(); return reinterpret_cast(p.begin()); } inline const_iterator begin() const { return reinterpret_cast(p.begin()); } inline const_iterator constBegin() const { return reinterpret_cast(p.begin()); } inline iterator end() { detach(); return reinterpret_cast(p.end()); } inline const_iterator end() const { return reinterpret_cast(p.end()); } inline const_iterator constEnd() const { return reinterpret_cast(p.end()); } 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()); current_index=0; return *begin(); } inline const T& first() const { Q_ASSERT(!isEmpty()); current_index=0; return *begin(); } T& last() { Q_ASSERT(!isEmpty()); return *(--end()); } const T& last() const { Q_ASSERT(!isEmpty()); current_index=count()-1; return *(--end()); } 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; typedef ptrdiff_t difference_type; #ifdef QT3_SUPPORT inline QT3_SUPPORT iterator remove(iterator pos) { return erase(pos); } inline QT3_SUPPORT int remove(const T &t) { return removeAll(t); } inline QT3_SUPPORT int findIndex(const T& t) const { return indexOf(t); } inline QT3_SUPPORT iterator find(const T& t) { int i = indexOf(t); return (i == -1 ? end() : (begin()+i)); } inline QT3_SUPPORT const_iterator find (const T& t) const { int i = indexOf(t); return (i == -1 ? end() : (begin()+i)); } inline QT3_SUPPORT iterator find(iterator from, const T& t) { int i = indexOf(t, from - begin()); return i == -1 ? end() : begin()+i; } inline QT3_SUPPORT const_iterator find(const_iterator from, const T& t) const { int i = indexOf(t, from - begin()); return i == -1 ? end() : begin()+i; } #endif // 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); #ifndef QT_NO_STL static inline QList fromStdList(const std::list &list) { QList tmp; qCopy(list.begin(), list.end(), std::back_inserter(tmp)); return tmp; } inline std::list toStdList() const { std::list tmp; qCopy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; } #endif private: void detach_helper(); void free(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); int current_index; }; #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); else *reinterpret_cast(n) = t; } 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) { l.d->ref.ref(); if (!d->ref.deref()) free(d); d = l.d; if (!d->sharable) detach_helper(); } return *this; } template inline typename QList::iterator QList::insert(iterator before, const T &t) { int iBefore = int(before.i - reinterpret_cast(p.begin())); Node *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) { 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::append(const T &t) { detach(); if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.append()); QT_TRY { node_construct(n, t); } QT_CATCH(...) { --d->end; QT_RETHROW; } } else { const T cpy(t); Node *n = reinterpret_cast(p.append()); QT_TRY { node_construct(n, cpy); } QT_CATCH(...) { --d->end; QT_RETHROW; } } } template inline void QList::prepend(const T &t) { detach(); if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.prepend()); QT_TRY { node_construct(n, t); } QT_CATCH(...) { ++d->begin; QT_RETHROW; } } else { const T cpy(t); Node *n = reinterpret_cast(p.prepend()); QT_TRY { node_construct(n, cpy); } QT_CATCH(...) { ++d->begin; QT_RETHROW; } } } template inline void QList::insert(int i, const T &t) { detach(); 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 { const T cpy(t); Node *n = reinterpret_cast(p.insert(i)); QT_TRY { node_construct(n, cpy); } QT_CATCH(...) { p.remove(i); QT_RETHROW; } } } 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(); if (QTypeInfo::isLarge || QTypeInfo::isStatic) { reinterpret_cast(p.at(i))->t() = t; } else { const T cpy(t); reinterpret_cast(p.at(i))->t() = cpy; } } 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(); void *t = d->array[d->begin + i]; d->array[d->begin + i] = d->array[d->begin + j]; d->array[d->begin + j] = t; } 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 { if (alength < 0) alength = size() - pos; if (pos == 0 && alength == size()) return *this; QList cpy; if (pos + alength > size()) alength = size() - pos; for (int i = pos; i < pos + alength; ++i) cpy += at(i); 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 void QList::detach_helper() { Node *n = reinterpret_cast(p.begin()); QListData::Data *x = p.detach3(); QT_TRY { node_copy(reinterpret_cast(p.begin()), reinterpret_cast(p.end()), n); } QT_CATCH(...) { qFree(d); d = x; QT_RETHROW; } if (!x->ref.deref()) free(x); } template Q_OUTOFLINE_TEMPLATE QList::~QList() { if (d && !d->ref.deref()) free(d); } template Q_OUTOFLINE_TEMPLATE bool QList::operator==(const QList &l) const { if (p.size() != l.p.size()) return false; if (d == l.d) return true; Node *i = reinterpret_cast(p.end()); Node *b = reinterpret_cast(p.begin()); Node *li = reinterpret_cast(l.p.end()); while (i != b) { --i; --li; if (!(i->t() == li->t())) return false; } return true; } // ### Qt 5: rename freeData() to avoid confusion with std::free() template Q_OUTOFLINE_TEMPLATE void QList::free(QListData::Data *data) { node_destruct(reinterpret_cast(data->array + data->begin), reinterpret_cast(data->array + data->end)); if (data->ref == 0) qFree(data); } template Q_OUTOFLINE_TEMPLATE void QList::clear() { *this = QList(); } template Q_OUTOFLINE_TEMPLATE int QList::removeAll(const T &_t) { detachShared(); const T t = _t; int removedCount=0, i=0; Node *n; while (i < p.size()) if ((n = reinterpret_cast(p.at(i)))->t() == t) { node_destruct(n); p.remove(i); ++removedCount; } else { ++i; } return removedCount; } template Q_OUTOFLINE_TEMPLATE bool QList::removeOne(const T &_t) { detachShared(); 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) { 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) { detach(); Node *n = reinterpret_cast(p.append2(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 QBool QList::contains(const T &t) const { Node *b = reinterpret_cast(p.begin()); Node *i = reinterpret_cast(p.end()); while (i-- != b) if (i->t() == t) return QBool(true); return QBool(false); } template Q_OUTOFLINE_TEMPLATE int QList::count(const T &t) const { int c = 0; Node *b = reinterpret_cast(p.begin()); Node *i = reinterpret_cast(p.end()); while (i-- != b) if (i->t() == t) ++c; return c; } Q_DECLARE_SEQUENTIAL_ITERATOR(List) Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(List) QT_END_NAMESPACE QT_END_HEADER #endif // QLIST_H