summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qlist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qlist.cpp')
-rw-r--r--src/corelib/tools/qlist.cpp303
1 files changed, 248 insertions, 55 deletions
diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp
index db00dcb458..8ed0da7ca0 100644
--- a/src/corelib/tools/qlist.cpp
+++ b/src/corelib/tools/qlist.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Intel Corporation.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -148,6 +149,17 @@ void QListData::realloc(int alloc)
d->begin = d->end = 0;
}
+void QListData::realloc_grow(int growth)
+{
+ Q_ASSERT(!d->ref.isShared());
+ int alloc = grow(d->alloc + growth);
+ Data *x = static_cast<Data *>(::realloc(d, DataHeaderSize + alloc * sizeof(void *)));
+ Q_CHECK_PTR(x);
+
+ d = x;
+ d->alloc = alloc;
+}
+
void QListData::dispose(Data *d)
{
Q_ASSERT(!d->ref.isShared());
@@ -167,7 +179,7 @@ void **QListData::append(int n)
::memcpy(d->array, d->array + b, e * sizeof(void *));
d->begin = 0;
} else {
- realloc(grow(d->alloc + n));
+ realloc_grow(n);
}
}
d->end = e + n;
@@ -191,7 +203,7 @@ void **QListData::prepend()
Q_ASSERT(!d->ref.isShared());
if (d->begin == 0) {
if (d->end >= d->alloc / 3)
- realloc(grow(d->alloc + 1));
+ realloc_grow(1);
if (d->end < d->alloc / 3)
d->begin = d->alloc - 2 * d->end;
@@ -218,7 +230,7 @@ void **QListData::insert(int i)
if (d->begin == 0) {
if (d->end == d->alloc) {
// If the array is full, we expand it and move some items rightward
- realloc(grow(d->alloc + 1));
+ realloc_grow(1);
} else {
// If there is free space at the end of the array, we move some items rightward
}
@@ -332,41 +344,56 @@ void **QListData::erase(void **xi)
\reentrant
QList\<T\> is one of Qt's generic \l{container classes}. It
- stores a list of values and provides fast index-based access as
- well as fast insertions and removals.
+ stores items in a list that provides fast index-based access
+ and index-based insertions and removals.
QList\<T\>, QLinkedList\<T\>, and QVector\<T\> provide similar
- functionality. Here's an overview:
+ APIs and functionality. They are often interchangeable, but there
+ are performance consequences. Here is an overview of use cases:
\list
- \li For most purposes, QList is the right class to use. Its
- index-based API is more convenient than QLinkedList's
- iterator-based API, and it is usually faster than
- QVector because of the way it stores its items in
- memory. It also expands to less code in your executable.
- \li If you need a real linked list, with guarantees of \l{constant
- time} insertions in the middle of the list and iterators to
- items rather than indexes, use QLinkedList.
- \li If you want the items to occupy adjacent memory positions,
- use QVector.
+ \li QVector should be your default first choice.
+ QVector\<T\> will usually give better performance than QList\<T\>,
+ because QVector\<T\> always stores its items sequentially in memory,
+ where QList\<T\> will allocate its items on the heap unless
+ \c {sizeof(T) <= sizeof(void*)} and T has been declared to be
+ either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
+ \l {Q_DECLARE_TYPEINFO}. See the \l {Pros and Cons of Using QList}
+ for an explanation.
+ \li However, QList is used throughout the Qt APIs for passing
+ parameters and for returning values. Use QList to interface with
+ those APIs.
+ \li If you need a real linked list, which guarantees
+ \l {Algorithmic Complexity}{constant time} insertions mid-list and
+ uses iterators to items rather than indexes, use QLinkedList.
\endlist
+ \note QVector and QVarLengthArray both guarantee C-compatible
+ array layout. QList does not. This might be important if your
+ application must interface with a C API.
- Internally, QList\<T\> is represented as an array of pointers to
- items of type T. If T is itself a pointer type or a basic type
- that is no larger than a pointer, or if T is one of Qt's \l{shared
- classes}, then QList\<T\> stores the items directly in the pointer
- array. For lists under a thousand items, this array representation
- allows for very fast insertions in the middle, and it allows
- index-based access. Furthermore, operations like prepend() and
- append() are very fast, because QList preallocates memory at both
+ \note Iterators into a QLinkedList and references into
+ heap-allocating QLists remain valid long as the referenced items
+ remain in the container. This is not true for iterators and
+ references into a QVector and non-heap-allocating QLists.
+
+ Internally, QList\<T\> is represented as an array of T if
+ \c{sizeof(T) <= sizeof(void*)} and T has been declared to be
+ either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
+ \l {Q_DECLARE_TYPEINFO}. Otherwise, QList\<T\> is represented
+ as an array of T* and the items are allocated on the heap.
+
+ The array representation allows very fast insertions and
+ index-based access. The prepend() and append() operations are
+ also very fast because QList preallocates memory at both
ends of its internal array. (See \l{Algorithmic Complexity} for
- details.) Note, however, that for unshared list items that are
- larger than a pointer, each append or insert of a new item
- requires allocating the new item on the heap, and this per item
- allocation might make QVector a better choice in cases that do
- lots of appending or inserting, since QVector allocates memory for
- its items in a single heap allocation.
+ details.
+
+ Note, however, that when the conditions specified above are not met,
+ each append or insert of a new item requires allocating the new item
+ on the heap, and this per item allocation will make QVector a better
+ choice for use cases that do a lot of appending or inserting, because
+ QVector can allocate memory for many items in a single heap allocation.
Note that the internal array only ever gets bigger over the life
of the list. It never shrinks. The internal array is deallocated
@@ -401,9 +428,10 @@ void **QListData::erase(void **xi)
\snippet code/src_corelib_tools_qlistdata.cpp 2
- Because QList is implemented as an array of pointers, this
- operation is very fast (\l{constant time}). For read-only access,
- an alternative syntax is to use at():
+ Because QList is implemented as an array of pointers for types
+ that are larger than a pointer or are not movable, this operation
+ requires (\l{Algorithmic Complexity}{constant time}). For read-only
+ access, an alternative syntax is to use at():
\snippet code/src_corelib_tools_qlistdata.cpp 3
@@ -417,10 +445,10 @@ void **QListData::erase(void **xi)
\snippet code/src_corelib_tools_qlistdata.cpp 4
- Inserting and removing items at either ends of the list is very
- fast (\l{constant time} in most cases), because QList
- preallocates extra space on both sides of its internal buffer to
- allow for fast growth at both ends of the list.
+ Inserting and removing items at either end of the list is very
+ fast (\l{Algorithmic Complexity}{constant time} in most cases),
+ because QList preallocates extra space on both sides of its
+ internal buffer to allow for fast growth at both ends of the list.
If you want to find all occurrences of a particular value in a
list, use indexOf() or lastIndexOf(). The former searches forward
@@ -481,6 +509,11 @@ void **QListData::erase(void **xi)
\l{QStringList::removeDuplicates()}{removeDuplicates},
\l{QStringList::sort()}{sort}.
+ \section1 More Information on Using Qt Containers
+
+ For a detailed discussion comparing Qt containers with each other and
+ with STL containers, see \l {Understand the Qt Containers}.
+
\sa QListIterator, QMutableListIterator, QLinkedList, QVector
*/
@@ -512,10 +545,11 @@ void **QListData::erase(void **xi)
Constructs a copy of \a other.
- This operation takes \l{constant time}, because QList is
- \l{implicitly shared}. This makes returning a QList from a
- function very fast. If a shared instance is modified, it will be
- copied (copy-on-write), and that takes \l{linear time}.
+ This operation takes \l{Algorithmic Complexity}{constant time},
+ because QList is \l{implicitly shared}. This makes returning a
+ QList from a function very fast. If a shared instance is modified,
+ it will be copied (copy-on-write), and that takes
+ \l{Algorithmic Complexity}{linear time}.
\sa operator=()
*/
@@ -584,6 +618,65 @@ void **QListData::erase(void **xi)
\sa operator==()
*/
+/*! \fn bool operator<(const QList<T> &lhs, const QList<T> &rhs)
+ \since 5.6
+ \relates QList
+
+ Returns \c true if list \a lhs is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {lexicographically less than} \a rhs; otherwise returns \c false.
+
+ This function requires the value type to have an implementation
+ of \c operator<().
+*/
+
+/*! \fn bool operator<=(const QList<T> &lhs, const QList<T> &rhs)
+ \since 5.6
+ \relates QList
+
+ Returns \c true if list \a lhs is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {lexicographically less than or equal to} \a rhs; otherwise returns \c false.
+
+ This function requires the value type to have an implementation
+ of \c operator<().
+*/
+
+/*! \fn bool operator>(const QList<T> &lhs, const QList<T> &rhs)
+ \since 5.6
+ \relates QList
+
+ Returns \c true if list \a lhs is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {lexicographically greater than} \a rhs; otherwise returns \c false.
+
+ This function requires the value type to have an implementation
+ of \c operator<().
+*/
+
+/*! \fn bool operator>=(const QList<T> &lhs, const QList<T> &rhs)
+ \since 5.6
+ \relates QList
+
+ Returns \c true if list \a lhs is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {lexicographically greater than or equal to} \a rhs; otherwise returns \c false.
+
+ This function requires the value type to have an implementation
+ of \c operator<().
+*/
+
+/*!
+ \fn uint qHash(const QList<T> &key, uint seed = 0)
+ \since 5.6
+ \relates QList
+
+ Returns the hash value for \a key,
+ using \a seed to seed the calculation.
+
+ This function requires qHash() to be overloaded for the value type \c T.
+*/
+
/*!
\fn int QList::size() const
@@ -641,7 +734,7 @@ void **QListData::erase(void **xi)
Returns the item at index position \a i in the list. \a i must be
a valid index position in the list (i.e., 0 <= \a i < size()).
- This function is very fast (\l{constant time}).
+ This function is very fast (\l{Algorithmic Complexity}{constant time}).
\sa value(), operator[]()
*/
@@ -654,8 +747,8 @@ void **QListData::erase(void **xi)
If this function is called on a list that is currently being shared, it
will trigger a copy of all elements. Otherwise, this function runs in
- \l{constant time}. If you do not want to modify the list you should use
- QList::at().
+ \l{Algorithmic Complexity}{constant time}. If you do not want to modify
+ the list you should use QList::at().
\sa at(), value()
*/
@@ -664,7 +757,7 @@ void **QListData::erase(void **xi)
\overload
- Same as at(). This function runs in \l{constant time}.
+ Same as at(). This function runs in \l{Algorithmic Complexity}{constant time}.
*/
/*! \fn QList::reserve(int alloc)
@@ -690,9 +783,9 @@ void **QListData::erase(void **xi)
This is the same as list.insert(size(), \a value).
If this list is not shared, this operation is typically
- very fast (amortized \l{constant time}), because QList
- preallocates extra space on both sides of its internal
- buffer to allow for fast growth at both ends of the list.
+ very fast (amortized \l{Algorithmic Complexity}{constant time}),
+ because QList preallocates extra space on both sides of its
+ internal buffer to allow for fast growth at both ends of the list.
\sa operator<<(), prepend(), insert()
*/
@@ -718,9 +811,9 @@ void **QListData::erase(void **xi)
This is the same as list.insert(0, \a value).
If this list is not shared, this operation is typically
- very fast (amortized \l{constant time}), because QList
- preallocates extra space on both sides of its internal
- buffer to allow for fast growth at both ends of the list.
+ very fast (amortized \l{Algorithmic Complexity}{constant time}),
+ because QList preallocates extra space on both sides of its
+ internal buffer to allow for fast growth at both ends of the list.
\sa append(), insert()
*/
@@ -811,7 +904,8 @@ void **QListData::erase(void **xi)
same as takeAt(0). This function assumes the list is not empty. To
avoid failure, call isEmpty() before calling this function.
- If this list is not shared, this operation takes \l{constant time}.
+ If this list is not shared, this operation takes
+ \l {Algorithmic Complexity}{constant time}.
If you don't use the return value, removeFirst() is more
efficient.
@@ -826,7 +920,8 @@ void **QListData::erase(void **xi)
not empty. To avoid failure, call isEmpty() before calling this
function.
- If this list is not shared, this operation takes \l{constant time}.
+ If this list is not shared, this operation takes
+ \l {Algorithmic Complexity}{constant time}.
If you don't use the return value, removeLast() is more
efficient.
@@ -1000,6 +1095,52 @@ void **QListData::erase(void **xi)
\sa constBegin(), end()
*/
+/*! \fn QList::reverse_iterator QList::rbegin()
+ \since 5.6
+
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
+ item in the list, in reverse order.
+
+ \sa begin(), crbegin(), rend()
+*/
+
+/*! \fn QList::const_reverse_iterator QList::rbegin() const
+ \since 5.6
+ \overload
+*/
+
+/*! \fn QList::const_reverse_iterator QList::crbegin() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
+ item in the list, in reverse order.
+
+ \sa begin(), rbegin(), rend()
+*/
+
+/*! \fn QList::reverse_iterator QList::rend()
+ \since 5.6
+
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
+ the last item in the list, in reverse order.
+
+ \sa end(), crend(), rbegin()
+*/
+
+/*! \fn QList::const_reverse_iterator QList::rend() const
+ \since 5.6
+ \overload
+*/
+
+/*! \fn QList::const_reverse_iterator QList::crend() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
+ past the last item in the list, in reverse order.
+
+ \sa end(), rend(), rbegin()
+*/
+
/*! \fn QList::iterator QList::erase(iterator pos)
Removes the item associated with the iterator \a pos from the
@@ -1070,6 +1211,38 @@ void **QListData::erase(void **xi)
Typedef for const T &. Provided for STL compatibility.
*/
+/*! \typedef QList::reverse_iterator
+ \since 5.6
+
+ The QList::reverse_iterator typedef provides an STL-style non-const
+ reverse iterator for QList.
+
+ It is simply a typedef for \c{std::reverse_iterator<iterator>}.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QList::rbegin(), QList::rend(), QList::const_reverse_iterator, QList::iterator
+*/
+
+/*! \typedef QList::const_reverse_iterator
+ \since 5.6
+
+ The QList::const_reverse_iterator typedef provides an STL-style const
+ reverse iterator for QList.
+
+ It is simply a typedef for \c{std::reverse_iterator<const_iterator>}.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QList::rbegin(), QList::rend(), QList::reverse_iterator, QList::const_iterator
+*/
+
/*! \fn int QList::count() const
Returns the number of items in the list. This is effectively the
@@ -1090,7 +1263,7 @@ void **QListData::erase(void **xi)
not be empty. If the list can be empty, call isEmpty() before
calling this function.
- \sa last(), isEmpty()
+ \sa constFirst(), last(), isEmpty()
*/
/*! \fn const T& QList::first() const
@@ -1098,13 +1271,23 @@ void **QListData::erase(void **xi)
\overload
*/
+/*! \fn const T& QList::constFirst() const
+ \since 5.6
+
+ Returns a const reference to the first item in the list. The list must
+ not be empty. If the list can be empty, call isEmpty() before
+ calling this function.
+
+ \sa constLast(), isEmpty(), first()
+*/
+
/*! \fn T& QList::last()
Returns a reference to the last item in the list. The list must
not be empty. If the list can be empty, call isEmpty() before
calling this function.
- \sa first(), isEmpty()
+ \sa constLast(), first(), isEmpty()
*/
/*! \fn const T& QList::last() const
@@ -1112,6 +1295,16 @@ void **QListData::erase(void **xi)
\overload
*/
+/*! \fn const T& QList::constLast() const
+ \since 5.6
+
+ Returns a reference to the last item in the list. The list must
+ not be empty. If the list can be empty, call isEmpty() before
+ calling this function.
+
+ \sa constFirst(), isEmpty(), last()
+*/
+
/*! \fn void QList::removeFirst()
Removes the first item in the list. Calling this function is