From e6b629f3ebc1d530218f01a735275e56bf474a18 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 16 Feb 2010 18:21:55 +0100 Subject: add QString(const QChar *) c'tor to complement the QString(const QChar *, int) one, which unfortunately clamps sizes below zero to zero instead of computing the length itself instead. Reviewed-by: denis Reviewed-by: joao --- src/corelib/tools/qstring.cpp | 36 +++++++++++++++++++++++++++++++++++- src/corelib/tools/qstring.h | 3 ++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index dec59b7..f85d794 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -989,6 +989,40 @@ QString::QString(const QChar *unicode, int size) } } +/*! + \since 4.7 + + Constructs a string initialized with the characters of the QChar array + \a unicode, which must be terminated with a 0. + + QString makes a deep copy of the string data. The unicode data is copied as + is and the Byte Order Mark is preserved if present. +*/ +QString::QString(const QChar *unicode) +{ + if (!unicode) { + d = &shared_null; + d->ref.ref(); + } else { + int size = 0; + while (unicode[size] != 0) + ++size; + if (!size) { + d = &shared_empty; + d->ref.ref(); + } else { + d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + Q_CHECK_PTR(d); + d->ref = 1; + d->alloc = d->size = size; + d->clean = d->asciiCache = d->simpletext = d->righttoleft = d->capacity = 0; + d->data = d->array; + memcpy(d->array, unicode, size * sizeof(QChar)); + d->array[size] = '\0'; + } + } +} + /*! Constructs a string of the given \a size with every character set @@ -3867,7 +3901,7 @@ QString QString::fromUtf8(const char *str, int size) host byte order is assumed. This function is comparatively slow. - Use QString(const ushort *, int) if possible. + Use QString(const ushort *, int) or QString(const ushort *) if possible. QString makes a deep copy of the Unicode data. diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 702a21a..8de3c7d 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -91,7 +91,8 @@ class Q_CORE_EXPORT QString { public: inline QString(); - QString(const QChar *unicode, int size); + QString(const QChar *unicode, int size); // Qt5: don't cap size < 0 + explicit QString(const QChar *unicode); // Qt5: merge with the above QString(QChar c); QString(int size, QChar c); inline QString(const QLatin1String &latin1); -- cgit v0.12 From d590fc729e3afaedf181da58f8b685d7597040da Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 16 Feb 2010 18:23:18 +0100 Subject: optimization: get rid of QString::fromUtf16() usage, part 2 QString::fromUtf16() is slow - it does a BOM check and optionally byte swapping, which is utterly irrelevant when converting internal data structures which are raw utf16 in host byte order. so replace it with QString::fromUnicode() where possible (which seems to be everywhere). the reasoning is the same as in commit e0fda52f, so not getting further reviews. Reviewed-by: denis Reviewed-by: joao --- src/3rdparty/phonon/ds9/mediagraph.cpp | 12 ++++++------ src/3rdparty/phonon/waveout/mediaobject.cpp | 2 +- src/corelib/io/qprocess_symbian.cpp | 2 +- src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp | 8 ++++---- src/multimedia/audio/qaudioinput_win32_p.cpp | 2 +- src/multimedia/audio/qaudiooutput_win32_p.cpp | 2 +- src/sql/drivers/db2/qsql_db2.cpp | 4 ++-- src/sql/drivers/oci/qsql_oci.cpp | 15 +++++++-------- src/sql/drivers/odbc/qsql_odbc.cpp | 2 +- src/sql/drivers/sqlite/qsql_sqlite.cpp | 10 +++++----- 10 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/3rdparty/phonon/ds9/mediagraph.cpp b/src/3rdparty/phonon/ds9/mediagraph.cpp index a467dd7..3e7a68b 100644 --- a/src/3rdparty/phonon/ds9/mediagraph.cpp +++ b/src/3rdparty/phonon/ds9/mediagraph.cpp @@ -379,7 +379,7 @@ namespace Phonon FILTER_INFO info; filter->QueryFilterInfo(&info); #ifdef GRAPH_DEBUG - qDebug() << "removeFilter" << QString::fromUtf16(info.achName); + qDebug() << "removeFilter" << QString((const QChar *)info.achName); #endif if (info.pGraph) { info.pGraph->Release(); @@ -875,7 +875,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName); + qDebug() << Q_FUNC_INFO << QString((const QChar *)info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -921,7 +921,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << "found a decoder filter" << QString::fromUtf16(info.achName); + qDebug() << "found a decoder filter" << QString((const QChar *)info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -937,7 +937,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName); + qDebug() << Q_FUNC_INFO << QString((const QChar *)info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -956,7 +956,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName); + qDebug() << Q_FUNC_INFO << QString((const QChar *)info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -990,7 +990,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << "found a demuxer filter" << QString::fromUtf16(info.achName); + qDebug() << "found a demuxer filter" << QString((const QChar *)info.achName); if (info.pGraph) { info.pGraph->Release(); } diff --git a/src/3rdparty/phonon/waveout/mediaobject.cpp b/src/3rdparty/phonon/waveout/mediaobject.cpp index db71942..08af4ee 100644 --- a/src/3rdparty/phonon/waveout/mediaobject.cpp +++ b/src/3rdparty/phonon/waveout/mediaobject.cpp @@ -50,7 +50,7 @@ namespace Phonon { ushort b[256]; waveOutGetErrorText(error, (LPWSTR)b, 256); - return QString::fromUtf16(b); + return QString((const QChar *)b); } class WorkerThread : public QThread diff --git a/src/corelib/io/qprocess_symbian.cpp b/src/corelib/io/qprocess_symbian.cpp index 75cde51..07d10ad 100644 --- a/src/corelib/io/qprocess_symbian.cpp +++ b/src/corelib/io/qprocess_symbian.cpp @@ -1002,7 +1002,7 @@ bool QProcessPrivate::waitForDeadChild() TExitCategoryName catName = symbianProcess->ExitCategory(); qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode" << exitCode << ", crashed:" << crashed - << ", category:" << QString::fromUtf16(catName.Ptr()); + << ", category:" << QString((const QChar *)catName.Ptr()); #endif } else { QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForDeadChild() not dead!"); diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp index 955a880..67dc90c 100644 --- a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp +++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp @@ -218,7 +218,7 @@ void QAudioDeviceInfoInternal::updateLists() for(i=0;i QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) for(i=0;i QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) for(i=0;i &storage) value = qMakeDate(storage.takeFirst()); break; case QVariant::String: - value = QString::fromUtf16( - reinterpret_cast(storage.takeFirst().constData())); + value = QString( + reinterpret_cast(storage.takeFirst().constData())); break; default: break; //nothing @@ -454,7 +454,7 @@ QString qOraWarn(OCIError *err, int *errorCode) OCI_HTYPE_ERROR); if (errorCode) *errorCode = errcode; - return QString::fromUtf16(reinterpret_cast(errbuf)); + return QString(reinterpret_cast(errbuf)); } void qOraWarning(const char* msg, OCIError *err) @@ -989,8 +989,7 @@ int QOCICols::readPiecewise(QVector &values, int index) } else { if (isStringField) { QString str = values.at(fieldNum + index).toString(); - str += QString::fromUtf16(reinterpret_cast(col), - chunkSize / 2); + str += QString(reinterpret_cast(col), chunkSize / 2); values[fieldNum + index] = str; fieldInf[fieldNum].ind = 0; } else { @@ -1457,7 +1456,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector &boundValues, b break; case SQLT_STR: - (*list)[r] = QString::fromUtf16(reinterpret_cast(data + (*list)[r] = QString(reinterpret_cast(data + r * columns[i].maxLen)); break; @@ -1608,7 +1607,7 @@ void QOCICols::getValues(QVector &v, int index) } // else fall through case QVariant::String: - v[index + i] = QString::fromUtf16(reinterpret_cast(fld.data)); + v[index + i] = QString(reinterpret_cast(fld.data)); break; case QVariant::ByteArray: if (fld.len > 0) @@ -2102,7 +2101,7 @@ bool QOCIDriver::open(const QString & db, qWarning("QOCIDriver::open: could not get Oracle server version."); } else { QString versionStr; - versionStr = QString::fromUtf16(reinterpret_cast(vertxt)); + versionStr = QString(reinterpret_cast(vertxt)); QRegExp vers(QLatin1String("([0-9]+)\\.[0-9\\.]+[0-9]")); if (vers.indexIn(versionStr) >= 0) d->serverVersion = vers.cap(1).toInt(); diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index 18bc743..fab3ab3 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -1558,7 +1558,7 @@ bool QODBCResult::exec() case QVariant::String: if (d->unicode) { if (bindValueType(i) & QSql::Out) - values[i] = QString::fromUtf16((ushort*)tmpStorage.takeFirst().constData()); + values[i] = QString((QChar *)tmpStorage.takeFirst().constData()); break; } // fall through diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp index d3be304..24dcad9 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.cpp +++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp @@ -95,7 +95,7 @@ static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::Er int errorCode = -1) { return QSqlError(descr, - QString::fromUtf16(static_cast(sqlite3_errmsg16(access))), + QString(reinterpret_cast(sqlite3_errmsg16(access))), type, errorCode); } @@ -162,13 +162,13 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset) q->init(nCols); for (int i = 0; i < nCols; ++i) { - QString colName = QString::fromUtf16( - static_cast(sqlite3_column_name16(stmt, i)) + QString colName = QString(reinterpret_cast( + sqlite3_column_name16(stmt, i)) ).remove(QLatin1Char('"')); // must use typeName for resolving the type to match QSqliteDriver::record - QString typeName = QString::fromUtf16( - static_cast(sqlite3_column_decltype16(stmt, i))); + QString typeName = QString(reinterpret_cast( + sqlite3_column_decltype16(stmt, i))); int dotIdx = colName.lastIndexOf(QLatin1Char('.')); QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), qGetColumnType(typeName)); -- cgit v0.12 From 7134f8b25a7a69960767280f9c23981b08d8e68b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 28 Jan 2010 21:02:34 +0100 Subject: add QList::reserve() while this reserves memory "only" for the pointer list, this still amounts to 100% of the re-allocs for small simple types. for big/complex/static types the gain is lower, but still. Reviewed-by: Denis Reviewed-by: Joao --- src/corelib/tools/qlist.cpp | 39 ++++++++++++++++++++++++++++++++++----- src/corelib/tools/qlist.h | 26 +++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index ce62016..ac0dc46 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -125,22 +125,23 @@ QListData::Data *QListData::detach2() } /*! - * Detaches the QListData by reallocating new memory. + * Detaches the QListData by allocating new memory for a list which possibly + * has a different size than the copied one. * 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::detach3() +QListData::Data *QListData::detach(int alloc) { Data *x = d; - Data* t = static_cast(qMalloc(DataHeaderSize + x->alloc * sizeof(void *))); + Data* t = static_cast(qMalloc(DataHeaderSize + alloc * sizeof(void *))); Q_CHECK_PTR(t); t->ref = 1; t->sharable = true; - t->alloc = x->alloc; - if (!t->alloc) { + t->alloc = alloc; + if (!alloc) { t->begin = 0; t->end = 0; } else { @@ -152,6 +153,21 @@ QListData::Data *QListData::detach3() return x; } +/*! + * Detaches the QListData by reallocating new memory. + * 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 + */ +#if QT_VERSION >= 0x050000 +# error "Remove QListData::detach3(), it is only required for binary compatibility for 4.5.x to 4.6.x" +#endif +QListData::Data *QListData::detach3() +{ + return detach(d->alloc); +} + void QListData::realloc(int alloc) { Q_ASSERT(d->ref == 1); @@ -647,6 +663,19 @@ void **QListData::erase(void **xi) Same as at(). */ +/*! \fn QList::reserve(int alloc) + + Reserve space for \a alloc elements. + + If \a alloc is smaller than the current size of the list, nothing will happen. + + Use this function to avoid repetetive reallocation of QList's internal + data if you can predict how many elements will be appended. + Note that the reservation applies only to the internal pointer array. + + \since 4.7 +*/ + /*! \fn void QList::append(const T &value) Inserts \a value at the end of the list. diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 1d08c41..3b9eefa 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -72,9 +72,10 @@ struct Q_CORE_EXPORT QListData { }; enum { DataHeaderSize = sizeof(Data) - sizeof(void *) }; + Data *detach(int alloc); Data *detach(); // remove in 5.0 Data *detach2(); // remove in 5.0 - Data *detach3(); + Data *detach3(); // remove in 5.0 void realloc(int alloc); static Data shared_null; Data *d; @@ -140,6 +141,7 @@ public: 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); @@ -331,6 +333,7 @@ public: #endif private: + void detach_helper(int alloc); void detach_helper(); void free(QListData::Data *d); @@ -464,6 +467,17 @@ 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 != 1) + detach_helper(alloc); + else + p.realloc(alloc); + } +} + +template Q_OUTOFLINE_TEMPLATE void QList::append(const T &t) { detach(); @@ -599,10 +613,10 @@ Q_OUTOFLINE_TEMPLATE T QList::value(int i, const T& defaultValue) const } template -Q_OUTOFLINE_TEMPLATE void QList::detach_helper() +Q_OUTOFLINE_TEMPLATE void QList::detach_helper(int alloc) { Node *n = reinterpret_cast(p.begin()); - QListData::Data *x = p.detach3(); + QListData::Data *x = p.detach(alloc); QT_TRY { node_copy(reinterpret_cast(p.begin()), reinterpret_cast(p.end()), n); } QT_CATCH(...) { @@ -616,6 +630,12 @@ Q_OUTOFLINE_TEMPLATE void QList::detach_helper() } template +Q_OUTOFLINE_TEMPLATE void QList::detach_helper() +{ + detach_helper(d->alloc); +} + +template Q_OUTOFLINE_TEMPLATE QList::~QList() { if (d && !d->ref.deref()) -- cgit v0.12 From 5723f1bcb538a5624cbed871c34507ff26285878 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 28 Jan 2010 21:05:21 +0100 Subject: optimization: use QList::reserve() in QSet::toList() Reviewed-by: Denis Reviewed-by: Joao --- src/corelib/tools/qset.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index 6525880..9acbed4 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -292,6 +292,7 @@ template Q_OUTOFLINE_TEMPLATE QList QSet::toList() const { QList result; + result.reserve(size()); typename QSet::const_iterator i = constBegin(); while (i != constEnd()) { result.append(*i); -- cgit v0.12 From c03b21d272f617b037ad9d0ccaa2f442638bf302 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 28 Jan 2010 21:07:18 +0100 Subject: optimize QList::mid() instead of append()ing each element separately, reserve enough space and do a low-level node copy. obviously, the gain for small simple types is the biggest. Reviewed-by: joao Reviewed-by: denis --- src/corelib/tools/qlist.h | 15 ++++++++++++--- tests/auto/qlist/tst_qlist.cpp | 10 ++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 3b9eefa..8c75c98 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -589,11 +589,20 @@ Q_OUTOFLINE_TEMPLATE QList QList::mid(int pos, int alength) const 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); + QList 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; } diff --git a/tests/auto/qlist/tst_qlist.cpp b/tests/auto/qlist/tst_qlist.cpp index 59b2c7b..a590fca 100644 --- a/tests/auto/qlist/tst_qlist.cpp +++ b/tests/auto/qlist/tst_qlist.cpp @@ -60,6 +60,7 @@ private slots: void length() const; void lengthSignature() const; void append() const; + void mid() const; }; void tst_QList::length() const @@ -129,5 +130,14 @@ void tst_QList::append() const } +void tst_QList::mid() const +{ + QList list; + list << "foo" << "bar" << "baz" << "bak" << "buck" << "hello" << "kitty"; + + QCOMPARE(list.mid(3, 3), + QList() << "bak" << "buck" << "hello"); +} + QTEST_APPLESS_MAIN(tst_QList) #include "tst_qlist.moc" -- cgit v0.12 From 82027baa2c7705ae49300ce3ca0ac9eb4add2e96 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 16 Feb 2010 13:00:07 +0100 Subject: optimize qHash() some more on modern architectures, a longer data dependency chain is worse than a slightly bigger instruction. as it happens, the code is also clearer. would you have guessed that qHash() is only 28 bits wide? Reviewed-by: joao Reviewed-by: denis --- src/corelib/tools/qhash.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 285f4c9..85a8b63 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -64,13 +64,11 @@ QT_BEGIN_NAMESPACE static uint hash(const uchar *p, int n) { uint h = 0; - uint g; while (n--) { h = (h << 4) + *p++; - g = h & 0xf0000000; - h ^= g >> 23; - h &= ~g; + h ^= (h & 0xf0000000) >> 23; + h &= 0x0fffffff; } return h; } @@ -78,13 +76,11 @@ static uint hash(const uchar *p, int n) static uint hash(const QChar *p, int n) { uint h = 0; - uint g; while (n--) { h = (h << 4) + (*p++).unicode(); - g = h & 0xf0000000; - h ^= g >> 23; - h &= ~g; + h ^= (h & 0xf0000000) >> 23; + h &= 0x0fffffff; } return h; } -- cgit v0.12 From 5af4e7d0e44be7d35c38c439fa9fc42f54ccd09b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 16 Feb 2010 15:37:44 +0100 Subject: avoid double reallocation in string-growing replace() case detach() followed by resize() is suboptimal, as it first creates an identically sized copy, and then a differently sized one. Reviewed-by: joao Reviewed-by: denis --- src/corelib/tools/qstring.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index f85d794..cce313b 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1800,13 +1800,14 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar } QT_TRY { - detach(); if (blen == alen) { // replace in place + detach(); for (int i = 0; i < nIndices; ++i) memcpy(d->data + indices[i], afterBuffer, alen * sizeof(QChar)); } else if (alen < blen) { // replace from front + detach(); uint to = indices[0]; if (alen) memcpy(d->data+to, after, alen*sizeof(QChar)); -- cgit v0.12 From 02135be18f3c4b1d1525aff6dfe96c9c8521084d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 16 Feb 2010 15:44:41 +0100 Subject: avoid double reallocations in appending operations operator+=() and co. would first detach, and then realloc if they found the reservation too small. in particular, appending anything to an empty list would trigger this double reallocation (first copy shared_null, then grow the copy). Reviewed-by: joao Reviewed-by: denis --- src/corelib/tools/qlist.cpp | 18 ++++++++++++++++++ src/corelib/tools/qlist.h | 28 ++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index ac0dc46..a468c77 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -154,6 +154,19 @@ QListData::Data *QListData::detach(int alloc) } /*! + * Detaches the QListData by allocating new memory for a list which will be bigger + * than the copied one and is expected to grow further. + * 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 alloc) +{ + return detach(grow(alloc)); +} + +/*! * Detaches the QListData by reallocating new memory. * 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. @@ -596,6 +609,11 @@ void **QListData::erase(void **xi) \internal */ +/*! \fn void QList::detach_grow(int alloc) + + \internal +*/ + /*! \fn void QList::detachShared() \internal diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 8c75c98..1edac03 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -73,6 +73,7 @@ struct Q_CORE_EXPORT QListData { enum { DataHeaderSize = sizeof(Data) - sizeof(void *) }; Data *detach(int alloc); + Data *detach_grow(int alloc); Data *detach(); // remove in 5.0 Data *detach2(); // remove in 5.0 Data *detach3(); // remove in 5.0 @@ -121,6 +122,7 @@ public: inline int size() const { return p.size(); } inline void detach() { if (d->ref != 1) detach_helper(); } + inline void detach_grow(int by) { if (d->ref != 1) detach_helper_grow(d->end - d->begin + by); } inline void detachShared() { @@ -333,6 +335,7 @@ public: #endif private: + void detach_helper_grow(int alloc); void detach_helper(int alloc); void detach_helper(); void free(QListData::Data *d); @@ -480,7 +483,7 @@ Q_OUTOFLINE_TEMPLATE void QList::reserve(int alloc) template Q_OUTOFLINE_TEMPLATE void QList::append(const T &t) { - detach(); + detach_grow(1); if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.append()); QT_TRY { @@ -504,7 +507,7 @@ Q_OUTOFLINE_TEMPLATE void QList::append(const T &t) template inline void QList::prepend(const T &t) { - detach(); + detach_grow(1); if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.prepend()); QT_TRY { @@ -528,7 +531,7 @@ inline void QList::prepend(const T &t) template inline void QList::insert(int i, const T &t) { - detach(); + detach_grow(1); if (QTypeInfo::isLarge || QTypeInfo::isStatic) { Node *n = reinterpret_cast(p.insert(i)); QT_TRY { @@ -622,6 +625,23 @@ Q_OUTOFLINE_TEMPLATE T QList::value(int i, const T& defaultValue) const } template +Q_OUTOFLINE_TEMPLATE void QList::detach_helper_grow(int alloc) +{ + Node *n = reinterpret_cast(p.begin()); + QListData::Data *x = p.detach_grow(alloc); + 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 void QList::detach_helper(int alloc) { Node *n = reinterpret_cast(p.begin()); @@ -730,7 +750,7 @@ Q_OUTOFLINE_TEMPLATE typename QList::iterator QList::erase(typename QList< template Q_OUTOFLINE_TEMPLATE QList &QList::operator+=(const QList &l) { - detach(); + detach_grow(l.size()); Node *n = reinterpret_cast(p.append2(l.p)); QT_TRY{ node_copy(n, reinterpret_cast(p.end()), reinterpret_cast(l.p.begin())); -- cgit v0.12