From 26a6d3f11b5a88fb2b6564384429eadffc3f16c3 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 4 Jul 2011 14:03:23 +0200 Subject: Fix compilation with c++0x mode Change-Id: Ie4f157f25c31e46d4cc7cb628b8605b99561a4e8 Reviewed-on: http://codereview.qt.nokia.com/1220 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qstringlist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h index efb7f46c9b..bded94399d 100644 --- a/src/corelib/tools/qstringlist.h +++ b/src/corelib/tools/qstringlist.h @@ -68,7 +68,7 @@ public: inline QStringList(const QStringList &l) : QList(l) { } inline QStringList(const QList &l) : QList(l) { } #ifdef Q_COMPILER_INITIALIZER_LISTS - inline QStringList(std::initializer_list args) : QList(args) { } + inline QStringList(std::initializer_list args) : QList(args) { } #endif inline void sort(); -- cgit v1.2.3 From fcca106e590ba550c536a6b8de1b011ccc2c0d30 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 6 Jul 2011 09:17:00 +0200 Subject: Add an internal QRefCount class to QtCore The class will be used by QString and possibly other container classes to allow for the Data objects to be created at compile time in read-only memory. Change-Id: I9c7538bc97df637cc920e6e5ef23d67a93abac0d Reviewed-on: http://codereview.qt.nokia.com/1216 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qrefcount.cpp | 51 +++++++++++++++++++++++ src/corelib/tools/qrefcount.h | 92 +++++++++++++++++++++++++++++++++++++++++ src/corelib/tools/tools.pri | 2 + 3 files changed, 145 insertions(+) create mode 100644 src/corelib/tools/qrefcount.cpp create mode 100644 src/corelib/tools/qrefcount.h (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qrefcount.cpp b/src/corelib/tools/qrefcount.cpp new file mode 100644 index 0000000000..c40214b2ab --- /dev/null +++ b/src/corelib/tools/qrefcount.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QtPrivate::RefCount + \internal + + QRefCount implements atomic ref counting for Qt's shared classes. It behaves very similar + to QAtomicInt, but ignores negative ref counts. + + This can be used to allow to implement e.g. const read-only QStringData objects. QString::shared_null and + the qs(...) macro make use of this feature. +*/ diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h new file mode 100644 index 0000000000..9223cfe352 --- /dev/null +++ b/src/corelib/tools/qrefcount.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QREFCOUNT_H +#define QREFCOUNT_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +namespace QtPrivate +{ + +class RefCount +{ +public: + inline void ref() { + if (atomic >= 0) + atomic.ref(); + } + + inline bool deref() { + if (atomic < 0) + return true; + return atomic.deref(); + } + + inline bool operator==(int value) const + { return atomic.operator ==(value); } + inline bool operator!=(int value) const + { return atomic.operator !=(value); } + inline bool operator!() const + { return atomic.operator !(); } + inline operator int() const + { return atomic.operator int(); } + inline RefCount &operator=(int value) + { atomic = value; return *this; } + + QBasicAtomicInt atomic; +}; + +#define Q_REFCOUNT_INITIALIZER(a) { Q_BASIC_ATOMIC_INITIALIZER(a) } + +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 42cab84cc0..f5b38eb1c0 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -30,6 +30,7 @@ HEADERS += \ tools/qrect.h \ tools/qregexp.h \ tools/qringbuffer_p.h \ + tools/qrefcount.h \ tools/qscopedpointer.h \ tools/qscopedpointer_p.h \ tools/qscopedvaluerollback.h \ @@ -72,6 +73,7 @@ SOURCES += \ tools/qcontiguouscache.cpp \ tools/qrect.cpp \ tools/qregexp.cpp \ + tools/qrefcount.cpp \ tools/qshareddata.cpp \ tools/qsharedpointer.cpp \ tools/qsimd.cpp \ -- cgit v1.2.3 From ee85e9cc10bc6874c892b09fa54b5dbd79854069 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 6 Jul 2011 09:21:10 +0200 Subject: Support for compile time generated QStrings use with QString string(QStringLiteral("foo")) or QString string(qs("foo")). qs(...) can in almost all places replace QLatin1String. the Macro qs requires c++0x support or a compiler where sizeof(wchar_t) == 2. In case these conditions are not met, qs simply falls back to QLatin1String. The commit also cleans up the QStringData structure significantly, now using only 16 bytes for the header on 32 bit systems. The bitflags to store unicode directionality of the string and whether the string would require complex text processing to render are removed. They don't really belong here and the result can be calculated very fast in any case. Added an internal QRefCount class the encapsulates the reference counting semantics required where a negative refcount is never changed. This is required to be able to put the string data into a constant POD object. Change-Id: I5b1395213deca48b2d582a036a0e8a8358d26d14 Reviewed-on: http://codereview.qt.nokia.com/1218 Reviewed-by: Olivier Goffart Reviewed-by: Lars Knoll --- src/corelib/tools/qstring.cpp | 439 +++++++++++++++++++----------------------- src/corelib/tools/qstring.h | 130 +++++++++---- 2 files changed, 287 insertions(+), 282 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index afb396ce50..eb5804b254 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -797,10 +797,8 @@ const QString::Null QString::null = { }; \sa split() */ -QString::Data QString::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), - 0, 0, shared_null.array, 0, 0, 0, 0, 0, {0} }; -QString::Data QString::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), - 0, 0, shared_empty.array, 0, 0, 0, 0, 0, {0} }; +const QConstStringData<1> QString::shared_null = (const QConstStringData<1>) { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; +const QConstStringData<1> QString::shared_empty = (const QConstStringData<1>) { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; int QString::grow(int size) { @@ -1044,20 +1042,15 @@ int QString::toWCharArray(wchar_t *array) const QString::QString(const QChar *unicode, int size) { if (!unicode) { - d = &shared_null; - d->ref.ref(); + d = const_cast(&shared_null.str); } else if (size <= 0) { - d = &shared_empty; - d->ref.ref(); + d = const_cast(&shared_empty.str); } else { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - memcpy(d->array, unicode, size * sizeof(QChar)); - d->array[size] = '\0'; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + memcpy(d->data(), unicode, size * sizeof(QChar)); + d->data()[size] = '\0'; } } @@ -1073,24 +1066,19 @@ QString::QString(const QChar *unicode, int size) QString::QString(const QChar *unicode) { if (!unicode) { - d = &shared_null; - d->ref.ref(); + d = const_cast(&shared_null.str); } else { int size = 0; while (unicode[size] != 0) ++size; if (!size) { - d = &shared_empty; - d->ref.ref(); + d = const_cast(&shared_empty.str); } else { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - memcpy(d->array, unicode, size * sizeof(QChar)); - d->array[size] = '\0'; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + memcpy(d->data(), unicode, size * sizeof(QChar)); + d->data()[size] = '\0'; } } } @@ -1105,18 +1093,14 @@ QString::QString(const QChar *unicode) QString::QString(int size, QChar ch) { if (size <= 0) { - d = &shared_empty; - d->ref.ref(); + d = const_cast(&shared_empty.str); } else { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[size] = '\0'; - ushort *i = d->array + size; - ushort *b = d->array; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + d->data()[size] = '\0'; + ushort *i = d->data() + size; + ushort *b = d->data(); const ushort value = ch.unicode(); while (i != b) *--i = value; @@ -1131,13 +1115,10 @@ QString::QString(int size, QChar ch) */ QString::QString(int size, Qt::Initialization) { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[size] = '\0'; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + d->data()[size] = '\0'; } /*! \fn QString::QString(const QLatin1String &str) @@ -1152,15 +1133,11 @@ QString::QString(int size, Qt::Initialization) */ QString::QString(QChar ch) { - void *buf = qMalloc(sizeof(Data) + sizeof(QChar)); - Q_CHECK_PTR(buf); - d = reinterpret_cast(buf); - d->ref = 1; - d->alloc = d->size = 1; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[0] = ch.unicode(); - d->array[1] = '\0'; + d = (Data *) qMalloc(sizeof(Data) + 2*sizeof(QChar)); + Q_CHECK_PTR(d); + *d = (Data) { Q_REFCOUNT_INITIALIZER(1), 1, 1, false, { 0 } }; + d->data()[0] = ch.unicode(); + d->data()[1] = '\0'; } /*! \fn QString::QString(const QByteArray &ba) @@ -1256,21 +1233,23 @@ void QString::resize(int size) if (size < 0) size = 0; - if (size == 0 && !d->capacity) { - Data *x = &shared_empty; - x->ref.ref(); + if (d->offset && d->ref == 1 && size < d->size) { + d->size = size; + return; + } + + if (size == 0 && !d->capacityReserved) { + Data *x = const_cast(&shared_empty.str); if (!d->ref.deref()) QString::free(d); d = x; } else { if (d->ref != 1 || size > d->alloc || - (!d->capacity && size < d->size && size < d->alloc >> 1)) + (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) realloc(grow(size)); if (d->alloc >= size) { d->size = size; - if (d->data == d->array) { - d->array[size] = '\0'; - } + d->data()[size] = '\0'; } } } @@ -1328,28 +1307,21 @@ void QString::resize(int size) // ### Qt 5: rename reallocData() to avoid confusion. 197625 void QString::realloc(int alloc) { - if (d->ref != 1 || d->data != d->array) { - Data *x = static_cast(qMalloc(sizeof(Data) + alloc * sizeof(QChar))); + if (d->ref != 1 || d->offset) { + Data *x = static_cast(qMalloc(sizeof(Data) + (alloc+1) * sizeof(QChar))); Q_CHECK_PTR(x); - x->size = qMin(alloc, d->size); - ::memcpy(x->array, d->data, x->size * sizeof(QChar)); - x->array[x->size] = 0; - x->ref = 1; - x->alloc = alloc; - x->clean = d->clean; - x->simpletext = d->simpletext; - x->righttoleft = d->righttoleft; - x->capacity = d->capacity; - x->data = x->array; + *x = (Data){ Q_REFCOUNT_INITIALIZER(1), qMin(alloc, d->size), alloc, d->capacityReserved, { 0 } }; + ::memcpy(x->data(), d->data(), x->size * sizeof(QChar)); + x->data()[x->size] = 0; if (!d->ref.deref()) QString::free(d); d = x; } else { - Data *p = static_cast(qRealloc(d, sizeof(Data) + alloc * sizeof(QChar))); + Data *p = static_cast(qRealloc(d, sizeof(Data) + (alloc+1) * sizeof(QChar))); Q_CHECK_PTR(p); d = p; d->alloc = alloc; - d->data = d->array; + d->offset = 0; } } @@ -1363,8 +1335,8 @@ void QString::expand(int i) int sz = d->size; resize(qMax(i + 1, sz)); if (d->size - 1 > sz) { - ushort *n = d->data + d->size - 1; - ushort *e = d->data + sz; + ushort *n = d->data() + d->size - 1; + ushort *e = d->data() + sz; while (n != e) * --n = ' '; } @@ -1482,9 +1454,9 @@ QString &QString::insert(int i, const QLatin1String &str) int len = qstrlen(str.latin1()); expand(qMax(d->size, i) + len - 1); - ::memmove(d->data + i + len, d->data + i, (d->size - i - len) * sizeof(QChar)); + ::memmove(d->data() + i + len, d->data() + i, (d->size - i - len) * sizeof(QChar)); for (int j = 0; j < len; ++j) - d->data[i + j] = s[j]; + d->data()[i + j] = s[j]; return *this; } @@ -1501,7 +1473,7 @@ QString& QString::insert(int i, const QChar *unicode, int size) return *this; const ushort *s = (const ushort *)unicode; - if (s >= d->data && s < d->data + d->alloc) { + if (s >= d->data() && s < d->data() + d->alloc) { // Part of me - take a copy ushort *tmp = static_cast(qMalloc(size * sizeof(QChar))); Q_CHECK_PTR(tmp); @@ -1513,8 +1485,8 @@ QString& QString::insert(int i, const QChar *unicode, int size) expand(qMax(d->size, i) + size - 1); - ::memmove(d->data + i + size, d->data + i, (d->size - i - size) * sizeof(QChar)); - memcpy(d->data + i, s, size * sizeof(QChar)); + ::memmove(d->data() + i + size, d->data() + i, (d->size - i - size) * sizeof(QChar)); + memcpy(d->data() + i, s, size * sizeof(QChar)); return *this; } @@ -1532,8 +1504,8 @@ QString& QString::insert(int i, QChar ch) if (i < 0) return *this; expand(qMax(i, d->size)); - ::memmove(d->data + i + 1, d->data + i, (d->size - i) * sizeof(QChar)); - d->data[i] = ch.unicode(); + ::memmove(d->data() + i + 1, d->data() + i, (d->size - i) * sizeof(QChar)); + d->data()[i] = ch.unicode(); return *this; } @@ -1557,15 +1529,15 @@ QString& QString::insert(int i, QChar ch) */ QString &QString::append(const QString &str) { - if (str.d != &shared_null) { - if (d == &shared_null) { + if (str.d != &shared_null.str) { + if (d == &shared_null.str) { operator=(str); } else { if (d->ref != 1 || d->size + str.d->size > d->alloc) realloc(grow(d->size + str.d->size)); - memcpy(d->data + d->size, str.d->data, str.d->size * sizeof(QChar)); + memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); d->size += str.d->size; - d->data[d->size] = '\0'; + d->data()[d->size] = '\0'; } } return *this; @@ -1583,7 +1555,7 @@ QString &QString::append(const QLatin1String &str) int len = qstrlen((char *)s); if (d->ref != 1 || d->size + len > d->alloc) realloc(grow(d->size + len)); - ushort *i = d->data + d->size; + ushort *i = d->data() + d->size; while ((*i++ = *s++)) ; d->size += len; @@ -1626,8 +1598,8 @@ QString &QString::append(QChar ch) { if (d->ref != 1 || d->size + 1 > d->alloc) realloc(grow(d->size + 1)); - d->data[d->size++] = ch.unicode(); - d->data[d->size] = '\0'; + d->data()[d->size++] = ch.unicode(); + d->data()[d->size] = '\0'; return *this; } @@ -1707,7 +1679,7 @@ QString &QString::remove(int pos, int len) resize(pos); // truncate } else if (len > 0) { detach(); - memmove(d->data + pos, d->data + pos + len, + memmove(d->data() + pos, d->data() + pos + len, (d->size - pos - len + 1) * sizeof(ushort)); d->size -= len; } @@ -1756,14 +1728,14 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs) ushort c = ch.unicode(); if (cs == Qt::CaseSensitive) { while (i < d->size) - if (d->data[i] == ch) + if (d->data()[i] == ch) remove(i, 1); else i++; } else { c = foldCase(c); while (i < d->size) - if (foldCase(d->data[i]) == c) + if (foldCase(d->data()[i]) == c) remove(i, 1); else i++; @@ -1859,10 +1831,10 @@ QString &QString::replace(const QString &before, const QString &after, Qt::CaseS */ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen) { - // copy *after in case it lies inside our own d->data area + // copy *after in case it lies inside our own d->data() area // (which we could possibly invalidate via a realloc or corrupt via memcpy operations.) QChar *afterBuffer = const_cast(after); - if (after >= reinterpret_cast(d->data) && after < reinterpret_cast(d->data) + d->size) { + if (after >= reinterpret_cast(d->data()) && after < reinterpret_cast(d->data()) + d->size) { afterBuffer = static_cast(qMalloc(alen*sizeof(QChar))); Q_CHECK_PTR(afterBuffer); ::memcpy(afterBuffer, after, alen*sizeof(QChar)); @@ -1873,30 +1845,30 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar // replace in place detach(); for (int i = 0; i < nIndices; ++i) - memcpy(d->data + indices[i], afterBuffer, alen * sizeof(QChar)); + 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)); + memcpy(d->data()+to, after, alen*sizeof(QChar)); to += alen; uint movestart = indices[0] + blen; for (int i = 1; i < nIndices; ++i) { int msize = indices[i] - movestart; if (msize > 0) { - memmove(d->data + to, d->data + movestart, msize * sizeof(QChar)); + memmove(d->data() + to, d->data() + movestart, msize * sizeof(QChar)); to += msize; } if (alen) { - memcpy(d->data + to, afterBuffer, alen*sizeof(QChar)); + memcpy(d->data() + to, afterBuffer, alen*sizeof(QChar)); to += alen; } movestart = indices[i] + blen; } int msize = d->size - movestart; if (msize > 0) - memmove(d->data + to, d->data + movestart, msize * sizeof(QChar)); + memmove(d->data() + to, d->data() + movestart, msize * sizeof(QChar)); resize(d->size - nIndices*(blen-alen)); } else { // replace from back @@ -1910,9 +1882,9 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar int movestart = indices[nIndices] + blen; int insertstart = indices[nIndices] + nIndices*(alen-blen); int moveto = insertstart + alen; - memmove(d->data + moveto, d->data + movestart, + memmove(d->data() + moveto, d->data() + movestart, (moveend - movestart)*sizeof(QChar)); - memcpy(d->data + insertstart, afterBuffer, alen*sizeof(QChar)); + memcpy(d->data() + insertstart, afterBuffer, alen*sizeof(QChar)); moveend = movestart-blen; } } @@ -1994,7 +1966,7 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs return remove(ch, cs); if (after.d->size == 1) - return replace(ch, after.d->data[0], cs); + return replace(ch, after.d->data()[0], cs); if (d->size == 0) return *this; @@ -2007,13 +1979,13 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs uint pos = 0; if (cs == Qt::CaseSensitive) { while (pos < 1023 && index < d->size) { - if (d->data[index] == cc) + if (d->data()[index] == cc) indices[pos++] = index; index++; } } else { while (pos < 1023 && index < d->size) { - if (QChar::toCaseFolded(d->data[index]) == cc) + if (QChar::toCaseFolded(d->data()[index]) == cc) indices[pos++] = index; index++; } @@ -2045,7 +2017,7 @@ QString& QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs) ushort b = before.unicode(); if (d->size) { detach(); - ushort *i = d->data; + ushort *i = d->data(); const ushort *e = i + d->size; if (cs == Qt::CaseSensitive) { for (; i != e; ++i) @@ -2170,7 +2142,7 @@ bool QString::operator==(const QString &other) const if (d->size != other.d->size) return false; - return qMemEquals(d->data, other.d->data, d->size); + return qMemEquals(d->data(), other.d->data(), d->size); } /*! @@ -2178,7 +2150,7 @@ bool QString::operator==(const QString &other) const */ bool QString::operator==(const QLatin1String &other) const { - const ushort *uc = d->data; + const ushort *uc = d->data(); const ushort *e = uc + d->size; const uchar *c = (uchar *)other.latin1(); @@ -2240,7 +2212,7 @@ bool QString::operator<(const QString &other) const */ bool QString::operator<(const QLatin1String &other) const { - const ushort *uc = d->data; + const ushort *uc = d->data(); const ushort *e = uc + d->size; const uchar *c = (uchar *) other.latin1(); @@ -2342,7 +2314,7 @@ bool QString::operator<(const QLatin1String &other) const */ bool QString::operator>(const QLatin1String &other) const { - const ushort *uc = d->data;; + const ushort *uc = d->data();; const ushort *e = uc + d->size; const uchar *c = (uchar *) other.latin1(); @@ -2687,7 +2659,7 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c { const int sl = str.d->size; if (sl == 1) - return lastIndexOf(QChar(str.d->data[0]), from, cs); + return lastIndexOf(QChar(str.d->data()[0]), from, cs); const int l = d->size; if (from < 0) @@ -2700,7 +2672,7 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c if (from > delta) from = delta; - return lastIndexOfHelper(d->data, from, str.d->data, str.d->size, cs); + return lastIndexOfHelper(d->data(), from, str.d->data(), str.d->size, cs); } /*! @@ -2743,7 +2715,7 @@ int QString::lastIndexOf(const QLatin1String &str, int from, Qt::CaseSensitivity for (int i = 0; i < sl; ++i) s[i] = str.latin1()[i]; - return lastIndexOfHelper(d->data, from, s.data(), sl, cs); + return lastIndexOfHelper(d->data(), from, s.data(), sl, cs); } /*! @@ -2789,7 +2761,7 @@ int QString::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs if (from > delta) from = delta; - return lastIndexOfHelper(d->data, from, reinterpret_cast(str.unicode()), + return lastIndexOfHelper(d->data(), from, reinterpret_cast(str.unicode()), str.size(), cs); } @@ -2940,14 +2912,14 @@ QString& QString::replace(const QRegExp &rx, const QString &after) while (i < pos) { int copyend = replacements[i].pos; int size = copyend - copystart; - memcpy(uc, d->data + copystart, size * sizeof(QChar)); + memcpy(uc, d->data() + copystart, size * sizeof(QChar)); uc += size; - memcpy(uc, after.d->data, al * sizeof(QChar)); + memcpy(uc, after.d->data(), al * sizeof(QChar)); uc += al; copystart = copyend + replacements[i].length; i++; } - memcpy(uc, d->data + copystart, (d->size - copystart) * sizeof(QChar)); + memcpy(uc, d->data() + copystart, (d->size - copystart) * sizeof(QChar)); newstring.resize(newlen); *this = newstring; caretMode = QRegExp::CaretWontMatch; @@ -3366,7 +3338,7 @@ QString QString::left(int n) const { if (n >= d->size || n < 0) return *this; - return QString((const QChar*) d->data, n); + return QString((const QChar*) d->data(), n); } /*! @@ -3384,7 +3356,7 @@ QString QString::right(int n) const { if (n >= d->size || n < 0) return *this; - return QString((const QChar*) d->data + d->size - n, n); + return QString((const QChar*) d->data() + d->size - n, n); } /*! @@ -3406,7 +3378,7 @@ QString QString::right(int n) const QString QString::mid(int position, int n) const { - if (d == &shared_null || position >= d->size) + if (d == &shared_null.str || position >= d->size) return QString(); if (n < 0) n = d->size - position; @@ -3418,7 +3390,7 @@ QString QString::mid(int position, int n) const n = d->size - position; if (position == 0 && n == d->size) return *this; - return QString((const QChar*) d->data + position, n); + return QString((const QChar*) d->data() + position, n); } /*! @@ -3456,8 +3428,8 @@ bool QString::startsWith(const QChar &c, Qt::CaseSensitivity cs) const { return d->size && (cs == Qt::CaseSensitive - ? d->data[0] == c - : foldCase(d->data[0]) == foldCase(c.unicode())); + ? d->data()[0] == c + : foldCase(d->data()[0]) == foldCase(c.unicode())); } /*! @@ -3530,8 +3502,8 @@ bool QString::endsWith(const QChar &c, Qt::CaseSensitivity cs) const { return d->size && (cs == Qt::CaseSensitive - ? d->data[d->size - 1] == c - : foldCase(d->data[d->size - 1]) == foldCase(c.unicode())); + ? d->data()[d->size - 1] == c + : foldCase(d->data()[d->size - 1]) == foldCase(c.unicode())); } /*! \fn const char *QString::ascii() const @@ -3765,22 +3737,17 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size) { Data *d; if (!str) { - d = &shared_null; - d->ref.ref(); + d = const_cast(&shared_null.str); } else if (size == 0 || (!*str && size < 0)) { - d = &shared_empty; - d->ref.ref(); + d = const_cast(&shared_empty.str); } else { if (size < 0) size = qstrlen(str); - d = static_cast(qMalloc(sizeof(Data) + size * sizeof(QChar))); + d = static_cast(qMalloc(sizeof(Data) + (size+1) * sizeof(QChar))); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[size] = '\0'; - ushort *dst = d->data; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + d->data()[size] = '\0'; + ushort *dst = d->data(); /* SIMD: * Unpacking with SSE has been shown to improve performance on recent CPUs * The same method gives no improvement with NEON. @@ -3818,11 +3785,9 @@ QString::Data *QString::fromAscii_helper(const char *str, int size) if (codecForCStrings) { Data *d; if (!str) { - d = &shared_null; - d->ref.ref(); + d = const_cast(&shared_null.str); } else if (size == 0 || (!*str && size < 0)) { - d = &shared_empty; - d->ref.ref(); + d = const_cast(&shared_empty.str); } else { if (size < 0) size = qstrlen(str); @@ -3995,7 +3960,7 @@ QString& QString::setUnicode(const QChar *unicode, int size) { resize(size); if (unicode && size) - memcpy(d->data, unicode, size * sizeof(QChar)); + memcpy(d->data(), unicode, size * sizeof(QChar)); return *this; } @@ -4034,7 +3999,7 @@ QString QString::simplified() const if (d->size == 0) return *this; - const QChar * const start = reinterpret_cast(d->data); + const QChar * const start = reinterpret_cast(d->data()); const QChar *from = start; const QChar *fromEnd = start + d->size; forever { @@ -4043,8 +4008,7 @@ QString QString::simplified() const break; if (++from == fromEnd) { // All-whitespace string - shared_empty.ref.ref(); - return QString(&shared_empty, 0); + return QString(shared_empty); } } // This loop needs no underflow check, as we already determined that @@ -4079,7 +4043,7 @@ QString QString::simplified() const // of already simplified characters - at least one, obviously - // without a trailing space. QString result((fromEnd - from) + copyCount, Qt::Uninitialized); - QChar *to = reinterpret_cast(result.d->data); + QChar *to = reinterpret_cast(result.d->data()); ::memcpy(to, copyFrom, copyCount * 2); to += copyCount; fromEnd--; @@ -4100,7 +4064,7 @@ QString QString::simplified() const } done: *to++ = ch; - result.truncate(to - reinterpret_cast(result.d->data)); + result.truncate(to - reinterpret_cast(result.d->data())); return result; } @@ -4124,7 +4088,7 @@ QString QString::trimmed() const { if (d->size == 0) return *this; - const QChar *s = (const QChar*)d->data; + const QChar *s = (const QChar*)d->data(); if (!s->isSpace() && !s[d->size-1].isSpace()) return *this; int start = 0; @@ -4137,8 +4101,7 @@ QString QString::trimmed() const } int l = end - start + 1; if (l <= 0) { - shared_empty.ref.ref(); - return QString(&shared_empty, 0); + return QString(shared_empty); } return QString(s + start, l); } @@ -4250,8 +4213,8 @@ QString& QString::fill(QChar ch, int size) { resize(size < 0 ? d->size : size); if (d->size) { - QChar *i = (QChar*)d->data + d->size; - QChar *b = (QChar*)d->data; + QChar *i = (QChar*)d->data() + d->size; + QChar *b = (QChar*)d->data(); while (i != b) *--i = ch; } @@ -4597,7 +4560,7 @@ int QString::compare(const QString &other, Qt::CaseSensitivity cs) const { if (cs == Qt::CaseSensitive) return ucstrcmp(constData(), length(), other.constData(), other.length()); - return ucstricmp(d->data, d->data + d->size, other.d->data, other.d->data + other.d->size); + return ucstricmp(d->data(), d->data() + d->size, other.d->data(), other.d->data() + other.d->size); } /*! @@ -4828,12 +4791,9 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1, const ushort *QString::utf16() const { - if (d->data != d->array) { - QString *that = const_cast(this); - that->realloc(); // ensure '\\0'-termination for ::fromRawData strings - return that->d->data; - } - return d->array; + if (d->offset) + const_cast(this)->realloc(); // ensure '\\0'-termination for ::fromRawData strings + return d->data(); } /*! @@ -4862,8 +4822,8 @@ QString QString::leftJustified(int width, QChar fill, bool truncate) const if (padlen > 0) { result.resize(len+padlen); if (len) - memcpy(result.d->data, d->data, sizeof(QChar)*len); - QChar *uc = (QChar*)result.d->data + len; + memcpy(result.d->data(), d->data(), sizeof(QChar)*len); + QChar *uc = (QChar*)result.d->data() + len; while (padlen--) * uc++ = fill; } else { @@ -4900,11 +4860,11 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const int padlen = width - len; if (padlen > 0) { result.resize(len+padlen); - QChar *uc = (QChar*)result.d->data; + QChar *uc = (QChar*)result.d->data(); while (padlen--) * uc++ = fill; if (len) - memcpy(uc, d->data, sizeof(QChar)*len); + memcpy(uc, d->data(), sizeof(QChar)*len); } else { if (truncate) result = left(width); @@ -4924,7 +4884,7 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const QString QString::toLower() const { - const ushort *p = d->data; + const ushort *p = d->data(); if (!p) return *this; if (!d->size) @@ -4939,7 +4899,7 @@ QString QString::toLower() const } #endif - const ushort *e = d->data + d->size; + const ushort *e = d->data() + d->size; // this avoids one out of bounds check in the loop if (QChar(*p).isLowSurrogate()) @@ -4952,17 +4912,17 @@ QString QString::toLower() const const QUnicodeTables::Properties *prop = qGetProp(c); if (prop->lowerCaseDiff || prop->lowerCaseSpecial) { QString s(d->size, Qt::Uninitialized); - memcpy(s.d->data, d->data, (p - d->data)*sizeof(ushort)); - ushort *pp = s.d->data + (p - d->data); + memcpy(s.d->data(), d->data(), (p - d->data())*sizeof(ushort)); + ushort *pp = s.d->data() + (p - d->data()); while (p < e) { uint c = *p; if (QChar(c).isLowSurrogate() && QChar(*(p - 1)).isHighSurrogate()) c = QChar::surrogateToUcs4(*(p - 1), c); prop = qGetProp(c); if (prop->lowerCaseSpecial) { - int pos = pp - s.d->data; + int pos = pp - s.d->data(); s.resize(s.d->size + SPECIAL_CASE_MAX_LEN); - pp = s.d->data + pos; + pp = s.d->data() + pos; const ushort *specialCase = specialCaseMap + prop->lowerCaseDiff; while (*specialCase) *pp++ = *specialCase++; @@ -4971,7 +4931,7 @@ QString QString::toLower() const } ++p; } - s.truncate(pp - s.d->data); + s.truncate(pp - s.d->data()); return s; } ++p; @@ -4988,11 +4948,11 @@ QString QString::toCaseFolded() const if (!d->size) return *this; - const ushort *p = d->data; + const ushort *p = d->data(); if (!p) return *this; - const ushort *e = d->data + d->size; + const ushort *e = d->data() + d->size; uint last = 0; while (p < e) { @@ -5000,9 +4960,9 @@ QString QString::toCaseFolded() const if (folded != *p) { QString s(*this); s.detach(); - ushort *pp = s.d->data + (p - d->data); - const ushort *ppe = s.d->data + s.d->size; - last = pp > s.d->data ? *(pp - 1) : 0; + ushort *pp = s.d->data() + (p - d->data()); + const ushort *ppe = s.d->data() + s.d->size; + last = pp > s.d->data() ? *(pp - 1) : 0; while (pp < ppe) { *pp = foldCase(*pp, last); ++pp; @@ -5024,7 +4984,7 @@ QString QString::toCaseFolded() const QString QString::toUpper() const { - const ushort *p = d->data; + const ushort *p = d->data(); if (!p) return *this; if (!d->size) @@ -5039,7 +4999,7 @@ QString QString::toUpper() const } #endif - const ushort *e = d->data + d->size; + const ushort *e = d->data() + d->size; // this avoids one out of bounds check in the loop if (QChar(*p).isLowSurrogate()) @@ -5052,17 +5012,17 @@ QString QString::toUpper() const const QUnicodeTables::Properties *prop = qGetProp(c); if (prop->upperCaseDiff || prop->upperCaseSpecial) { QString s(d->size, Qt::Uninitialized); - memcpy(s.d->data, d->data, (p - d->data)*sizeof(ushort)); - ushort *pp = s.d->data + (p - d->data); + memcpy(s.d->data(), d->data(), (p - d->data())*sizeof(ushort)); + ushort *pp = s.d->data() + (p - d->data()); while (p < e) { uint c = *p; if (QChar(c).isLowSurrogate() && QChar(*(p - 1)).isHighSurrogate()) c = QChar::surrogateToUcs4(*(p - 1), c); prop = qGetProp(c); if (prop->upperCaseSpecial) { - int pos = pp - s.d->data; + int pos = pp - s.d->data(); s.resize(s.d->size + SPECIAL_CASE_MAX_LEN); - pp = s.d->data + pos; + pp = s.d->data() + pos; const ushort *specialCase = specialCaseMap + prop->upperCaseDiff; while (*specialCase) *pp++ = *specialCase++; @@ -5071,7 +5031,7 @@ QString QString::toUpper() const } ++p; } - s.truncate(pp - s.d->data); + s.truncate(pp - s.d->data()); return s; } ++p; @@ -6196,19 +6156,19 @@ QString QString::repeated(int times) const if (result.d->alloc != resultSize) return QString(); // not enough memory - memcpy(result.d->data, d->data, d->size * sizeof(ushort)); + memcpy(result.d->data(), d->data(), d->size * sizeof(ushort)); int sizeSoFar = d->size; - ushort *end = result.d->data + sizeSoFar; + ushort *end = result.d->data() + sizeSoFar; const int halfResultSize = resultSize >> 1; while (sizeSoFar <= halfResultSize) { - memcpy(end, result.d->data, sizeSoFar * sizeof(ushort)); + memcpy(end, result.d->data(), sizeSoFar * sizeof(ushort)); end += sizeSoFar; sizeSoFar <<= 1; } - memcpy(end, result.d->data, (resultSize - sizeSoFar) * sizeof(ushort)); - result.d->data[resultSize] = '\0'; + memcpy(end, result.d->data(), (resultSize - sizeSoFar) * sizeof(ushort)); + result.d->data()[resultSize] = '\0'; result.d->size = resultSize; return result; } @@ -6902,7 +6862,7 @@ QString QString::multiArg(int numArgs, const QString **args) const { QString result; QMap numbersUsed; - const QChar *uc = (const QChar *) d->data; + const QChar *uc = (const QChar *) d->data(); const int len = d->size; const int end = len - 1; int lastNumber = -1; @@ -6951,62 +6911,50 @@ QString QString::multiArg(int numArgs, const QString **args) const return result; } -static bool isStringRightToLeft(const ushort *p, const ushort *end) -{ - bool righttoleft = false; - while (p < end) { - switch(QChar::direction(*p)) - { - case QChar::DirL: - goto end; - case QChar::DirR: - case QChar::DirAL: - righttoleft = true; - goto end; - default: - break; - } - ++p; - } - end: - return righttoleft; -} -/*! \internal - */ -void QString::updateProperties() const +/*! \fn bool QString::isSimpleText() const + + \internal +*/ +bool QString::isSimpleText() const { - ushort *p = d->data; - ushort *end = p + d->size; - d->simpletext = true; + const ushort *p = d->data(); + const ushort * const end = p + d->size; while (p < end) { ushort uc = *p; // sort out regions of complex text formatting if (uc > 0x058f && (uc < 0x1100 || uc > 0xfb0f)) { - d->simpletext = false; + return false; } p++; } - d->righttoleft = isStringRightToLeft(d->data, d->data + d->size); - d->clean = true; -} - -bool QString::isRightToLeft() const -{ - return isStringRightToLeft(d->data, d->data + d->size); + return true; } -/*! \fn bool QString::isSimpleText() const - - \internal -*/ - /*! \fn bool QString::isRightToLeft() const Returns true if the string is read right to left. */ - +bool QString::isRightToLeft() const +{ + const ushort *p = d->data(); + const ushort * const end = p + d->size; + while (p < end) { + switch(QChar::direction(*p)) + { + case QChar::DirL: + return false; + case QChar::DirR: + case QChar::DirAL: + return true; + default: + break; + } + ++p; + } + return false; +} /*! \fn QChar *QString::data() @@ -7122,17 +7070,13 @@ bool QString::isRightToLeft() const QString QString::fromRawData(const QChar *unicode, int size) { Data *x = static_cast(qMalloc(sizeof(Data))); + *x = (Data){ Q_REFCOUNT_INITIALIZER(1), size, 0, false, { 0 } }; Q_CHECK_PTR(x); if (unicode) { - x->data = (ushort *)unicode; + x->offset = (const ushort *)unicode - (x->d + sizeof(qptrdiff)/sizeof(ushort)); } else { - x->data = x->array; size = 0; } - x->ref = 1; - x->alloc = x->size = size; - *x->array = '\0'; - x->clean = x->simpletext = x->righttoleft = x->capacity = 0; return QString(x, 0); } @@ -7152,18 +7096,16 @@ QString QString::fromRawData(const QChar *unicode, int size) */ QString &QString::setRawData(const QChar *unicode, int size) { - if (d->ref != 1 || (d->data == d->array && d->alloc)) { + if (d->ref != 1 || d->alloc) { *this = fromRawData(unicode, size); } else { if (unicode) { - d->data = (ushort *)unicode; + d->size = size; + d->offset = (const ushort *)unicode - (d->d + sizeof(qptrdiff)/sizeof(ushort)); } else { - d->data = d->array; - size = 0; + d->offset = 0; + d->size = 0; } - d->alloc = d->size = size; - *d->array = '\0'; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; } return *this; } @@ -7212,7 +7154,7 @@ QString &QString::setRawData(const QChar *unicode, int size) \snippet doc/src/snippets/code/src_corelib_tools_qstring.cpp 6 - \sa QString, QLatin1Char + \sa QString, QLatin1Char, QStringLiteral */ /*! \fn QLatin1String::QLatin1String(const char *str) @@ -8345,7 +8287,7 @@ QStringRef QString::rightRef(int n) const QStringRef QString::midRef(int position, int n) const { - if (d == &shared_null || position >= d->size) + if (d == &shared_null.str || position >= d->size) return QStringRef(); if (n < 0) n = d->size - position; @@ -9071,4 +9013,21 @@ QVector QStringRef::toUcs4() const return v; } +/*! + \macro QStringLiteral(str) + \relates QString + + The macro generates the data for a QString out of \a str at compile time if the compiler supports it. + Creating a QString from it is free in this case, and the generated string data is stored in + the read-only segment of the compiled object file. + + Using QStringLiteral instead of a double quoted ascii literal can significantly speed up creation + of QString's from data known at compile time. + + If the compiler is c++0x enabled the string \a str can actually contain unicode data. + + For compilers not supporting the creation of compile time strings, QStringLiteral will fall back to + QLatin1String. +*/ + QT_END_NAMESPACE diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 154012d132..81dff3d309 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -44,7 +44,7 @@ #include #include -#include +#include #include #ifndef QT_NO_STL @@ -77,9 +77,65 @@ class QLatin1String; class QStringRef; template class QVector; +struct QStringData { + QtPrivate::RefCount ref; + int size; + uint alloc : 31; + uint capacityReserved : 1; + union { + qptrdiff offset; // will always work as we add/subtract from a ushort ptr + ushort d[sizeof(qptrdiff)/sizeof(ushort)]; + }; + inline ushort *data() { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; } + inline const ushort *data() const { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; } +}; + + +#if defined(Q_COMPILER_UNICODE_STRINGS) + +template struct QConstStringData +{ + const QStringData str; + const char16_t data[n]; + operator const QStringData &() const { return str; } +}; +#define QStringLiteral(str) (const QConstStringData) \ +{ { Q_REFCOUNT_INITIALIZER(-1), sizeof(u"" str)/2 -1, 0, 0, { 0 } }, u"" str } + +// wchar_t is 2 bytes +#elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) + +template struct QConstStringData +{ + const QStringData str; + const wchar_t data[n]; + operator const QStringData &() const { return str; } +}; +#define QStringLiteral(str) (const QConstStringData) \ +{ { Q_REFCOUNT_INITIALIZER(-1), sizeof(L"" str)/2 -1, 0, 0, { 0 } }, L"" str } + +// fallback, uses QLatin1String as next best options +#else + +template struct QConstStringData +{ + const QStringData str; + const ushort data[n]; + operator const QStringData &() const { return str; } +}; +#define QStringLiteral(str) QLatin1String(str) + +#endif + +#ifndef QT_NO_KEYWORDS +#define qs(str) QStringLiteral(str) +#endif + class Q_CORE_EXPORT QString { public: + typedef QStringData Data; + inline QString(); QString(const QChar *unicode, int size); // Qt5: don't cap size < 0 explicit QString(const QChar *unicode); // Qt5: merge with the above @@ -108,7 +164,7 @@ public: int capacity() const; inline void reserve(int size); - inline void squeeze() { if (d->size < d->alloc || d->ref != 1) realloc(); d->capacity = 0;} + inline void squeeze() { if (d->size < d->alloc || d->ref != 1) realloc(); d->capacityReserved = false;} inline const QChar *unicode() const; inline QChar *data(); @@ -262,8 +318,8 @@ public: inline QString &operator+=(QChar c) { if (d->ref != 1 || d->size + 1 > d->alloc) realloc(grow(d->size + 1)); - d->data[d->size++] = c.unicode(); - d->data[d->size] = '\0'; + d->data()[d->size++] = c.unicode(); + d->data()[d->size] = '\0'; return *this; } @@ -491,15 +547,17 @@ public: // compatibility struct Null { }; static const Null null; - inline QString(const Null &): d(&shared_null) { d->ref.ref(); } + inline QString(const Null &): d(const_cast(&shared_null.str)) {} inline QString &operator=(const Null &) { *this = QString(); return *this; } - inline bool isNull() const { return d == &shared_null; } + inline bool isNull() const { return d == &shared_null.str; } - bool isSimpleText() const { if (!d->clean) updateProperties(); return d->simpletext; } + bool isSimpleText() const; bool isRightToLeft() const; QString(int size, Qt::Initialization); + template + inline QString(const QConstStringData &dd) : d(const_cast(&dd.str)) {} private: #if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED) @@ -511,22 +569,11 @@ private: QString &operator=(const QByteArray &a); #endif - struct Data { - QBasicAtomicInt ref; - int alloc, size; - ushort *data; // QT5: put that after the bit field to fill alignment gap; don't use sizeof any more then - ushort clean : 1; - ushort simpletext : 1; - ushort righttoleft : 1; - ushort capacity : 1; - ushort reserved : 11; - // ### Qt5: try to ensure that "array" is aligned to 16 bytes on both 32- and 64-bit - ushort array[1]; - }; - static Data shared_null; - static Data shared_empty; + static const QConstStringData<1> shared_null; + static const QConstStringData<1> shared_empty; Data *d; - QString(Data *dd, int /*dummy*/) : d(dd) {} + inline QString(Data *dd, int /*dummy*/) : d(dd) {} + #ifndef QT_NO_TEXTCODEC static QTextCodec *codecForCStrings; #endif @@ -605,23 +652,23 @@ inline QString::QString(const QLatin1String &aLatin1) : d(fromLatin1_helper(aLat inline int QString::length() const { return d->size; } inline const QChar QString::at(int i) const -{ Q_ASSERT(uint(i) < uint(size())); return d->data[i]; } +{ Q_ASSERT(uint(i) < uint(size())); return d->data()[i]; } inline const QChar QString::operator[](int i) const -{ Q_ASSERT(uint(i) < uint(size())); return d->data[i]; } +{ Q_ASSERT(uint(i) < uint(size())); return d->data()[i]; } inline const QChar QString::operator[](uint i) const -{ Q_ASSERT(i < uint(size())); return d->data[i]; } +{ Q_ASSERT(i < uint(size())); return d->data()[i]; } inline bool QString::isEmpty() const { return d->size == 0; } inline const QChar *QString::unicode() const -{ return reinterpret_cast(d->data); } +{ return reinterpret_cast(d->data()); } inline const QChar *QString::data() const -{ return reinterpret_cast(d->data); } +{ return reinterpret_cast(d->data()); } inline QChar *QString::data() -{ detach(); return reinterpret_cast(d->data); } +{ detach(); return reinterpret_cast(d->data()); } inline const QChar *QString::constData() const -{ return reinterpret_cast(d->data); } +{ return reinterpret_cast(d->data()); } inline void QString::detach() -{ if (d->ref != 1 || d->data != d->array) realloc(); } +{ if (d->ref != 1 || d->offset) realloc(); } inline bool QString::isDetached() const { return d->ref == 1; } inline QString &QString::operator=(const QLatin1String &s) @@ -703,10 +750,10 @@ public: // all this is not documented: We just say "like QChar" and let it be. inline operator QChar() const - { return i < s.d->size ? s.d->data[i] : 0; } + { return i < s.d->size ? s.d->data()[i] : 0; } inline QCharRef &operator=(const QChar &c) { if (i >= s.d->size) s.expand(i); else s.detach(); - s.d->data[i] = c.unicode(); return *this; } + s.d->data()[i] = c.unicode(); return *this; } // An operator= for each QChar cast constructors #ifndef QT_NO_CAST_FROM_ASCII @@ -773,9 +820,9 @@ inline void QCharRef::setRow(uchar arow) { QChar(*this).setRow(arow); } inline void QCharRef::setCell(uchar acell) { QChar(*this).setCell(acell); } -inline QString::QString() : d(&shared_null) { d->ref.ref(); } +inline QString::QString() : d(const_cast(&shared_null.str)) {} inline QString::~QString() { if (!d->ref.deref()) free(d); } -inline void QString::reserve(int asize) { if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacity = 1;} +inline void QString::reserve(int asize) { if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true;} inline QString &QString::setUtf16(const ushort *autf16, int asize) { return setUnicode(reinterpret_cast(autf16), asize); } inline QCharRef QString::operator[](int i) @@ -783,17 +830,17 @@ inline QCharRef QString::operator[](int i) inline QCharRef QString::operator[](uint i) { return QCharRef(*this, i); } inline QString::iterator QString::begin() -{ detach(); return reinterpret_cast(d->data); } +{ detach(); return reinterpret_cast(d->data()); } inline QString::const_iterator QString::begin() const -{ return reinterpret_cast(d->data); } +{ return reinterpret_cast(d->data()); } inline QString::const_iterator QString::constBegin() const -{ return reinterpret_cast(d->data); } +{ return reinterpret_cast(d->data()); } inline QString::iterator QString::end() -{ detach(); return reinterpret_cast(d->data + d->size); } +{ detach(); return reinterpret_cast(d->data() + d->size); } inline QString::const_iterator QString::end() const -{ return reinterpret_cast(d->data + d->size); } +{ return reinterpret_cast(d->data() + d->size); } inline QString::const_iterator QString::constEnd() const -{ return reinterpret_cast(d->data + d->size); } +{ return reinterpret_cast(d->data() + d->size); } inline QBool QString::contains(const QString &s, Qt::CaseSensitivity cs) const { return QBool(indexOf(s, 0, cs) != -1); } inline QBool QString::contains(const QStringRef &s, Qt::CaseSensitivity cs) const @@ -1024,7 +1071,7 @@ public: inline const QChar *unicode() const { if (!m_string) - return reinterpret_cast(QString::shared_null.data); + return reinterpret_cast(QString::shared_null.str.data()); return m_string->unicode() + m_position; } inline const QChar *data() const { return unicode(); } @@ -1154,7 +1201,6 @@ inline QBool QStringRef::contains(const QStringRef &s, Qt::CaseSensitivity cs) c { return QBool(indexOf(s, 0, cs) != -1); } - QT_END_NAMESPACE QT_END_HEADER -- cgit v1.2.3 From f4c07fe72168778cd6ea5a6c07fb6add91b2e3d0 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 4 Jul 2011 12:21:06 +0200 Subject: Unify QLatin1String and QLatin1Literal Unify the two classes and get rid of one TODO item for Qt 5. Using strlen in the constructor of QLatin1String works, as the compiler can do the calculation at compile time. Change-Id: I59d98c71a34b86d4211fa0d8cfd40b7d612c5a78 Reviewed-on: http://codereview.qt.nokia.com/1219 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qstring.cpp | 80 +++++++++++++++++++----------------- src/corelib/tools/qstring.h | 13 +++--- src/corelib/tools/qstringbuilder.cpp | 49 ++-------------------- src/corelib/tools/qstringbuilder.h | 38 +---------------- 4 files changed, 57 insertions(+), 123 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index eb5804b254..fe6cae25d1 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -720,6 +720,18 @@ const QString::Null QString::null = { }; \section1 More Efficient String Construction + Many strings are known at compile time. But the trivial + constructor QString("Hello"), will convert the string literal + to a QString using the codecForCStrings(). To avoid this one + can use the QStringLiteral macro to directly create the required + data at compile time. Constructing a QString out of the literal + does then not cause any overhead at runtime. + + A slightly less efficient way is to use QLatin1String. This class wraps + a C string literal, precalculates it length at compile time and can + then be used for faster comparison with QStrings and conversion to + QStrings than a regular C string literal. + Using the QString \c{'+'} operator, it is easy to construct a complex string from multiple substrings. You will often write code like this: @@ -735,9 +747,6 @@ const QString::Null QString::null = { }; where \e{n > 2}, there can be as many as \e{n - 1} calls to the memory allocator. - Second, QLatin1String does not store its length internally but - calls qstrlen() when it needs to know its length. - In 4.6, an internal template class \c{QStringBuilder} has been added along with a few helper functions. This class is marked internal and does not appear in the documentation, because you @@ -755,12 +764,6 @@ const QString::Null QString::null = { }; then called \e{once} to get the required space, and the substrings are copied into it one by one. - \c{QLatin1Literal} is a second internal class that can replace - QLatin1String, which can't be changed for compatibility reasons. - \c{QLatin1Literal} stores its length, thereby saving time when - \c{QStringBuilder} computes the amount of memory required for the - final string. - Additional efficiency is gained by inlining and reduced reference counting (the QString created from a \c{QStringBuilder} typically has a ref count of 1, whereas QString::append() needs an extra @@ -2076,7 +2079,7 @@ QString &QString::replace(const QLatin1String &before, const QString &after, Qt::CaseSensitivity cs) { - int blen = qstrlen(before.latin1()); + int blen = before.size(); QVarLengthArray b(blen); for (int i = 0; i < blen; ++i) b[i] = (uchar)before.latin1()[i]; @@ -2099,7 +2102,7 @@ QString &QString::replace(const QString &before, const QLatin1String &after, Qt::CaseSensitivity cs) { - int alen = qstrlen(after.latin1()); + int alen = after.size(); QVarLengthArray a(alen); for (int i = 0; i < alen; ++i) a[i] = (uchar)after.latin1()[i]; @@ -2120,7 +2123,7 @@ QString &QString::replace(const QString &before, */ QString &QString::replace(QChar c, const QLatin1String &after, Qt::CaseSensitivity cs) { - int alen = qstrlen(after.latin1()); + int alen = after.size(); QVarLengthArray a(alen); for (int i = 0; i < alen; ++i) a[i] = (uchar)after.latin1()[i]; @@ -2150,20 +2153,23 @@ bool QString::operator==(const QString &other) const */ bool QString::operator==(const QLatin1String &other) const { + if (d->size != other.size()) + return false; + + if (!other.size()) + return isEmpty(); + const ushort *uc = d->data(); const ushort *e = uc + d->size; const uchar *c = (uchar *)other.latin1(); - if (!c) - return isEmpty(); - - while (*c) { - if (uc == e || *uc != *c) + while (uc < e) { + if (*uc != *c) return false; ++uc; ++c; } - return (uc == e); + return true; } /*! \fn bool QString::operator==(const QByteArray &other) const @@ -2212,20 +2218,20 @@ bool QString::operator<(const QString &other) const */ bool QString::operator<(const QLatin1String &other) const { - const ushort *uc = d->data(); - const ushort *e = uc + d->size; const uchar *c = (uchar *) other.latin1(); - if (!c || *c == 0) return false; - while (*c) { - if (uc == e || *uc != *c) + const ushort *uc = d->data(); + const ushort *e = uc + qMin(d->size, other.size()); + + while (uc < e) { + if (*uc != *c) break; ++uc; ++c; } - return (uc == e ? *c : *uc < *c); + return (uc == (d->data() + d->size) ? *c : *uc < *c); } /*! \fn bool QString::operator<(const QByteArray &other) const @@ -2314,20 +2320,20 @@ bool QString::operator<(const QLatin1String &other) const */ bool QString::operator>(const QLatin1String &other) const { - const ushort *uc = d->data();; - const ushort *e = uc + d->size; const uchar *c = (uchar *) other.latin1(); - if (!c || *c == '\0') return !isEmpty(); - while (*c) { - if (uc == e || *uc != *c) + const ushort *uc = d->data();; + const ushort *e = uc + qMin(d->size, other.size()); + + while (uc < e) { + if (*uc != *c) break; ++uc; ++c; } - return (uc == e ? false : *uc > *c); + return (uc == (d->data() + d->size) ? false : *uc > *c); } /*! \fn bool QString::operator>(const QByteArray &other) const @@ -2696,7 +2702,7 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c */ int QString::lastIndexOf(const QLatin1String &str, int from, Qt::CaseSensitivity cs) const { - const int sl = qstrlen(str.latin1()); + const int sl = str.size(); if (sl == 1) return lastIndexOf(QLatin1Char(str.latin1()[0]), from, cs); @@ -3832,7 +3838,7 @@ QString QString::fromLocal8Bit(const char *str, int size) if (!str) return QString(); if (size == 0 || (!*str && size < 0)) - return QLatin1String(""); + return QString(shared_empty); #if !defined(QT_NO_TEXTCODEC) if (size < 0) size = qstrlen(str); @@ -7468,7 +7474,7 @@ QDataStream &operator>>(QDataStream &in, QString &str) } } } else { - str = QLatin1String(""); + str = QString(QLatin1String("")); } } return in; @@ -8440,7 +8446,7 @@ int QStringRef::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const */ int QStringRef::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const { - const int sl = qstrlen(str.latin1()); + const int sl = str.size(); if (sl == 1) return lastIndexOf(QLatin1Char(str.latin1()[0]), from, cs); @@ -8793,7 +8799,7 @@ static inline int qt_find_latin1_string(const QChar *haystack, int size, int from, Qt::CaseSensitivity cs) { const char *latin1 = needle.latin1(); - int len = qstrlen(latin1); + int len = needle.size(); QVarLengthArray s(len); for (int i = 0; i < len; ++i) s[i] = latin1[i]; @@ -8834,7 +8840,7 @@ static inline bool qt_starts_with(const QChar *haystack, int haystackLen, return !needle.latin1(); if (haystackLen == 0) return !needle.latin1() || *needle.latin1() == 0; - const int slen = qstrlen(needle.latin1()); + const int slen = needle.size(); if (slen > haystackLen) return false; const ushort *data = reinterpret_cast(haystack); @@ -8885,7 +8891,7 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen, return !needle.latin1(); if (haystackLen == 0) return !needle.latin1() || *needle.latin1() == 0; - const int slen = qstrlen(needle.latin1()); + const int slen = needle.size(); int pos = haystackLen - slen; if (pos < 0) return false; diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 81dff3d309..e0473e411a 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -610,11 +610,11 @@ public: class Q_CORE_EXPORT QLatin1String { public: - inline explicit QLatin1String(const char *s) : chars(s) {} - inline QLatin1String &operator=(const QLatin1String &other) - { chars = other.chars; return *this; } + inline explicit QLatin1String(const char *s) : m_size(s ? strlen(s) : 0), m_data(s) {} - inline const char *latin1() const { return chars; } + inline const char *latin1() const { return m_data; } + inline int size() const { return m_size; } + inline const char *data() const { return m_data; } inline bool operator==(const QString &s) const { return s == *this; } @@ -642,9 +642,12 @@ public: inline QT_ASCII_CAST_WARN bool operator>=(const char *s) const { return QString::fromAscii(s) <= *this; } private: - const char *chars; + int m_size; + const char *m_data; }; +// Qt 4.x compatibility +typedef QLatin1String QLatin1Literal; inline QString::QString(const QLatin1String &aLatin1) : d(fromLatin1_helper(aLatin1.latin1())) diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 1cc7e5d2c3..4c6848498b 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -44,47 +44,6 @@ QT_BEGIN_NAMESPACE -/*! - \class QLatin1Literal - \internal - \reentrant - \since 4.6 - - \brief The QLatin1Literal class provides a thin wrapper around string - literals used in source code. - - \ingroup tools - \ingroup shared - \ingroup string-processing - - - Unlike \c QLatin1String, a \c QLatin1Literal can retrieve its size - without iterating over the literal. - - The main use of \c QLatin1Literal is in conjunction with \c QStringBuilder - to reduce the number of reallocations needed to build up a string from - smaller chunks. - - \sa QStringBuilder, QLatin1String, QString, QStringRef -*/ - -/*! \fn int QLatin1Literal::size() const - - Returns the number of characters in the literal \e{excluding} the trailing - NULL char. -*/ - -/*! \fn QLatin1Literal::QLatin1Literal(const char str) - - Constructs a new literal from the string \a str. -*/ - -/*! \fn const char *QLatin1Literal::data() const - - Returns a pointer to the first character of the string literal. - The string literal is terminated by a NUL character. -*/ - /*! \class QStringBuilder \internal @@ -110,7 +69,7 @@ QT_BEGIN_NAMESPACE The QStringBuilder class is not to be used explicitly in user code. Instances of the class are created as return values of the operator%() function, acting on objects of type QString, - QLatin1String, QLatin1Literal, QStringRef, QChar, QCharRef, + QLatin1String, QStringRef, QChar, QCharRef, QLatin1Char, and \c char. Concatenating strings with operator%() generally yields better @@ -118,7 +77,7 @@ QT_BEGIN_NAMESPACE if there are three or more of them, and performs equally well in other cases. - \sa QLatin1Literal, QString + \sa QLatin1String, QString */ /*! \fn QStringBuilder::QStringBuilder(const A &a, const B &b) @@ -132,7 +91,7 @@ QT_BEGIN_NAMESPACE takes a QString parameter. This function is usable with arguments of type \c QString, - \c QLatin1String, \c QLatin1Literal, \c QStringRef, + \c QLatin1String, \c QStringRef, \c QChar, \c QCharRef, \c QLatin1Char, and \c char. */ @@ -145,7 +104,7 @@ QT_BEGIN_NAMESPACE /*! \fn operator QStringBuilder::QString() const - Converts the \c QLatin1Literal into a \c QString object. + Converts the \c QLatin1String into a \c QString object. */ /*! \internal diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 594ab2f183..c86a51f8e3 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -59,22 +59,6 @@ QT_BEGIN_NAMESPACE QT_MODULE(Core) -// ### Qt 5: merge with QLatin1String -class QLatin1Literal -{ -public: - int size() const { return m_size; } - const char *data() const { return m_data; } - - template - QLatin1Literal(const char (&str)[N]) - : m_size(N - 1), m_data(str) {} - -private: - const int m_size; - const char * const m_data; -}; - struct Q_CORE_EXPORT QAbstractConcatenable { protected: @@ -234,31 +218,13 @@ template <> struct QConcatenable typedef QLatin1String type; typedef QString ConvertTo; enum { ExactSize = true }; - static int size(const QLatin1String &a) { return qstrlen(a.latin1()); } + static int size(const QLatin1String &a) { return a.size(); } static inline void appendTo(const QLatin1String &a, QChar *&out) - { - for (const char *s = a.latin1(); *s; ) - *out++ = QLatin1Char(*s++); - } - static inline void appendTo(const QLatin1String &a, char *&out) - { - for (const char *s = a.latin1(); *s; ) - *out++ = *s++; - } -}; - -template <> struct QConcatenable -{ - typedef QLatin1Literal type; - typedef QString ConvertTo; - enum { ExactSize = true }; - static int size(const QLatin1Literal &a) { return a.size(); } - static inline void appendTo(const QLatin1Literal &a, QChar *&out) { for (const char *s = a.data(); *s; ) *out++ = QLatin1Char(*s++); } - static inline void appendTo(const QLatin1Literal &a, char *&out) + static inline void appendTo(const QLatin1String &a, char *&out) { for (const char *s = a.data(); *s; ) *out++ = *s++; -- cgit v1.2.3 From f3d6589068450283e9f147851113d1795b47acc6 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 7 Jul 2011 16:10:31 +0200 Subject: Bugfix the QConstString implementation. Change-Id: Ic9ea9d91c1a976962a3881ecdf7ad178de768b08 Reviewed-on: http://codereview.qt.nokia.com/1349 Reviewed-by: Qt Sanity Bot Reviewed-by: Lars Knoll --- src/corelib/tools/qstring.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index fe6cae25d1..d2928003a4 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -800,8 +800,8 @@ const QString::Null QString::null = { }; \sa split() */ -const QConstStringData<1> QString::shared_null = (const QConstStringData<1>) { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; -const QConstStringData<1> QString::shared_empty = (const QConstStringData<1>) { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; +const QConstStringData<1> QString::shared_null = { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; +const QConstStringData<1> QString::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; int QString::grow(int size) { -- cgit v1.2.3 From 571785b31d21715857228b00f96cd24601b28c8c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 7 Jul 2011 19:51:09 +0200 Subject: Make the new QStringLiteral produce a non-temporary This is currently GCC-only code (the __extension ({ }) stuff), but it was the only way I found to create a static variable and return it. I had to add the QConstStringDataPtr container because I had to return a pointer to the data -- it's impossible to return a reference through this extension. I could have returned a naked pointer directly too. This isn't complete. GCC 4.6 is placing the string in the .data section, not .rodata as we wanted. Investigating further. Change-Id: I170030dca3eddbd69f6c879e952f652f7fe5d958 Reviewed-on: http://codereview.qt.nokia.com/1350 Reviewed-by: Lars Knoll --- src/corelib/tools/qstring.h | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index e0473e411a..c10af450b3 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -90,32 +90,54 @@ struct QStringData { inline const ushort *data() const { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; } }; +template struct QConstStringData; +template struct QConstStringDataPtr +{ + const QConstStringData *ptr; +}; -#if defined(Q_COMPILER_UNICODE_STRINGS) +#if defined(Q_CC_GNU) +// We need to create a QStringData in the .rodata section of memory +// and the only way to do that is to create a "static const" variable. +// To do that, we need the __extension__ {( )} trick which only GCC supports +# if defined(Q_COMPILER_UNICODE_STRINGS) template struct QConstStringData { const QStringData str; const char16_t data[n]; operator const QStringData &() const { return str; } }; -#define QStringLiteral(str) (const QConstStringData) \ -{ { Q_REFCOUNT_INITIALIZER(-1), sizeof(u"" str)/2 -1, 0, 0, { 0 } }, u"" str } -// wchar_t is 2 bytes -#elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) +# define QStringLiteral(str) \ + __extension__ ({ \ + enum { Size = sizeof(u"" str)/2 }; \ + static const QConstStringData qstring_literal = \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, u"" str }; \ + QConstStringDataPtr holder = { &qstring_literal }; \ + holder; }) +# elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) +// wchar_t is 2 bytes template struct QConstStringData { const QStringData str; const wchar_t data[n]; operator const QStringData &() const { return str; } }; -#define QStringLiteral(str) (const QConstStringData) \ -{ { Q_REFCOUNT_INITIALIZER(-1), sizeof(L"" str)/2 -1, 0, 0, { 0 } }, L"" str } +# define QStringLiteral(str) \ + __extension__ ({ \ + enum { Size = sizeof(L"" str)/2 }; \ + static const QConstStringData qstring_literal = \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, L"" str }; \ + QConstStringDataPtr holder = { &qstring_literal }; \ + holder; }) +# endif +#endif +#ifndef QStringLiteral +// not GCC, or GCC in C++98 mode with 4-byte wchar_t // fallback, uses QLatin1String as next best options -#else template struct QConstStringData { @@ -123,8 +145,7 @@ template struct QConstStringData const ushort data[n]; operator const QStringData &() const { return str; } }; -#define QStringLiteral(str) QLatin1String(str) - +# define QStringLiteral(str) QLatin1String(str) #endif #ifndef QT_NO_KEYWORDS @@ -558,6 +579,8 @@ public: QString(int size, Qt::Initialization); template inline QString(const QConstStringData &dd) : d(const_cast(&dd.str)) {} + template + inline QString(QConstStringDataPtr dd) : d(const_cast(&dd.ptr->str)) {} private: #if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED) -- cgit v1.2.3 From a21f99292567418c620ccf2ffbb13946cac03b8d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 7 Jul 2011 19:53:35 +0200 Subject: Add support for QStringLiterals in QStringBuilder Otherwise we get errors for failing to have operator+ properly when writing: QStringLiteral("foo") + s Change-Id: I03844c95e9fdfa886eadfa2b5fe104ff048fd618 Reviewed-on: http://codereview.qt.nokia.com/1351 Reviewed-by: Qt Sanity Bot Reviewed-by: Lars Knoll --- src/corelib/tools/qstringbuilder.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index c86a51f8e3..6d998b62aa 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -249,6 +249,23 @@ template <> struct QConcatenable : private QAbstractConcatenable #endif }; +template struct QConcatenable > : private QAbstractConcatenable +{ + typedef QConstStringDataPtr type; + typedef QString ConvertTo; + enum { ExactSize = true }; + static int size(const type &) { return N; } + static inline void appendTo(const type &a, QChar *&out) + { + memcpy(out, reinterpret_cast(a.ptr->data), sizeof(QChar) * N); + out += N; + } +#ifndef QT_NO_CAST_TO_ASCII + static inline QT_ASCII_CAST_WARN void appendTo(const type &a, char *&out) + { convertToAscii(a.ptr->data, N, out); } +#endif +}; + template <> struct QConcatenable : private QAbstractConcatenable { typedef QStringRef type; -- cgit v1.2.3 From d96b7b809e614dd416709acec768529457120b9f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 8 Jul 2011 10:42:49 +0200 Subject: Use memmove in QListData::append(int) as regions overlap. It's undefined behaviour to memcpy regions with overlapping area. You have to use memmove. Change-Id: I912c819bf7ab26ba1e60028ee9d7c833dfc5138a Reviewed-on: http://codereview.qt.nokia.com/1355 Reviewed-by: Olivier Goffart --- src/corelib/tools/qlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 80c610be36..14dfc6a139 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -164,7 +164,7 @@ void **QListData::append(int n) if (b - n >= 2 * d->alloc / 3) { // we have enough space. Just not at the end -> move it. e -= b; - ::memcpy(d->array, d->array + b, e * sizeof(void *)); + ::memmove(d->array, d->array + b, e * sizeof(void *)); d->begin = 0; } else { realloc(grow(d->alloc + n)); -- cgit v1.2.3 From 2e58f52ded89e1d925f7129bc6c70a1a8b72f765 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 8 Jul 2011 11:11:39 +0200 Subject: Remove the qs() macro. There is tootoo many risks of conflicts with existing code. QStringLiteral is not that hard to type. And if users want to use qs they can still define it in their own headers. Change-Id: I7da4772d902033fa163f5177c012b5d0e87332d7 Reviewed-on: http://codereview.qt.nokia.com/1357 Reviewed-by: Lars Knoll --- src/corelib/tools/qstring.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index c10af450b3..de973a82fb 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -148,10 +148,6 @@ template struct QConstStringData # define QStringLiteral(str) QLatin1String(str) #endif -#ifndef QT_NO_KEYWORDS -#define qs(str) QStringLiteral(str) -#endif - class Q_CORE_EXPORT QString { public: -- cgit v1.2.3 From cd80fcb5d6db9d99684b94a90d2c798b712442c4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 8 Jul 2011 14:10:02 +0200 Subject: Use lambdas for generating static data for QStringLiteral This means it will work on C++0x compilers that support lambdas (all of them once they've completed supporting the functionality). Olivier had the idea and the initial code. Change-Id: I11ef7da4058ed18f4ea99ada070891a68ed54f55 Reviewed-on: http://codereview.qt.nokia.com/1380 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qstring.h | 59 +++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 26 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index de973a82fb..2251b64430 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -96,28 +96,16 @@ template struct QConstStringDataPtr const QConstStringData *ptr; }; -#if defined(Q_CC_GNU) -// We need to create a QStringData in the .rodata section of memory -// and the only way to do that is to create a "static const" variable. -// To do that, we need the __extension__ {( )} trick which only GCC supports - -# if defined(Q_COMPILER_UNICODE_STRINGS) +#if defined(Q_COMPILER_UNICODE_STRINGS) template struct QConstStringData { const QStringData str; const char16_t data[n]; operator const QStringData &() const { return str; } }; +#define QT_QSTRING_UNICODE_MARKER u"" -# define QStringLiteral(str) \ - __extension__ ({ \ - enum { Size = sizeof(u"" str)/2 }; \ - static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, u"" str }; \ - QConstStringDataPtr holder = { &qstring_literal }; \ - holder; }) - -# elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) +#elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) // wchar_t is 2 bytes template struct QConstStringData { @@ -125,26 +113,45 @@ template struct QConstStringData const wchar_t data[n]; operator const QStringData &() const { return str; } }; -# define QStringLiteral(str) \ +#define QT_QSTRING_UNICODE_MARKER L"" + +#else +template struct QConstStringData +{ + const QStringData str; + const ushort data[n]; + operator const QStringData &() const { return str; } +}; +#endif + +#if defined(QT_QSTRING_UNICODE_MARKER) +# if defined(Q_COMPILER_LAMBDA) +# define QStringLiteral(str) ([]() { \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + static const QConstStringData qstring_literal = \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + QConstStringDataPtr holder = { &qstring_literal }; \ + return holder; }()) + +# elif defined(Q_CC_GNU) +// We need to create a QStringData in the .rodata section of memory +// and the only way to do that is to create a "static const" variable. +// To do that, we need the __extension__ {( )} trick which only GCC supports + +# define QStringLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(L"" str)/2 }; \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, L"" str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ QConstStringDataPtr holder = { &qstring_literal }; \ holder; }) # endif #endif #ifndef QStringLiteral -// not GCC, or GCC in C++98 mode with 4-byte wchar_t +// no lambdas, not GCC, or GCC in C++98 mode with 4-byte wchar_t // fallback, uses QLatin1String as next best options -template struct QConstStringData -{ - const QStringData str; - const ushort data[n]; - operator const QStringData &() const { return str; } -}; # define QStringLiteral(str) QLatin1String(str) #endif @@ -576,7 +583,7 @@ public: template inline QString(const QConstStringData &dd) : d(const_cast(&dd.str)) {} template - inline QString(QConstStringDataPtr dd) : d(const_cast(&dd.ptr->str)) {} + Q_DECL_CONSTEXPR inline QString(QConstStringDataPtr dd) : d(const_cast(&dd.ptr->str)) {} private: #if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED) -- cgit v1.2.3 From d9bec0a1d2d7ac18a9a8ae5eff8dd8204eb6bf70 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 8 Jul 2011 15:49:26 +0200 Subject: Remove Qt 4.3 binary compatibility for MSVC When we removed the useless "const" in the return type, we broke compatibility with a few compilers that include the return type in the mangling. We don't need that anymore in Qt 5. This change should have had a ### Qt5 mark everywhere, not just in a comment in qstring.cpp. Change-Id: I8839f8dc540b34e57a3efdb160a1c015f7328422 Merge-request: 13 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1385 Reviewed-by: Qt Sanity Bot --- src/corelib/tools/qbytearray.h | 20 -------------------- src/corelib/tools/qchar.cpp | 4 ---- src/corelib/tools/qchar.h | 15 --------------- src/corelib/tools/qstring.cpp | 4 ---- src/corelib/tools/qstring.h | 6 ------ 5 files changed, 49 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 9f54f1a831..26cf2af59c 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -172,15 +172,9 @@ public: inline bool isSharedWith(const QByteArray &other) const { return d == other.d; } void clear(); -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - const char at(int i) const; - const char operator[](int i) const; - const char operator[](uint i) const; -#else char at(int i) const; char operator[](int i) const; char operator[](uint i) const; -#endif QByteRef operator[](int i); QByteRef operator[](uint i); @@ -359,21 +353,12 @@ inline QByteArray::~QByteArray() { if (!d->ref.deref()) qFree(d); } inline int QByteArray::size() const { return d->size; } -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE -inline const char QByteArray::at(int i) const -{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } -inline const char QByteArray::operator[](int i) const -{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } -inline const char QByteArray::operator[](uint i) const -{ Q_ASSERT(i < uint(size())); return d->data[i]; } -#else inline char QByteArray::at(int i) const { Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } inline char QByteArray::operator[](int i) const { Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } inline char QByteArray::operator[](uint i) const { Q_ASSERT(i < uint(size())); return d->data[i]; } -#endif inline bool QByteArray::isEmpty() const { return d->size == 0; } @@ -412,13 +397,8 @@ class Q_CORE_EXPORT QByteRef { : a(array),i(idx) {} friend class QByteArray; public: -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - inline operator const char() const - { return i < a.d->size ? a.d->data[i] : char(0); } -#else inline operator char() const { return i < a.d->size ? a.d->data[i] : char(0); } -#endif inline QByteRef &operator=(char c) { if (i >= a.d->size) a.expand(i); else a.detach(); a.d->data[i] = c; return *this; } diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 9db7d1ae83..475bd55de4 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1295,11 +1295,7 @@ ushort QChar::toCaseFolded(ushort ucs2) \sa toLatin1(), unicode(), QTextCodec::codecForCStrings() */ -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE -const char QChar::toAscii() const -#else char QChar::toAscii() const -#endif { #ifndef QT_NO_CODEC_FOR_C_STRINGS if (QTextCodec::codecForCStrings()) diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index b7793403bd..cd30dace09 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -56,13 +56,8 @@ struct QLatin1Char { public: inline explicit QLatin1Char(char c) : ch(c) {} -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - inline const char toLatin1() const { return ch; } - inline const ushort unicode() const { return ushort(uchar(ch)); } -#else inline char toLatin1() const { return ch; } inline ushort unicode() const { return ushort(uchar(ch)); } -#endif private: char ch; @@ -230,15 +225,9 @@ public: UnicodeVersion unicodeVersion() const; -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - const char toAscii() const; - inline const char toLatin1() const; - inline const ushort unicode() const { return ucs; } -#else char toAscii() const; inline char toLatin1() const; inline ushort unicode() const { return ucs; } -#endif #ifdef Q_NO_PACKED_REFERENCE inline ushort &unicode() { return const_cast(ucs); } #else @@ -339,11 +328,7 @@ Q_DECLARE_TYPEINFO(QChar, Q_MOVABLE_TYPE); inline QChar::QChar() : ucs(0) {} -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE -inline const char QChar::toLatin1() const { return ucs > 0xff ? '\0' : char(ucs); } -#else inline char QChar::toLatin1() const { return ucs > 0xff ? '\0' : char(ucs); } -#endif inline QChar QChar::fromLatin1(char c) { return QChar(ushort(uchar(c))); } inline QChar::QChar(uchar c, uchar r) : ucs(ushort((r << 8) | c)){} diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index d2928003a4..dab281cdf8 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -3636,10 +3636,6 @@ QByteArray QString::toLatin1() const return toLatin1_helper(unicode(), length()); } -// ### Qt 5: Change the return type of at least toAscii(), -// toLatin1() and unicode() such that the use of Q_COMPILER_MANGLES_RETURN_TYPE -// isn't necessary in the header. See task 177402. - /*! Returns an 8-bit representation of the string as a QByteArray. diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 2251b64430..34f160e782 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -832,15 +832,9 @@ public: inline void setCell(uchar cell); inline void setRow(uchar row); -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - const char toAscii() const { return QChar(*this).toAscii(); } - const char toLatin1() const { return QChar(*this).toLatin1(); } - const ushort unicode() const { return QChar(*this).unicode(); } -#else char toAscii() const { return QChar(*this).toAscii(); } char toLatin1() const { return QChar(*this).toLatin1(); } ushort unicode() const { return QChar(*this).unicode(); } -#endif ushort& unicode() { return s.data()[i].unicode(); } }; -- cgit v1.2.3 From 0c0676ada2cc3943d09f8eb1e75491b80f08f27b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 8 Jul 2011 15:49:26 +0200 Subject: Remove #ifdef for platforms where QChar was packed -- there aren't any On ARM OABI, sizeof(QChar) was 4, so we used to pack it so QChar[] was isomorphic to ushort[]. We don't support the OABI anymore and the EABI does the right thing. Change-Id: I181dd2f169f6868450302e269ef9ad5d643f306f Merge-request: 13 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1386 Reviewed-by: Qt Sanity Bot --- src/corelib/tools/qchar.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index cd30dace09..d6db72d5ac 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -228,11 +228,7 @@ public: char toAscii() const; inline char toLatin1() const; inline ushort unicode() const { return ucs; } -#ifdef Q_NO_PACKED_REFERENCE - inline ushort &unicode() { return const_cast(ucs); } -#else inline ushort &unicode() { return ucs; } -#endif static QChar fromAscii(char c); static QChar fromLatin1(char c); -- cgit v1.2.3 From 82454b6014a7ee0b048b4db8d64a21de849d4ab9 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 12 Jul 2011 09:08:55 +0200 Subject: remove unneeded cast operator on QConstStringData Change-Id: Ib5f090cd6c716e1d936894be206b78629e70137b Reviewed-on: http://codereview.qt.nokia.com/1487 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qstring.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 34f160e782..27948e04ea 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -101,7 +101,6 @@ template struct QConstStringData { const QStringData str; const char16_t data[n]; - operator const QStringData &() const { return str; } }; #define QT_QSTRING_UNICODE_MARKER u"" @@ -111,7 +110,6 @@ template struct QConstStringData { const QStringData str; const wchar_t data[n]; - operator const QStringData &() const { return str; } }; #define QT_QSTRING_UNICODE_MARKER L"" @@ -120,7 +118,6 @@ template struct QConstStringData { const QStringData str; const ushort data[n]; - operator const QStringData &() const { return str; } }; #endif -- cgit v1.2.3