diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/tools/qstring.cpp | 439 | ||||
-rw-r--r-- | src/corelib/tools/qstring.h | 130 |
2 files changed, 287 insertions, 282 deletions
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<Data *>(&shared_null.str); } else if (size <= 0) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&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<Data *>(&shared_null.str); } else { int size = 0; while (unicode[size] != 0) ++size; if (!size) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&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<Data *>(&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<Data *>(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<Data *>(&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<Data *>(qMalloc(sizeof(Data) + alloc * sizeof(QChar))); + if (d->ref != 1 || d->offset) { + Data *x = static_cast<Data *>(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<Data *>(qRealloc(d, sizeof(Data) + alloc * sizeof(QChar))); + Data *p = static_cast<Data *>(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<ushort *>(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<QChar *>(after); - if (after >= reinterpret_cast<QChar *>(d->data) && after < reinterpret_cast<QChar *>(d->data) + d->size) { + if (after >= reinterpret_cast<QChar *>(d->data()) && after < reinterpret_cast<QChar *>(d->data()) + d->size) { afterBuffer = static_cast<QChar *>(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<const ushort*>(str.unicode()), + return lastIndexOfHelper(d->data(), from, reinterpret_cast<const ushort*>(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<Data *>(&shared_null.str); } else if (size == 0 || (!*str && size < 0)) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&shared_empty.str); } else { if (size < 0) size = qstrlen(str); - d = static_cast<Data *>(qMalloc(sizeof(Data) + size * sizeof(QChar))); + d = static_cast<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 *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<Data *>(&shared_null.str); } else if (size == 0 || (!*str && size < 0)) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&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<QChar *>(d->data); + const QChar * const start = reinterpret_cast<QChar *>(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<QChar *>(result.d->data); + QChar *to = reinterpret_cast<QChar *>(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<QChar *>(result.d->data)); + result.truncate(to - reinterpret_cast<QChar *>(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<QString*>(this); - that->realloc(); // ensure '\\0'-termination for ::fromRawData strings - return that->d->data; - } - return d->array; + if (d->offset) + const_cast<QString*>(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<int, int> 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<Data *>(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<uint> 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 <QtCore/qchar.h> #include <QtCore/qbytearray.h> -#include <QtCore/qatomic.h> +#include <QtCore/qrefcount.h> #include <QtCore/qnamespace.h> #ifndef QT_NO_STL @@ -77,9 +77,65 @@ class QLatin1String; class QStringRef; template <typename T> 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<int n> struct QConstStringData +{ + const QStringData str; + const char16_t data[n]; + operator const QStringData &() const { return str; } +}; +#define QStringLiteral(str) (const QConstStringData<sizeof(u"" str)/2>) \ +{ { 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<int n> struct QConstStringData +{ + const QStringData str; + const wchar_t data[n]; + operator const QStringData &() const { return str; } +}; +#define QStringLiteral(str) (const QConstStringData<sizeof(L"" str)/2>) \ +{ { Q_REFCOUNT_INITIALIZER(-1), sizeof(L"" str)/2 -1, 0, 0, { 0 } }, L"" str } + +// fallback, uses QLatin1String as next best options +#else + +template<int n> 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<Data *>(&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 <int n> + inline QString(const QConstStringData<n> &dd) : d(const_cast<QStringData *>(&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<const QChar*>(d->data); } +{ return reinterpret_cast<const QChar*>(d->data()); } inline const QChar *QString::data() const -{ return reinterpret_cast<const QChar*>(d->data); } +{ return reinterpret_cast<const QChar*>(d->data()); } inline QChar *QString::data() -{ detach(); return reinterpret_cast<QChar*>(d->data); } +{ detach(); return reinterpret_cast<QChar*>(d->data()); } inline const QChar *QString::constData() const -{ return reinterpret_cast<const QChar*>(d->data); } +{ return reinterpret_cast<const QChar*>(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<Data *>(&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<const QChar *>(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<QChar*>(d->data); } +{ detach(); return reinterpret_cast<QChar*>(d->data()); } inline QString::const_iterator QString::begin() const -{ return reinterpret_cast<const QChar*>(d->data); } +{ return reinterpret_cast<const QChar*>(d->data()); } inline QString::const_iterator QString::constBegin() const -{ return reinterpret_cast<const QChar*>(d->data); } +{ return reinterpret_cast<const QChar*>(d->data()); } inline QString::iterator QString::end() -{ detach(); return reinterpret_cast<QChar*>(d->data + d->size); } +{ detach(); return reinterpret_cast<QChar*>(d->data() + d->size); } inline QString::const_iterator QString::end() const -{ return reinterpret_cast<const QChar*>(d->data + d->size); } +{ return reinterpret_cast<const QChar*>(d->data() + d->size); } inline QString::const_iterator QString::constEnd() const -{ return reinterpret_cast<const QChar*>(d->data + d->size); } +{ return reinterpret_cast<const QChar*>(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<const QChar *>(QString::shared_null.data); + return reinterpret_cast<const QChar *>(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 |