summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2010-02-23 12:02:52 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2010-02-23 12:02:52 (GMT)
commitde4332a4728e739b37e9c7b04c021e150e096270 (patch)
tree619aae505826654f3d89492efa53f758214fea6f /src/corelib
parenta419d587a666aaf55310b3a18e9f9e1993fef16e (diff)
parent3db40b0be40c946f547f238ed3f0af813892115e (diff)
downloadQt-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')
-rw-r--r--src/corelib/tools/qlist.cpp91
-rw-r--r--src/corelib/tools/qlist.h155
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(...) {