diff options
author | Thiago Macieira <thiago.macieira@nokia.com> | 2010-02-23 12:02:52 (GMT) |
---|---|---|
committer | Thiago Macieira <thiago.macieira@nokia.com> | 2010-02-23 12:02:52 (GMT) |
commit | de4332a4728e739b37e9c7b04c021e150e096270 (patch) | |
tree | 619aae505826654f3d89492efa53f758214fea6f /src/corelib/tools | |
parent | a419d587a666aaf55310b3a18e9f9e1993fef16e (diff) | |
parent | 3db40b0be40c946f547f238ed3f0af813892115e (diff) | |
download | Qt-de4332a4728e739b37e9c7b04c021e150e096270.zip Qt-de4332a4728e739b37e9c7b04c021e150e096270.tar.gz Qt-de4332a4728e739b37e9c7b04c021e150e096270.tar.bz2 |
Merge remote branch 'origin/master'
Conflicts:
doc/src/declarative/advtutorial1.qdoc
doc/src/declarative/tutorial2.qdoc
doc/src/declarative/tutorial3.qdoc
src/declarative/graphicsitems/qmlgraphicsmousearea.cpp
src/multimedia/playback/qmediaplayer.cpp
Diffstat (limited to 'src/corelib/tools')
-rw-r--r-- | src/corelib/tools/qlist.cpp | 91 | ||||
-rw-r--r-- | src/corelib/tools/qlist.h | 155 |
2 files changed, 186 insertions, 60 deletions
diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index ac0dc46..6f5bb9b 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -66,6 +66,53 @@ static int grow(int size) return x; } +/*! + * Detaches the QListData by allocating new memory for a list which will be bigger + * than the copied one and is expected to grow further. + * *idx is the desired insertion point and is clamped to the actual size of the list. + * num is the number of new elements to insert at the insertion point. + * Returns the old (shared) data, it is up to the caller to deref() and free(). + * For the new data node_copy needs to be called. + * + * \internal + */ +QListData::Data *QListData::detach_grow(int *idx, int num) +{ + Data *x = d; + int l = x->end - x->begin; + int nl = l + num; + int alloc = grow(nl); + Data* t = static_cast<Data *>(qMalloc(DataHeaderSize + alloc * sizeof(void *))); + Q_CHECK_PTR(t); + + t->ref = 1; + t->sharable = true; + t->alloc = alloc; + // The space reservation algorithm's optimization is biased towards appending: + // Something which looks like an append will put the data at the beginning, + // while something which looks like a prepend will put it in the middle + // instead of at the end. That's based on the assumption that prepending + // is uncommon and even an initial prepend will eventually be followed by + // at least some appends. + int bg; + if (*idx < 0) { + *idx = 0; + bg = (alloc - nl) >> 1; + } else if (*idx > l) { + *idx = l; + bg = 0; + } else if (*idx < (l >> 1)) { + bg = (alloc - nl) >> 1; + } else { + bg = 0; + } + t->begin = bg; + t->end = bg + nl; + d = t; + + return x; +} + #if QT_VERSION >= 0x050000 # error "Remove QListData::detach(), it is only required for binary compatibility for 4.0.x to 4.2.x" #endif @@ -180,22 +227,30 @@ void QListData::realloc(int alloc) d->begin = d->end = 0; } -// ensures that enough space is available to append one element -void **QListData::append() +// ensures that enough space is available to append n elements +void **QListData::append(int n) { Q_ASSERT(d->ref == 1); - if (d->end == d->alloc) { - int n = d->end - d->begin; - if (d->begin > 2 * d->alloc / 3) { + int e = d->end; + if (e + n > d->alloc) { + int b = d->begin; + if (b - n >= 2 * d->alloc / 3) { // we have enough space. Just not at the end -> move it. - ::memcpy(d->array + n, d->array + d->begin, n * sizeof(void *)); - d->begin = n; - d->end = n * 2; + e -= b; + ::memcpy(d->array, d->array + b, e * sizeof(void *)); + d->begin = 0; } else { - realloc(grow(d->alloc + 1)); + realloc(grow(d->alloc + n)); } } - return d->array + d->end++; + d->end = e + n; + return d->array + e; +} + +// ensures that enough space is available to append one element +void **QListData::append() +{ + return append(1); } // ensures that enough space is available to append the list @@ -209,7 +264,7 @@ void **QListData::append(const QListData& l) int n = l.d->end - l.d->begin; if (n) { if (e + n > d->alloc) - realloc(grow(e + l.d->end - l.d->begin)); + realloc(grow(e + n)); ::memcpy(d->array + d->end, l.d->array + l.d->begin, n*sizeof(void*)); d->end += n; } @@ -219,15 +274,7 @@ void **QListData::append(const QListData& l) // ensures that enough space is available to append the list void **QListData::append2(const QListData& l) { - Q_ASSERT(d->ref == 1); - int e = d->end; - int n = l.d->end - l.d->begin; - if (n) { - if (e + n > d->alloc) - realloc(grow(e + n)); - d->end += n; - } - return d->array + e; + return append(l.d->end - l.d->begin); } void **QListData::prepend() @@ -253,11 +300,11 @@ void **QListData::insert(int i) Q_ASSERT(d->ref == 1); if (i <= 0) return prepend(); - if (i >= d->end - d->begin) + int size = d->end - d->begin; + if (i >= size) return append(); bool leftward = false; - int size = d->end - d->begin; if (d->begin == 0) { if (d->end == d->alloc) { diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 5364e8e..3a29e13 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -52,6 +52,7 @@ #endif #include <new> +#include <limits.h> #include <string.h> QT_BEGIN_HEADER @@ -73,6 +74,7 @@ struct Q_CORE_EXPORT QListData { enum { DataHeaderSize = sizeof(Data) - sizeof(void *) }; Data *detach(int alloc); + Data *detach_grow(int *i, int n); Data *detach(); // remove in 5.0 Data *detach2(); // remove in 5.0 Data *detach3(); // remove in 5.0 @@ -80,6 +82,7 @@ struct Q_CORE_EXPORT QListData { static Data shared_null; Data *d; void **erase(void **xi); + void **append(int n); void **append(); void **append(const QListData &l); void **append2(const QListData &l); // remove in 5.0 @@ -95,6 +98,25 @@ struct Q_CORE_EXPORT QListData { inline void **end() const { return d->array + d->end; } }; +////////////////////////////////////////////////////////////////////////////////// +// +// QtPodForSize and QtPodForType are internal and may change or go away any time. +// We mean it. +// +////////////////////////////////////////////////////////////////////////////////// +template <int N> struct QtPodForSize { + // This base type is rather obviously broken and cannot be made + // working due to alignment constraints. + // This doesn't matter as far as QList is concerned, as we are + // using this type only for QTypeInfo<T>::isLarge == false. + typedef struct { } Type; +}; +template <> struct QtPodForSize<1> { typedef quint8 Type; }; +template <> struct QtPodForSize<2> { typedef quint16 Type; }; +template <> struct QtPodForSize<4> { typedef quint32 Type; }; +template <> struct QtPodForSize<8> { typedef quint64 Type; }; +template <class T> struct QtPodForType : QtPodForSize<sizeof(T)> { }; + template <typename T> class QList { @@ -333,6 +355,7 @@ public: #endif private: + Node *detach_helper_grow(int i, int n); void detach_helper(int alloc); void detach_helper(); void free(QListData::Data *d); @@ -480,9 +503,8 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc) template <typename T> Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t) { - detach(); - if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { - Node *n = reinterpret_cast<Node *>(p.append()); + if (d->ref != 1) { + Node *n = detach_helper_grow(INT_MAX, 1); QT_TRY { node_construct(n, t); } QT_CATCH(...) { @@ -490,13 +512,24 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t) QT_RETHROW; } } else { - const T cpy(t); - Node *n = reinterpret_cast<Node *>(p.append()); - QT_TRY { - node_construct(n, cpy); - } QT_CATCH(...) { - --d->end; - QT_RETHROW; + if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { + Node *n = reinterpret_cast<Node *>(p.append()); + QT_TRY { + node_construct(n, t); + } QT_CATCH(...) { + --d->end; + QT_RETHROW; + } + } else { + typedef typename QtPodForType<T>::Type PodNode; + PodNode cpy = *reinterpret_cast<const PodNode *>(&t); + Node *n = reinterpret_cast<Node *>(p.append()); + QT_TRY { + node_construct(n, *reinterpret_cast<const T *>(&cpy)); + } QT_CATCH(...) { + --d->end; + QT_RETHROW; + } } } } @@ -504,9 +537,8 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t) template <typename T> inline void QList<T>::prepend(const T &t) { - detach(); - if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { - Node *n = reinterpret_cast<Node *>(p.prepend()); + if (d->ref != 1) { + Node *n = detach_helper_grow(0, 1); QT_TRY { node_construct(n, t); } QT_CATCH(...) { @@ -514,13 +546,24 @@ inline void QList<T>::prepend(const T &t) QT_RETHROW; } } else { - const T cpy(t); - Node *n = reinterpret_cast<Node *>(p.prepend()); - QT_TRY { - node_construct(n, cpy); - } QT_CATCH(...) { - ++d->begin; - QT_RETHROW; + if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { + Node *n = reinterpret_cast<Node *>(p.prepend()); + QT_TRY { + node_construct(n, t); + } QT_CATCH(...) { + ++d->begin; + QT_RETHROW; + } + } else { + typedef typename QtPodForType<T>::Type PodNode; + PodNode cpy = *reinterpret_cast<const PodNode *>(&t); + Node *n = reinterpret_cast<Node *>(p.prepend()); + QT_TRY { + node_construct(n, *reinterpret_cast<const T *>(&cpy)); + } QT_CATCH(...) { + ++d->begin; + QT_RETHROW; + } } } } @@ -528,9 +571,8 @@ inline void QList<T>::prepend(const T &t) template <typename T> inline void QList<T>::insert(int i, const T &t) { - detach(); - if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { - Node *n = reinterpret_cast<Node *>(p.insert(i)); + if (d->ref != 1) { + Node *n = detach_helper_grow(i, 1); QT_TRY { node_construct(n, t); } QT_CATCH(...) { @@ -538,13 +580,24 @@ inline void QList<T>::insert(int i, const T &t) QT_RETHROW; } } else { - const T cpy(t); - Node *n = reinterpret_cast<Node *>(p.insert(i)); - QT_TRY { - node_construct(n, cpy); - } QT_CATCH(...) { - p.remove(i); - QT_RETHROW; + if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { + Node *n = reinterpret_cast<Node *>(p.insert(i)); + QT_TRY { + node_construct(n, t); + } QT_CATCH(...) { + p.remove(i); + QT_RETHROW; + } + } else { + typedef typename QtPodForType<T>::Type PodNode; + PodNode cpy = *reinterpret_cast<const PodNode *>(&t); + Node *n = reinterpret_cast<Node *>(p.insert(i)); + QT_TRY { + node_construct(n, *reinterpret_cast<const T *>(&cpy)); + } QT_CATCH(...) { + p.remove(i); + QT_RETHROW; + } } } } @@ -554,12 +607,7 @@ inline void QList<T>::replace(int i, const T &t) { Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::replace", "index out of range"); detach(); - if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { - reinterpret_cast<Node *>(p.at(i))->t() = t; - } else { - const T cpy(t); - reinterpret_cast<Node *>(p.at(i))->t() = cpy; - } + reinterpret_cast<Node *>(p.at(i))->t() = t; } template <typename T> @@ -622,6 +670,36 @@ Q_OUTOFLINE_TEMPLATE T QList<T>::value(int i, const T& defaultValue) const } template <typename T> +Q_OUTOFLINE_TEMPLATE typename QList<T>::Node *QList<T>::detach_helper_grow(int i, int c) +{ + Node *n = reinterpret_cast<Node *>(p.begin()); + QListData::Data *x = p.detach_grow(&i, c); + QT_TRY { + node_copy(reinterpret_cast<Node *>(p.begin()), + reinterpret_cast<Node *>(p.begin() + i), n); + } QT_CATCH(...) { + qFree(d); + d = x; + QT_RETHROW; + } + QT_TRY { + node_copy(reinterpret_cast<Node *>(p.begin() + i + c), + reinterpret_cast<Node *>(p.end()), n + i); + } QT_CATCH(...) { + node_destruct(reinterpret_cast<Node *>(p.begin()), + reinterpret_cast<Node *>(p.begin() + i)); + qFree(d); + d = x; + QT_RETHROW; + } + + if (!x->ref.deref()) + free(x); + + return reinterpret_cast<Node *>(p.begin() + i); +} + +template <typename T> Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper(int alloc) { Node *n = reinterpret_cast<Node *>(p.begin()); @@ -730,8 +808,9 @@ Q_OUTOFLINE_TEMPLATE typename QList<T>::iterator QList<T>::erase(typename QList< template <typename T> Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l) { - detach(); - Node *n = reinterpret_cast<Node *>(p.append2(l.p)); + Node *n = (d->ref != 1) + ? detach_helper_grow(INT_MAX, l.size()) + : reinterpret_cast<Node *>(p.append2(l.p)); QT_TRY{ node_copy(n, reinterpret_cast<Node *>(p.end()), reinterpret_cast<Node *>(l.p.begin())); } QT_CATCH(...) { |