diff options
Diffstat (limited to 'src/corelib/text')
27 files changed, 1388 insertions, 1341 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 4a00c664c0..ac5f2afb57 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -2,6 +2,7 @@ ** ** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -41,6 +42,7 @@ #include "qbytearray.h" #include "qbytearraymatcher.h" #include "private/qtools_p.h" +#include "qhashfunctions.h" #include "qstring.h" #include "qlist.h" #include "qlocale.h" @@ -63,7 +65,7 @@ #include <string.h> #include <stdlib.h> -#define IS_RAW_DATA(d) ((d)->offset != sizeof(QByteArrayData)) +#define IS_RAW_DATA(d) ((d)->flags() & QArrayData::RawDataType) QT_BEGIN_NAMESPACE @@ -332,7 +334,7 @@ int qstricmp(const char *str1, const char *str2) return int(Incomplete); }; -#if defined(__SSE4_1__) && !(defined(__SANITIZE_ADDRESS__) || QT_HAS_FEATURE(address_sanitizer)) +#if defined(__SSE4_1__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) enum { PageSize = 4096, PageMask = PageSize - 1 }; const __m128i zero = _mm_setzero_si128(); forever { @@ -731,27 +733,25 @@ QByteArray qUncompress(const uchar* data, int nbytes) return invalidCompressedData(); } - QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1)); + QPair<QByteArray::Data *, char *> pair = QByteArray::Data::allocate(expectedSize + 1); + QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(pair.first); if (Q_UNLIKELY(d.data() == nullptr)) return invalidCompressedData(); - d->size = expectedSize; forever { ulong alloc = len; - int res = ::uncompress((uchar*)d->data(), &len, + int res = ::uncompress((uchar*)pair.second, &len, data+4, nbytes-4); switch (res) { - case Z_OK: + case Z_OK: { Q_ASSERT(len <= alloc); Q_UNUSED(alloc); - d->size = len; - d->data()[len] = 0; - { - QByteArrayDataPtr dataPtr = { d.take() }; - return QByteArray(dataPtr); - } + QByteArray::DataPointer dataPtr = { d.take(), pair.second, uint(len) }; + pair.second[len] = '\0'; + return QByteArray(dataPtr); + } case Z_MEM_ERROR: qWarning("qUncompress: Z_MEM_ERROR: Not enough memory"); @@ -764,11 +764,12 @@ QByteArray qUncompress(const uchar* data, int nbytes) return invalidCompressedData(); } else { // grow the block - QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), len + 1); - if (Q_UNLIKELY(p == nullptr)) + pair = QByteArray::Data::reallocateUnaligned(d.data(), pair.second, len + 1); + Q_CHECK_PTR(pair.first); + if (Q_UNLIKELY(pair.first == nullptr)) return invalidCompressedData(); d.take(); // don't free - d.reset(p); + d.reset(pair.first); } continue; @@ -987,10 +988,20 @@ QByteArray qUncompress(const uchar* data, int nbytes) four. \value OmitTrailingEquals Omits adding the padding equal signs at the end of the encoded data. - - QByteArray::fromBase64() ignores the KeepTrailingEquals and - OmitTrailingEquals options and will not flag errors in case they are - missing or if there are too many of them. + \value IgnoreBase64DecodingErrors When decoding Base64-encoded data, ignores errors + in the input; invalid characters are simply skipped. + This enum value has been added in Qt 5.15. + \value AbortOnBase64DecodingErrors When decoding Base64-encoded data, stops at the first + decoding error. + This enum value has been added in Qt 5.15. + + QByteArray::fromBase64Encoding() and QByteArray::fromBase64() + ignore the KeepTrailingEquals and OmitTrailingEquals options. If + the IgnoreBase64DecodingErrors option is specified, they will not + flag errors in case trailing equal signs are missing or if there + are too many of them. If instead the AbortOnBase64DecodingErrors is + specified, then the input must either have no padding or have the + correct amount of equal signs. */ /*! \fn QByteArray::iterator QByteArray::begin() @@ -1184,9 +1195,6 @@ QByteArray qUncompress(const uchar* data, int nbytes) */ QByteArray &QByteArray::operator=(const QByteArray & other) noexcept { - other.d->ref.ref(); - if (!d->ref.deref()) - Data::deallocate(d); d = other.d; return *this; } @@ -1200,25 +1208,23 @@ QByteArray &QByteArray::operator=(const QByteArray & other) noexcept QByteArray &QByteArray::operator=(const char *str) { - Data *x; - if (!str) { - x = Data::sharedNull(); - } else if (!*str) { - x = Data::allocate(0); + if (!str || !*str) { + QPair<Data *, char *> pair; + if (!str) { + pair = qMakePair(Data::sharedNull(), Data::sharedNullData()); + } else { + pair = Data::allocate(0); + } + d = QByteArrayData(pair.first, pair.second, 0); } else { const int len = int(strlen(str)); - const uint fullLen = len + 1; - if (d->ref.isShared() || fullLen > d->alloc - || (len < d->size && fullLen < uint(d->alloc >> 1))) + const uint fullLen = uint(len) + 1; + if (d->needsDetach() || fullLen > d->allocatedCapacity() + || (len < size() && fullLen < (d->allocatedCapacity() >> 1))) reallocData(fullLen, d->detachFlags()); - x = d; - memcpy(x->data(), str, fullLen); // include null terminator - x->size = len; + memcpy(d.data(), str, fullLen); // include null terminator + d.size = len; } - x->ref.ref(); - if (!d->ref.deref()) - Data::deallocate(d); - d = x; return *this; } @@ -1421,7 +1427,7 @@ QByteArray &QByteArray::operator=(const char *str) \sa operator[]() */ -/*! \fn QByteRef QByteArray::operator[](int i) +/*! \fn char &QByteArray::operator[](int i) Returns the byte at index position \a i as a modifiable reference. @@ -1432,21 +1438,6 @@ QByteArray &QByteArray::operator=(const char *str) Example: \snippet code/src_corelib_tools_qbytearray.cpp 9 - The return value is of type QByteRef, a helper class for - QByteArray. When you get an object of type QByteRef, you can use - it as if it were a char &. If you assign to it, the assignment - will apply to the character in the QByteArray from which you got - the reference. - - \note Before Qt 5.14 it was possible to use this operator to access - a character at an out-of-bounds position in the byte array, and - then assign to such a position, causing the byte array to be - automatically resized. Furthermore, assigning a value to the - returned QByteRef would cause a detach of the byte array, even if the - byte array has been copied in the meanwhile (and the QByteRef kept - alive while the copy was taken). These behaviors are deprecated, - and will be changed in a future version of Qt. - \sa at() */ @@ -1457,16 +1448,6 @@ QByteArray &QByteArray::operator=(const char *str) Same as at(\a i). */ -/*! \fn QByteRef QByteArray::operator[](uint i) - - \overload -*/ - -/*! \fn char QByteArray::operator[](uint i) const - - \overload -*/ - /*! \fn char QByteArray::front() const \since 5.10 @@ -1498,7 +1479,7 @@ QByteArray &QByteArray::operator=(const char *str) */ /*! - \fn QByteRef QByteArray::front() + \fn char &QByteArray::front() \since 5.10 Returns a reference to the first character in the byte array. @@ -1513,7 +1494,7 @@ QByteArray &QByteArray::operator=(const char *str) */ /*! - \fn QByteRef QByteArray::back() + \fn char &QByteArray::back() \since 5.10 Returns a reference to the last character in the byte array. @@ -1564,7 +1545,7 @@ QByteArray &QByteArray::operator=(const char *str) */ void QByteArray::truncate(int pos) { - if (pos < d->size) + if (pos < size()) resize(pos); } @@ -1584,7 +1565,7 @@ void QByteArray::truncate(int pos) void QByteArray::chop(int n) { if (n > 0) - resize(d->size - n); + resize(size() - n); } @@ -1688,19 +1669,13 @@ void QByteArray::chop(int n) QByteArray::QByteArray(const char *data, int size) { if (!data) { - d = Data::sharedNull(); + d = DataPointer(); } else { if (size < 0) size = int(strlen(data)); - if (!size) { - d = Data::allocate(0); - } else { - d = Data::allocate(uint(size) + 1u); - Q_CHECK_PTR(d); - d->size = size; - memcpy(d->data(), data, size); - d->data()[size] = '\0'; - } + d = DataPointer(Data::allocate(uint(size) + 1u), size); + memcpy(d.data(), data, size); + d.data()[size] = '\0'; } } @@ -1714,13 +1689,11 @@ QByteArray::QByteArray(const char *data, int size) QByteArray::QByteArray(int size, char ch) { if (size <= 0) { - d = Data::allocate(0); + d = DataPointer(Data::allocate(0), 0); } else { - d = Data::allocate(uint(size) + 1u); - Q_CHECK_PTR(d); - d->size = size; - memset(d->data(), ch, size); - d->data()[size] = '\0'; + d = DataPointer(Data::allocate(uint(size) + 1u), size); + memset(d.data(), ch, size); + d.data()[size] = '\0'; } } @@ -1732,10 +1705,8 @@ QByteArray::QByteArray(int size, char ch) QByteArray::QByteArray(int size, Qt::Initialization) { - d = Data::allocate(uint(size) + 1u); - Q_CHECK_PTR(d); - d->size = size; - d->data()[size] = '\0'; + d = DataPointer(Data::allocate(uint(size) + 1u), size); + d.data()[size] = '\0'; } /*! @@ -1755,31 +1726,21 @@ void QByteArray::resize(int size) if (size < 0) size = 0; - if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) { - d->size = size; + if (!d->isShared() && !d->isMutable() && size < int(d.size)) { + d.size = size; return; } - if (d->size == 0 && d->ref.isStatic()) { - // - // Optimize the idiom: - // QByteArray a; - // a.resize(sz); - // ... - // which is used in place of the Qt 3 idiom: - // QByteArray a(sz); - // - Data *x = Data::allocate(uint(size) + 1u); - Q_CHECK_PTR(x); - x->size = size; - x->data()[size] = '\0'; - d = x; + if (size == 0 && !(d->flags() & Data::CapacityReserved)) { + d = DataPointer(Data::allocate(0), 0); } else { - if (d->ref.isShared() || uint(size) + 1u > d->alloc) - reallocData(uint(size) + 1u, d->detachFlags() | Data::Grow); - if (d->alloc) { - d->size = size; - d->data()[size] = '\0'; + if (d->needsDetach() || size > capacity() + || (!(d->flags() & Data::CapacityReserved) && size < int(d.size) + && size < (capacity() >> 1))) + reallocData(uint(size) + 1u, d->detachFlags() | Data::GrowsForward); + d.size = size; + if (d->isMutable()) { + d.data()[size] = '\0'; } } } @@ -1797,33 +1758,27 @@ void QByteArray::resize(int size) QByteArray &QByteArray::fill(char ch, int size) { - resize(size < 0 ? d->size : size); - if (d->size) - memset(d->data(), ch, d->size); + resize(size < 0 ? this->size() : size); + if (this->size()) + memset(d.data(), ch, this->size()); return *this; } -void QByteArray::reallocData(uint alloc, Data::AllocationOptions options) +void QByteArray::reallocData(uint alloc, Data::ArrayOptions options) { - if (d->ref.isShared() || IS_RAW_DATA(d)) { - Data *x = Data::allocate(alloc, options); - Q_CHECK_PTR(x); - x->size = qMin(int(alloc) - 1, d->size); - ::memcpy(x->data(), d->data(), x->size); - x->data()[x->size] = '\0'; - if (!d->ref.deref()) - Data::deallocate(d); - d = x; + if (d->needsDetach()) { + DataPointer dd(Data::allocate(alloc, options), qMin(int(alloc) - 1, d.size)); + ::memcpy(dd.data(), d.data(), dd.size); + dd.data()[dd.size] = 0; + d = dd; } else { - Data *x = Data::reallocateUnaligned(d, alloc, options); - Q_CHECK_PTR(x); - d = x; + d.reallocate(alloc, options); } } void QByteArray::expand(int i) { - resize(qMax(i + 1, d->size)); + resize(qMax(i + 1, size())); } /*! @@ -1869,9 +1824,9 @@ QByteArray QByteArray::nulTerminated() const QByteArray &QByteArray::prepend(const QByteArray &ba) { - if (d->size == 0 && d->ref.isStatic() && !IS_RAW_DATA(ba.d)) { + if (size() == 0 && d->isStatic() && !IS_RAW_DATA(ba.d)) { *this = ba; - } else if (ba.d->size != 0) { + } else if (ba.size() != 0) { QByteArray tmp = *this; *this = ba; append(tmp); @@ -1900,12 +1855,12 @@ QByteArray &QByteArray::prepend(const char *str) QByteArray &QByteArray::prepend(const char *str, int len) { if (str) { - if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc) - reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::Grow); - memmove(d->data()+len, d->data(), d->size); - memcpy(d->data(), str, len); - d->size += len; - d->data()[d->size] = '\0'; + if (d->needsDetach() || size() + len > capacity()) + reallocData(uint(size() + len) + 1u, d->detachFlags() | Data::GrowsForward); + memmove(d.data()+len, d.data(), d.size); + memcpy(d.data(), str, len); + d.size += len; + d.data()[d.size] = '\0'; } return *this; } @@ -1926,12 +1881,12 @@ QByteArray &QByteArray::prepend(const char *str, int len) QByteArray &QByteArray::prepend(char ch) { - if (d->ref.isShared() || uint(d->size) + 2u > d->alloc) - reallocData(uint(d->size) + 2u, d->detachFlags() | Data::Grow); - memmove(d->data()+1, d->data(), d->size); - d->data()[0] = ch; - ++d->size; - d->data()[d->size] = '\0'; + if (d->needsDetach() || size() + 1 > capacity()) + reallocData(uint(size()) + 2u, d->detachFlags() | Data::GrowsForward); + memmove(d.data()+1, d.data(), d.size); + d.data()[0] = ch; + ++d.size; + d.data()[d.size] = '\0'; return *this; } @@ -1961,14 +1916,14 @@ QByteArray &QByteArray::prepend(char ch) QByteArray &QByteArray::append(const QByteArray &ba) { - if (d->size == 0 && d->ref.isStatic() && !IS_RAW_DATA(ba.d)) { + if (size() == 0 && d->isStatic() && !IS_RAW_DATA(ba.d)) { *this = ba; - } else if (ba.d->size != 0) { - if (d->ref.isShared() || uint(d->size + ba.d->size) + 1u > d->alloc) - reallocData(uint(d->size + ba.d->size) + 1u, d->detachFlags() | Data::Grow); - memcpy(d->data() + d->size, ba.d->data(), ba.d->size); - d->size += ba.d->size; - d->data()[d->size] = '\0'; + } else if (ba.size() != 0) { + if (d->needsDetach() || size() + ba.size() > capacity()) + reallocData(uint(size() + ba.size()) + 1u, d->detachFlags() | Data::GrowsForward); + memcpy(d.data() + d.size, ba.data(), ba.size()); + d.size += ba.size(); + d.data()[d.size] = '\0'; } return *this; } @@ -1996,10 +1951,10 @@ QByteArray& QByteArray::append(const char *str) { if (str) { const int len = int(strlen(str)); - if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc) - reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::Grow); - memcpy(d->data() + d->size, str, len + 1); // include null terminator - d->size += len; + if (d->needsDetach() || size() + len > capacity()) + reallocData(uint(size() + len) + 1u, d->detachFlags() | Data::GrowsForward); + memcpy(d.data() + d.size, str, len + 1); // include null terminator + d.size += len; } return *this; } @@ -2021,11 +1976,11 @@ QByteArray &QByteArray::append(const char *str, int len) if (len < 0) len = qstrlen(str); if (str && len) { - if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc) - reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::Grow); - memcpy(d->data() + d->size, str, len); // include null terminator - d->size += len; - d->data()[d->size] = '\0'; + if (d->needsDetach() || size() + len > capacity()) + reallocData(uint(size() + len) + 1u, d->detachFlags() | Data::GrowsForward); + memcpy(d.data() + d.size, str, len); + d.size += len; + d.data()[d.size] = '\0'; } return *this; } @@ -2049,10 +2004,10 @@ QByteArray &QByteArray::append(const char *str, int len) QByteArray& QByteArray::append(char ch) { - if (d->ref.isShared() || uint(d->size) + 2u > d->alloc) - reallocData(uint(d->size) + 2u, d->detachFlags() | Data::Grow); - d->data()[d->size++] = ch; - d->data()[d->size] = '\0'; + if (d->needsDetach() || size() + 1 > capacity()) + reallocData(uint(size()) + 2u, d->detachFlags() | Data::GrowsForward); + d.data()[d.size++] = ch; + d.data()[d.size] = '\0'; return *this; } @@ -2093,7 +2048,7 @@ static inline QByteArray &qbytearray_insert(QByteArray *ba, QByteArray &QByteArray::insert(int i, const QByteArray &ba) { QByteArray copy(ba); - return qbytearray_insert(this, i, copy.d->data(), copy.d->size); + return qbytearray_insert(this, i, copy.constData(), copy.size()); } /*! @@ -2175,7 +2130,7 @@ QByteArray &QByteArray::insert(int i, int count, char ch) int oldsize = size(); resize(qMax(i, oldsize) + count); - char *dst = d->data(); + char *dst = d.data(); if (i > oldsize) ::memset(dst + oldsize, 0x20, i - oldsize); else if (i < oldsize) @@ -2200,14 +2155,14 @@ QByteArray &QByteArray::insert(int i, int count, char ch) QByteArray &QByteArray::remove(int pos, int len) { - if (len <= 0 || uint(pos) >= uint(d->size)) + if (len <= 0 || uint(pos) >= uint(size())) return *this; detach(); - if (len >= d->size - pos) { + if (len >= size() - pos) { resize(pos); } else { - memmove(d->data() + pos, d->data() + pos + len, d->size - pos - len); - resize(d->size - len); + memmove(d.data() + pos, d.data() + pos + len, size() - pos - len); + resize(size() - len); } return *this; } @@ -2224,9 +2179,9 @@ QByteArray &QByteArray::remove(int pos, int len) QByteArray &QByteArray::replace(int pos, int len, const QByteArray &after) { - if (len == after.d->size && (pos + len <= d->size)) { + if (len == after.size() && (pos + len <= size())) { detach(); - memmove(d->data() + pos, after.d->data(), len*sizeof(char)); + memmove(d.data() + pos, after.data(), len*sizeof(char)); return *this; } else { QByteArray copy(after); @@ -2261,9 +2216,9 @@ QByteArray &QByteArray::replace(int pos, int len, const char *after) */ QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen) { - if (len == alen && (pos + len <= d->size)) { + if (len == alen && (pos + len <= size())) { detach(); - memcpy(d->data() + pos, after, len*sizeof(char)); + memcpy(d.data() + pos, after, len*sizeof(char)); return *this; } else { remove(pos, len); @@ -2286,14 +2241,7 @@ QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen) QByteArray &QByteArray::replace(const QByteArray &before, const QByteArray &after) { - if (isNull() || before.d == after.d) - return *this; - - QByteArray aft = after; - if (after.d == d) - aft.detach(); - - return replace(before.constData(), before.size(), aft.constData(), aft.size()); + return replace(before.constData(), before.size(), after.constData(), after.size()); } /*! @@ -2306,11 +2254,7 @@ QByteArray &QByteArray::replace(const QByteArray &before, const QByteArray &afte QByteArray &QByteArray::replace(const char *c, const QByteArray &after) { - QByteArray aft = after; - if (after.d == d) - aft.detach(); - - return replace(c, qstrlen(c), aft.constData(), aft.size()); + return replace(c, qstrlen(c), after.constData(), after.size()); } /*! @@ -2330,13 +2274,13 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after // protect against before or after being part of this const char *a = after; const char *b = before; - if (after >= d->data() && after < d->data() + d->size) { + if (after >= constBegin() && after < constEnd()) { char *copy = (char *)malloc(asize); Q_CHECK_PTR(copy); memcpy(copy, after, asize); a = copy; } - if (before >= d->data() && before < d->data() + d->size) { + if (before >= constBegin() && before < constEnd()) { char *copy = (char *)malloc(bsize); Q_CHECK_PTR(copy); memcpy(copy, before, bsize); @@ -2345,13 +2289,13 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after QByteArrayMatcher matcher(before, bsize); int index = 0; - int len = d->size; - char *d = data(); + int len = size(); + char *d = data(); // detaches if (bsize == asize) { if (bsize) { while ((index = matcher.indexIn(*this, index)) != -1) { - memcpy(d + index, after, asize); + memcpy(d + index, a, asize); index += bsize; } } @@ -2370,7 +2314,7 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after to = index; } if (asize) { - memcpy(d + to, after, asize); + memcpy(d + to, a, asize); to += asize; } index += bsize; @@ -2413,7 +2357,7 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after resize(newlen); len = newlen; } - d = this->d->data(); + d = this->d.data(); // data(), without the detach() check while(pos) { pos--; @@ -2422,7 +2366,7 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after int moveto = insertstart + asize; memmove(d + moveto, d + movestart, (moveend - movestart)); if (asize) - memcpy(d + insertstart, after, asize); + memcpy(d + insertstart, a, asize); moveend = movestart - bsize; } } @@ -2485,8 +2429,7 @@ QByteArray &QByteArray::replace(const char *before, int bsize, const char *after QByteArray &QByteArray::replace(char before, const QByteArray &after) { char b[2] = { before, '\0' }; - QByteArray cb = fromRawData(b, 1); - return replace(cb, after); + return replace(b, 1, after.constData(), after.size()); } /*! \fn QByteArray &QByteArray::replace(char before, const QString &after) @@ -2520,9 +2463,9 @@ QByteArray &QByteArray::replace(char before, const QByteArray &after) QByteArray &QByteArray::replace(char before, char after) { - if (d->size) { + if (!isEmpty()) { char *i = data(); - char *e = i + d->size; + char *e = i + size(); for (; i != e; ++i) if (*i == before) * i = after; @@ -2563,7 +2506,7 @@ QList<QByteArray> QByteArray::split(char sep) const */ QByteArray QByteArray::repeated(int times) const { - if (d->size == 0) + if (isEmpty()) return *this; if (times <= 1) { @@ -2572,27 +2515,27 @@ QByteArray QByteArray::repeated(int times) const return QByteArray(); } - const int resultSize = times * d->size; + const int resultSize = times * size(); QByteArray result; result.reserve(resultSize); - if (result.d->alloc != uint(resultSize) + 1u) + if (result.capacity() != resultSize) return QByteArray(); // not enough memory - memcpy(result.d->data(), d->data(), d->size); + memcpy(result.d.data(), data(), size()); - int sizeSoFar = d->size; - char *end = result.d->data() + sizeSoFar; + int sizeSoFar = size(); + char *end = result.d.data() + sizeSoFar; const int halfResultSize = resultSize >> 1; while (sizeSoFar <= halfResultSize) { - memcpy(end, result.d->data(), sizeSoFar); + memcpy(end, result.d.data(), sizeSoFar); end += sizeSoFar; sizeSoFar <<= 1; } - memcpy(end, result.d->data(), resultSize - sizeSoFar); - result.d->data()[resultSize] = '\0'; - result.d->size = resultSize; + memcpy(end, result.d.data(), resultSize - sizeSoFar); + result.d.data()[resultSize] = '\0'; + result.d.size = resultSize; return result; } @@ -2614,17 +2557,17 @@ QByteArray QByteArray::repeated(int times) const int QByteArray::indexOf(const QByteArray &ba, int from) const { - const int ol = ba.d->size; + const int ol = ba.size(); if (ol == 0) return from; if (ol == 1) - return indexOf(*ba.d->data(), from); + return indexOf(ba[0], from); - const int l = d->size; - if (from > d->size || ol + from > l) + const int l = size(); + if (from > l || ol + from > l) return -1; - return qFindByteArray(d->data(), d->size, from, ba.d->data(), ol); + return qFindByteArray(data(), size(), from, ba.data(), ol); } /*! \fn int QByteArray::indexOf(const QString &str, int from) const @@ -2658,13 +2601,13 @@ int QByteArray::indexOf(const char *c, int from) const if (ol == 1) return indexOf(*c, from); - const int l = d->size; - if (from > d->size || ol + from > l) + const int l = size(); + if (from > l || ol + from > l) return -1; if (ol == 0) return from; - return qFindByteArray(d->data(), d->size, from, c, ol); + return qFindByteArray(data(), size(), from, c, ol); } /*! @@ -2683,13 +2626,13 @@ int QByteArray::indexOf(const char *c, int from) const int QByteArray::indexOf(char ch, int from) const { if (from < 0) - from = qMax(from + d->size, 0); - if (from < d->size) { - const char *n = d->data() + from - 1; - const char *e = d->data() + d->size; + from = qMax(from + size(), 0); + if (from < size()) { + const char *n = data() + from - 1; + const char *e = end(); while (++n != e) if (*n == ch) - return n - d->data(); + return n - data(); } return -1; } @@ -2744,11 +2687,11 @@ static int lastIndexOfHelper(const char *haystack, int l, const char *needle, in int QByteArray::lastIndexOf(const QByteArray &ba, int from) const { - const int ol = ba.d->size; + const int ol = ba.size(); if (ol == 1) - return lastIndexOf(*ba.d->data(), from); + return lastIndexOf(ba[0], from); - return lastIndexOfHelper(d->data(), d->size, ba.d->data(), ol, from); + return lastIndexOfHelper(data(), size(), ba.data(), ol, from); } /*! \fn int QByteArray::lastIndexOf(const QString &str, int from) const @@ -2783,7 +2726,7 @@ int QByteArray::lastIndexOf(const char *str, int from) const if (ol == 1) return lastIndexOf(*str, from); - return lastIndexOfHelper(d->data(), d->size, str, ol, from); + return lastIndexOfHelper(data(), size(), str, ol, from); } /*! @@ -2803,12 +2746,12 @@ int QByteArray::lastIndexOf(const char *str, int from) const int QByteArray::lastIndexOf(char ch, int from) const { if (from < 0) - from += d->size; - else if (from > d->size) - from = d->size-1; + from += size(); + else if (from > size()) + from = size()-1; if (from >= 0) { - const char *b = d->data(); - const char *n = d->data() + from + 1; + const char *b = data(); + const char *n = b + from + 1; while (n-- != b) if (*n == ch) return n - b; @@ -2827,7 +2770,7 @@ int QByteArray::count(const QByteArray &ba) const { int num = 0; int i = -1; - if (d->size > 500 && ba.d->size > 5) { + if (size() > 500 && ba.size() > 5) { QByteArrayMatcher matcher(ba); while ((i = matcher.indexIn(*this, i + 1)) != -1) ++num; @@ -2862,8 +2805,8 @@ int QByteArray::count(const char *str) const int QByteArray::count(char ch) const { int num = 0; - const char *i = d->data() + d->size; - const char *b = d->data(); + const char *i = end(); + const char *b = begin(); while (i != b) if (*--i == ch) ++num; @@ -2913,11 +2856,11 @@ int QByteArray::count(char ch) const */ bool QByteArray::startsWith(const QByteArray &ba) const { - if (d == ba.d || ba.d->size == 0) - return true; - if (d->size < ba.d->size) + if (size() < ba.size()) return false; - return memcmp(d->data(), ba.d->data(), ba.d->size) == 0; + if (data() == ba.data() || ba.size() == 0) + return true; + return memcmp(data(), ba.data(), ba.size()) == 0; } /*! \overload @@ -2930,9 +2873,9 @@ bool QByteArray::startsWith(const char *str) const if (!str || !*str) return true; const int len = int(strlen(str)); - if (d->size < len) + if (size() < len) return false; - return qstrncmp(d->data(), str, len) == 0; + return qstrncmp(data(), str, len) == 0; } /*! \overload @@ -2942,9 +2885,9 @@ bool QByteArray::startsWith(const char *str) const */ bool QByteArray::startsWith(char ch) const { - if (d->size == 0) + if (size() == 0) return false; - return d->data()[0] == ch; + return data()[0] == ch; } /*! @@ -2958,11 +2901,11 @@ bool QByteArray::startsWith(char ch) const */ bool QByteArray::endsWith(const QByteArray &ba) const { - if (d == ba.d || ba.d->size == 0) - return true; - if (d->size < ba.d->size) + if (size() < ba.size()) return false; - return memcmp(d->data() + d->size - ba.d->size, ba.d->data(), ba.d->size) == 0; + if (end() == ba.end() || ba.size() == 0) + return true; + return memcmp(end() - ba.size(), ba.data(), ba.size()) == 0; } /*! \overload @@ -2975,9 +2918,9 @@ bool QByteArray::endsWith(const char *str) const if (!str || !*str) return true; const int len = int(strlen(str)); - if (d->size < len) + if (size() < len) return false; - return qstrncmp(d->data() + d->size - len, str, len) == 0; + return qstrncmp(end() - len, str, len) == 0; } /* @@ -3059,9 +3002,9 @@ bool QByteArray::isLower() const */ bool QByteArray::endsWith(char ch) const { - if (d->size == 0) + if (size() == 0) return false; - return d->data()[d->size - 1] == ch; + return data()[size() - 1] == ch; } /*! @@ -3079,11 +3022,11 @@ bool QByteArray::endsWith(char ch) const QByteArray QByteArray::left(int len) const { - if (len >= d->size) + if (len >= size()) return *this; if (len < 0) len = 0; - return QByteArray(d->data(), len); + return QByteArray(data(), len); } /*! @@ -3101,11 +3044,11 @@ QByteArray QByteArray::left(int len) const QByteArray QByteArray::right(int len) const { - if (len >= d->size) + if (len >= size()) return *this; if (len < 0) len = 0; - return QByteArray(d->data() + d->size - len, len); + return QByteArray(end() - len, len); } /*! @@ -3130,13 +3073,14 @@ QByteArray QByteArray::mid(int pos, int len) const return QByteArray(); case QContainerImplHelper::Empty: { - QByteArrayDataPtr empty = { Data::allocate(0) }; + auto alloc = Data::allocate(0); + QByteArray::DataPointer empty = { alloc.first, alloc.second, 0 }; return QByteArray(empty); } case QContainerImplHelper::Full: return *this; case QContainerImplHelper::Subset: - return QByteArray(d->data() + pos, len); + return QByteArray(d.data() + pos, len); } Q_UNREACHABLE(); return QByteArray(); @@ -3239,9 +3183,7 @@ QByteArray QByteArray::toUpper_helper(QByteArray &a) void QByteArray::clear() { - if (!d->ref.deref()) - Data::deallocate(d); - d = Data::sharedNull(); + d.clear(); } #if !defined(QT_NO_DATASTREAM) || (defined(QT_BOOTSTRAPPED) && !defined(QT_BUILD_QMAKE)) @@ -3718,13 +3660,13 @@ QByteArray QByteArray::trimmed_helper(QByteArray &a) QByteArray QByteArray::leftJustified(int width, char fill, bool truncate) const { QByteArray result; - int len = d->size; + int len = size(); int padlen = width - len; if (padlen > 0) { result.resize(len+padlen); if (len) - memcpy(result.d->data(), d->data(), len); - memset(result.d->data()+len, fill, padlen); + memcpy(result.d.data(), data(), len); + memset(result.d.data()+len, fill, padlen); } else { if (truncate) result = left(width); @@ -3755,13 +3697,13 @@ QByteArray QByteArray::leftJustified(int width, char fill, bool truncate) const QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const { QByteArray result; - int len = d->size; + int len = size(); int padlen = width - len; if (padlen > 0) { result.resize(len+padlen); if (len) - memcpy(result.d->data()+padlen, data(), len); - memset(result.d->data(), fill, padlen); + memcpy(result.d.data()+padlen, data(), len); + memset(result.d.data(), fill, padlen); } else { if (truncate) result = left(width); @@ -3771,7 +3713,10 @@ QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const return result; } -bool QByteArray::isNull() const { return d == QArrayData::sharedNull(); } +bool QByteArray::isNull() const +{ + return d->isNull(); +} static qlonglong toIntegral_helper(const char *data, bool *ok, int base, qlonglong) { @@ -4098,19 +4043,19 @@ QByteArray QByteArray::toBase64(Base64Options options) const const char padchar = '='; int padlen = 0; - QByteArray tmp((d->size + 2) / 3 * 4, Qt::Uninitialized); + QByteArray tmp((size() + 2) / 3 * 4, Qt::Uninitialized); int i = 0; char *out = tmp.data(); - while (i < d->size) { + while (i < size()) { // encode 3 bytes at a time int chunk = 0; - chunk |= int(uchar(d->data()[i++])) << 16; - if (i == d->size) { + chunk |= int(uchar(data()[i++])) << 16; + if (i == size()) { padlen = 2; } else { - chunk |= int(uchar(d->data()[i++])) << 8; - if (i == d->size) + chunk |= int(uchar(data()[i++])) << 8; + if (i == size()) padlen = 1; else chunk |= int(uchar(data()[i++])); @@ -4440,17 +4385,14 @@ QByteArray QByteArray::number(double n, char f, int prec) QByteArray QByteArray::fromRawData(const char *data, int size) { - Data *x; + QByteArray::DataPointer x; if (!data) { - x = Data::sharedNull(); } else if (!size) { - x = Data::allocate(0); + x = DataPointer(Data::allocate(0), 0); } else { x = Data::fromRawData(data, size); - Q_CHECK_PTR(x); } - QByteArrayDataPtr dataPtr = { x }; - return QByteArray(dataPtr); + return QByteArray(x); } /*! @@ -4469,77 +4411,178 @@ QByteArray QByteArray::fromRawData(const char *data, int size) */ QByteArray &QByteArray::setRawData(const char *data, uint size) { - if (d->ref.isShared() || d->alloc) { - *this = fromRawData(data, size); - } else { - if (data) { - d->size = size; - d->offset = data - reinterpret_cast<char *>(d); - } else { - d->offset = sizeof(QByteArrayData); - d->size = 0; - } + if (!data || !size) { + clear(); } +// else if (d->isShared() || (d->flags() & Data::RawDataType) == 0) { + *this = fromRawData(data, size); +// } else { +// d.size = size; +// d.data() = const_cast<char *>(data); +// } return *this; } -/*! - \since 5.2 - - Returns a decoded copy of the Base64 array \a base64, using the alphabet - defined by \a options. Input is not checked for validity; invalid - characters in the input are skipped, enabling the decoding process to - continue with subsequent characters. - - For example: - - \snippet code/src_corelib_tools_qbytearray.cpp 44 - - The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}. +namespace { +struct fromBase64_helper_result { + qsizetype decodedLength; + QByteArray::Base64DecodingStatus status; +}; - \sa toBase64() -*/ -QByteArray QByteArray::fromBase64(const QByteArray &base64, Base64Options options) +fromBase64_helper_result fromBase64_helper(const char *input, qsizetype inputSize, + char *output /* may alias input */, + QByteArray::Base64Options options) { + fromBase64_helper_result result{ 0, QByteArray::Base64DecodingStatus::Ok }; + unsigned int buf = 0; int nbits = 0; - QByteArray tmp((base64.size() * 3) / 4, Qt::Uninitialized); - int offset = 0; - for (int i = 0; i < base64.size(); ++i) { - int ch = base64.at(i); + qsizetype offset = 0; + for (qsizetype i = 0; i < inputSize; ++i) { + int ch = input[i]; int d; - if (ch >= 'A' && ch <= 'Z') + if (ch >= 'A' && ch <= 'Z') { d = ch - 'A'; - else if (ch >= 'a' && ch <= 'z') + } else if (ch >= 'a' && ch <= 'z') { d = ch - 'a' + 26; - else if (ch >= '0' && ch <= '9') + } else if (ch >= '0' && ch <= '9') { d = ch - '0' + 52; - else if (ch == '+' && (options & Base64UrlEncoding) == 0) + } else if (ch == '+' && (options & QByteArray::Base64UrlEncoding) == 0) { d = 62; - else if (ch == '-' && (options & Base64UrlEncoding) != 0) + } else if (ch == '-' && (options & QByteArray::Base64UrlEncoding) != 0) { d = 62; - else if (ch == '/' && (options & Base64UrlEncoding) == 0) + } else if (ch == '/' && (options & QByteArray::Base64UrlEncoding) == 0) { d = 63; - else if (ch == '_' && (options & Base64UrlEncoding) != 0) + } else if (ch == '_' && (options & QByteArray::Base64UrlEncoding) != 0) { d = 63; - else - d = -1; + } else { + if (options & QByteArray::AbortOnBase64DecodingErrors) { + if (ch == '=') { + // can have 1 or 2 '=' signs, in both cases padding base64Size to + // a multiple of 4. Any other case is illegal. + if ((inputSize % 4) != 0) { + result.status = QByteArray::Base64DecodingStatus::IllegalInputLength; + return result; + } else if ((i == inputSize - 1) || + (i == inputSize - 2 && input[++i] == '=')) { + d = -1; // ... and exit the loop, normally + } else { + result.status = QByteArray::Base64DecodingStatus::IllegalPadding; + return result; + } + } else { + result.status = QByteArray::Base64DecodingStatus::IllegalCharacter; + return result; + } + } else { + d = -1; + } + } if (d != -1) { buf = (buf << 6) | d; nbits += 6; if (nbits >= 8) { nbits -= 8; - tmp[offset++] = buf >> nbits; + Q_ASSERT(offset < i); + output[offset++] = buf >> nbits; buf &= (1 << nbits) - 1; } } } - tmp.truncate(offset); - return tmp; + result.decodedLength = offset; + return result; +} +} // anonymous namespace + +/*! + \fn QByteArray::FromBase64Result QByteArray::fromBase64Encoding(QByteArray &&base64, Base64Options options) + \fn QByteArray::FromBase64Result QByteArray::fromBase64Encoding(const QByteArray &base64, Base64Options options) + \since 5.15 + \overload + + Decodes the Base64 array \a base64, using the options + defined by \a options. If \a options contains \c{IgnoreBase64DecodingErrors} + (the default), the input is not checked for validity; invalid + characters in the input are skipped, enabling the decoding process to + continue with subsequent characters. If \a options contains + \c{AbortOnBase64DecodingErrors}, then decoding will stop at the first + invalid character. + + For example: + + \snippet code/src_corelib_tools_qbytearray.cpp 44ter + + The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}. + + Returns a QByteArrayFromBase64Result object, containing the decoded + data and a flag telling whether decoding was successful. If the + \c{AbortOnBase64DecodingErrors} option was passed and the input + data was invalid, it is unspecified what the decoded data contains. + + \sa toBase64() +*/ +QByteArray::FromBase64Result QByteArray::fromBase64Encoding(QByteArray &&base64, Base64Options options) +{ + // try to avoid a detach when calling data(), as it would over-allocate + // (we need less space when decoding than the one required by the full copy) + if (base64.isDetached()) { + const auto base64result = fromBase64_helper(base64.data(), + base64.size(), + base64.data(), // in-place + options); + base64.truncate(int(base64result.decodedLength)); + return { std::move(base64), base64result.status }; + } + + return fromBase64Encoding(base64, options); +} + + +QByteArray::FromBase64Result QByteArray::fromBase64Encoding(const QByteArray &base64, Base64Options options) +{ + const auto base64Size = base64.size(); + QByteArray result((base64Size * 3) / 4, Qt::Uninitialized); + const auto base64result = fromBase64_helper(base64.data(), + base64Size, + const_cast<char *>(result.constData()), + options); + result.truncate(int(base64result.decodedLength)); + return { std::move(result), base64result.status }; +} + +/*! + \since 5.2 + + Returns a decoded copy of the Base64 array \a base64, using the options + defined by \a options. If \a options contains \c{IgnoreBase64DecodingErrors} + (the default), the input is not checked for validity; invalid + characters in the input are skipped, enabling the decoding process to + continue with subsequent characters. If \a options contains + \c{AbortOnBase64DecodingErrors}, then decoding will stop at the first + invalid character. + + For example: + + \snippet code/src_corelib_tools_qbytearray.cpp 44 + + The algorithm used to decode Base64-encoded data is defined in \l{RFC 4648}. + + Returns the decoded data, or, if the \c{AbortOnBase64DecodingErrors} + option was passed and the input data was invalid, an empty byte array. + + \note The fromBase64Encoding() function is recommended in new code. + + \sa toBase64(), fromBase64Encoding() +*/ +QByteArray QByteArray::fromBase64(const QByteArray &base64, Base64Options options) +{ + if (auto result = fromBase64Encoding(base64, options)) + return std::move(result.decoded); + return QByteArray(); } /*! @@ -4591,14 +4634,14 @@ QByteArray QByteArray::fromHex(const QByteArray &hexEncoded) */ QByteArray QByteArray::toHex(char separator) const { - if (!d->size) + if (isEmpty()) return QByteArray(); - const int length = separator ? (d->size * 3 - 1) : (d->size * 2); + const int length = separator ? (size() * 3 - 1) : (size() * 2); QByteArray hex(length, Qt::Uninitialized); char *hexData = hex.data(); - const uchar *data = (const uchar *)d->data(); - for (int i = 0, o = 0; i < d->size; ++i) { + const uchar *data = (const uchar *)this->data(); + for (int i = 0, o = 0; i < size(); ++i) { hexData[o++] = QtMiscUtils::toHexLower(data[i] >> 4); hexData[o++] = QtMiscUtils::toHexLower(data[i] & 0xf); @@ -4910,41 +4953,87 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA \sa QStringLiteral */ -namespace QtPrivate { -namespace DeprecatedRefClassBehavior { -void warn(WarningType w, EmittingClass c) -{ - static const char deprecatedBehaviorString[] = - "The corresponding behavior is deprecated, and will be changed" - " in a future version of Qt."; +/*! + \class QByteArray::FromBase64Result + \inmodule QtCore + \ingroup tools + \since 5.15 - const char *emittingClassName = nullptr; - const char *containerClassName = nullptr; + \brief The QByteArray::FromBase64Result class holds the result of + a call to QByteArray::fromBase64Encoding. - switch (c) { - case EmittingClass::QByteRef: - emittingClassName = "QByteRef"; - containerClassName = "QByteArray"; - break; - case EmittingClass::QCharRef: - emittingClassName = "QCharRef"; - containerClassName = "QString"; - break; - } + Objects of this class can be used to check whether the conversion + was successful, and if so, retrieve the decoded QByteArray. The + conversion operators defined for QByteArray::FromBase64Result make + its usage straightforward: - switch (w) { - case WarningType::OutOfRange: - qWarning("Using %s with an index pointing outside the valid range of a %s. %s", - emittingClassName, containerClassName, deprecatedBehaviorString); - break; - case WarningType::DelayedDetach: - qWarning("Using %s with on a %s that is not already detached. %s", - emittingClassName, containerClassName, deprecatedBehaviorString); - break; - } -} -} // namespace DeprecatedRefClassBehavior -} // namespace QtPrivate + \snippet code/src_corelib_tools_qbytearray.cpp 44ter + + In alternative, it is possible to access the conversion status + and the decoded data directly: + + \snippet code/src_corelib_tools_qbytearray.cpp 44quater + + \sa QByteArray::fromBase64 +*/ + +/*! + \variable QByteArray::FromBase64Result::decoded + + Contains the decoded byte array. +*/ + +/*! + \variable QByteArray::FromBase64Result::decodingStatus + + Contains whether the decoding was successful, expressed as a value + of type QByteArray::Base64DecodingStatus. +*/ + +/*! + \fn QByteArray::FromBase64Result::operator bool() const + + Returns whether the decoding was successful. This is equivalent + to checking whether the \c{decodingStatus} member is equal to + QByteArray::Base64DecodingStatus::Ok. +*/ +/*! + \fn QByteArray &QByteArray::FromBase64Result::operator*() const + + Returns the decoded byte array. +*/ + +/*! + \fn bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept + \relates QByteArray::FromBase64Result + + Returns \c true if \a lhs and \a rhs are equal, otherwise returns \c false. + + \a lhs and \a rhs are equal if and only if they contain the same decoding + status and, if the status is QByteArray::Base64DecodingStatus::Ok, if and + only if they contain the same decoded data. +*/ + +/*! + \fn bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept + \relates QByteArray::FromBase64Result + + Returns \c true if \a lhs and \a rhs are different, otherwise returns \c false. +*/ + +/*! + \relates QByteArray::FromBase64Result + + Returns the hash value for \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QByteArray::FromBase64Result &key, uint seed) noexcept +{ + QtPrivate::QHashCombine hash; + seed = hash(seed, key.decoded); + seed = hash(seed, static_cast<int>(key.decodingStatus)); + return seed; +} QT_END_NAMESPACE diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 1376e26260..e3fec1e62c 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -44,6 +44,7 @@ #include <QtCore/qrefcount.h> #include <QtCore/qnamespace.h> #include <QtCore/qarraydata.h> +#include <QtCore/qarraydatapointer.h> #include <QtCore/qcontainerfwd.h> #include <stdlib.h> @@ -110,44 +111,20 @@ Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt, ...); Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len, Qt::ChecksumType standard = Qt::ChecksumIso3309); -class QByteRef; class QString; class QDataStream; -typedef QArrayData QByteArrayData; - -template<int N> struct QStaticByteArrayData -{ - QByteArrayData ba; - char data[N + 1]; - - QByteArrayData *data_ptr() const - { - Q_ASSERT(ba.ref.isStatic()); - return const_cast<QByteArrayData *>(&ba); - } -}; - -struct QByteArrayDataPtr -{ - QByteArrayData *ptr; -}; - -#define Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \ - Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) - /**/ - -#define Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER(size) \ - Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QByteArrayData)) \ - /**/ +using QByteArrayData = QArrayDataPointer<char>; # define QByteArrayLiteral(str) \ ([]() -> QByteArray { \ enum { Size = sizeof(str) - 1 }; \ - static const QStaticByteArrayData<Size> qbytearray_literal = { \ - Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER(Size), \ - str }; \ - QByteArrayDataPtr holder = { qbytearray_literal.data_ptr() }; \ + static const QArrayData qbytearray_literal = { \ + Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 }; \ + QByteArrayData holder = { \ + static_cast<QTypedArrayData<char> *>(const_cast<QArrayData *>(&qbytearray_literal)), \ + const_cast<char *>(str), \ + Size }; \ const QByteArray ba(holder); \ return ba; \ }()) \ @@ -155,19 +132,33 @@ struct QByteArrayDataPtr class Q_CORE_EXPORT QByteArray { +public: + using DataPointer = QByteArrayData; private: typedef QTypedArrayData<char> Data; + DataPointer d; public: + enum Base64Option { Base64Encoding = 0, Base64UrlEncoding = 1, KeepTrailingEquals = 0, - OmitTrailingEquals = 2 + OmitTrailingEquals = 2, + + IgnoreBase64DecodingErrors = 0, + AbortOnBase64DecodingErrors = 4, }; Q_DECLARE_FLAGS(Base64Options, Base64Option) + enum class Base64DecodingStatus { + Ok, + IllegalInputLength, + IllegalCharacter, + IllegalPadding, + }; + inline QByteArray() noexcept; QByteArray(const char *, int size = -1); QByteArray(int size, char c); @@ -177,14 +168,13 @@ public: QByteArray &operator=(const QByteArray &) noexcept; QByteArray &operator=(const char *str); - inline QByteArray(QByteArray && other) noexcept : d(other.d) { other.d = Data::sharedNull(); } + inline QByteArray(QByteArray && other) noexcept + { qSwap(d, other.d); } inline QByteArray &operator=(QByteArray &&other) noexcept { qSwap(d, other.d); return *this; } - inline void swap(QByteArray &other) noexcept { qSwap(d, other.d); } - inline int size() const; inline bool isEmpty() const; void resize(int size); @@ -203,18 +193,17 @@ public: inline const char *constData() const; inline void detach(); inline bool isDetached() const; - inline bool isSharedWith(const QByteArray &other) const { return d == other.d; } + inline bool isSharedWith(const QByteArray &other) const + { return data() == other.data() && size() == other.size(); } void clear(); inline char at(int i) const; inline char operator[](int i) const; - inline char operator[](uint i) const; - Q_REQUIRED_RESULT inline QByteRef operator[](int i); - Q_REQUIRED_RESULT inline QByteRef operator[](uint i); + Q_REQUIRED_RESULT inline char &operator[](int i); Q_REQUIRED_RESULT char front() const { return at(0); } - Q_REQUIRED_RESULT inline QByteRef front(); + Q_REQUIRED_RESULT inline char &front(); Q_REQUIRED_RESULT char back() const { return at(size() - 1); } - Q_REQUIRED_RESULT inline QByteRef back(); + Q_REQUIRED_RESULT inline char &back(); int indexOf(char c, int from = 0) const; int indexOf(const char *c, int from = 0) const; @@ -254,7 +243,7 @@ public: void chop(int n); #if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC) -# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_CPP_ATTRIBUTE(nodiscard) +# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_cpp_attribute(nodiscard) // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 # pragma push_macro("Q_REQUIRED_RESULT") # undef Q_REQUIRED_RESULT @@ -377,8 +366,11 @@ public: Q_REQUIRED_RESULT static QByteArray number(qulonglong, int base = 10); Q_REQUIRED_RESULT static QByteArray number(double, char f = 'g', int prec = 6); Q_REQUIRED_RESULT static QByteArray fromRawData(const char *, int size); - Q_REQUIRED_RESULT static QByteArray fromBase64(const QByteArray &base64, - Base64Options options = Base64Encoding); + + class FromBase64Result; + Q_REQUIRED_RESULT static FromBase64Result fromBase64Encoding(QByteArray &&base64, Base64Options options = Base64Encoding); + Q_REQUIRED_RESULT static FromBase64Result fromBase64Encoding(const QByteArray &base64, Base64Options options = Base64Encoding); + Q_REQUIRED_RESULT static QByteArray fromBase64(const QByteArray &base64, Base64Options options = Base64Encoding); Q_REQUIRED_RESULT static QByteArray fromHex(const QByteArray &hexEncoded); Q_REQUIRED_RESULT static QByteArray fromPercentEncoding(const QByteArray &pctEncoded, char percent = '%'); @@ -433,19 +425,20 @@ public: static inline QByteArray fromStdString(const std::string &s); inline std::string toStdString() const; - inline int count() const { return d->size; } - int length() const { return d->size; } + inline int size() const { return d->size; } + inline int count() const { return size(); } + inline int length() const { return size(); } bool isNull() const; - inline QByteArray(QByteArrayDataPtr dd) - : d(static_cast<Data *>(dd.ptr)) + inline DataPointer &data_ptr() { return d; } + explicit inline QByteArray(const DataPointer &dd) + : d(dd) { } private: operator QNoImplicitBoolCast() const; - Data *d; - void reallocData(uint alloc, Data::AllocationOptions options); + void reallocData(uint alloc, Data::ArrayOptions options); void expand(int i); QByteArray nulTerminated() const; @@ -458,171 +451,86 @@ private: static QByteArray simplified_helper(const QByteArray &a); static QByteArray simplified_helper(QByteArray &a); - friend class QByteRef; friend class QString; friend Q_CORE_EXPORT QByteArray qUncompress(const uchar *data, int nbytes); -public: - typedef Data * DataPtr; - inline DataPtr &data_ptr() { return d; } }; Q_DECLARE_OPERATORS_FOR_FLAGS(QByteArray::Base64Options) -inline QByteArray::QByteArray() noexcept : d(Data::sharedNull()) { } -inline QByteArray::~QByteArray() { if (!d->ref.deref()) Data::deallocate(d); } -inline int QByteArray::size() const -{ return d->size; } +inline QByteArray::QByteArray() noexcept {} +inline QByteArray::~QByteArray() {} inline char QByteArray::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 char QByteArray::operator[](int i) const -{ Q_ASSERT(uint(i) < uint(size())); return d->data()[i]; } -inline char QByteArray::operator[](uint i) const -{ Q_ASSERT(i < uint(size())); return d->data()[i]; } +{ Q_ASSERT(uint(i) < uint(size())); return d.data()[i]; } inline bool QByteArray::isEmpty() const -{ return d->size == 0; } +{ return size() == 0; } #ifndef QT_NO_CAST_FROM_BYTEARRAY inline QByteArray::operator const char *() const -{ return d->data(); } +{ return data(); } inline QByteArray::operator const void *() const -{ return d->data(); } +{ return data(); } #endif inline char *QByteArray::data() -{ detach(); return d->data(); } +{ detach(); return d.data(); } inline const char *QByteArray::data() const -{ return d->data(); } +{ return d.data(); } inline const char *QByteArray::constData() const -{ return d->data(); } +{ return d.data(); } inline void QByteArray::detach() -{ if (d->ref.isShared() || (d->offset != sizeof(QByteArrayData))) reallocData(uint(d->size) + 1u, d->detachFlags()); } +{ if (d->needsDetach()) reallocData(uint(size()) + 1u, d->detachFlags()); } inline bool QByteArray::isDetached() const -{ return !d->ref.isShared(); } +{ return !d->isShared(); } inline QByteArray::QByteArray(const QByteArray &a) noexcept : d(a.d) -{ d->ref.ref(); } +{} inline int QByteArray::capacity() const -{ return d->alloc ? d->alloc - 1 : 0; } +{ const auto realCapacity = d->constAllocatedCapacity(); return realCapacity ? int(realCapacity) - 1 : 0; } inline void QByteArray::reserve(int asize) { - if (d->ref.isShared() || uint(asize) + 1u > d->alloc) { + if (d->needsDetach() || asize > capacity()) { reallocData(qMax(uint(size()), uint(asize)) + 1u, d->detachFlags() | Data::CapacityReserved); } else { - // cannot set unconditionally, since d could be the shared_null or - // otherwise static - d->capacityReserved = true; + d->flags() |= Data::CapacityReserved; } } inline void QByteArray::squeeze() { - if (d->ref.isShared() || uint(d->size) + 1u < d->alloc) { - reallocData(uint(d->size) + 1u, d->detachFlags() & ~Data::CapacityReserved); + if ((d->flags() & Data::CapacityReserved) == 0) + return; + if (d->needsDetach() || size() < capacity()) { + reallocData(uint(size()) + 1u, d->detachFlags() & ~Data::CapacityReserved); } else { - // cannot set unconditionally, since d could be shared_null or - // otherwise static. - d->capacityReserved = false; + d->flags() &= uint(~Data::CapacityReserved); } } -namespace QtPrivate { -namespace DeprecatedRefClassBehavior { - enum class EmittingClass { - QByteRef, - QCharRef, - }; - - enum class WarningType { - OutOfRange, - DelayedDetach, - }; - - Q_CORE_EXPORT Q_DECL_COLD_FUNCTION void warn(WarningType w, EmittingClass c); -} // namespace DeprecatedAssignmentOperatorBehavior -} // namespace QtPrivate - -class -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -Q_CORE_EXPORT -#endif -QByteRef { // ### Qt 7: remove - QByteArray &a; - int i; - inline QByteRef(QByteArray &array, int idx) - : a(array),i(idx) {} - friend class QByteArray; -public: - inline operator char() const - { - using namespace QtPrivate::DeprecatedRefClassBehavior; - if (Q_LIKELY(i < a.d->size)) - return a.d->data()[i]; -#ifdef QT_DEBUG - warn(WarningType::OutOfRange, EmittingClass::QByteRef); -#endif - return char(0); - } - inline QByteRef &operator=(char c) - { - using namespace QtPrivate::DeprecatedRefClassBehavior; - if (Q_UNLIKELY(i >= a.d->size)) { -#ifdef QT_DEBUG - warn(WarningType::OutOfRange, EmittingClass::QByteRef); -#endif - a.expand(i); - } else { -#ifdef QT_DEBUG - if (Q_UNLIKELY(!a.isDetached())) - warn(WarningType::DelayedDetach, EmittingClass::QByteRef); -#endif - a.detach(); - } - a.d->data()[i] = c; - return *this; - } - inline QByteRef &operator=(const QByteRef &c) - { - return operator=(char(c)); - } - inline bool operator==(char c) const - { return a.d->data()[i] == c; } - inline bool operator!=(char c) const - { return a.d->data()[i] != c; } - inline bool operator>(char c) const - { return a.d->data()[i] > c; } - inline bool operator>=(char c) const - { return a.d->data()[i] >= c; } - inline bool operator<(char c) const - { return a.d->data()[i] < c; } - inline bool operator<=(char c) const - { return a.d->data()[i] <= c; } -}; - -inline QByteRef QByteArray::operator[](int i) -{ Q_ASSERT(i >= 0); detach(); return QByteRef(*this, i); } -inline QByteRef QByteArray::operator[](uint i) -{ detach(); return QByteRef(*this, i); } -inline QByteRef QByteArray::front() { return operator[](0); } -inline QByteRef QByteArray::back() { return operator[](size() - 1); } +inline char &QByteArray::operator[](int i) +{ Q_ASSERT(i >= 0 && i < size()); return data()[i]; } +inline char &QByteArray::front() { return operator[](0); } +inline char &QByteArray::back() { return operator[](size() - 1); } inline QByteArray::iterator QByteArray::begin() -{ detach(); return d->data(); } +{ return data(); } inline QByteArray::const_iterator QByteArray::begin() const -{ return d->data(); } +{ return data(); } inline QByteArray::const_iterator QByteArray::cbegin() const -{ return d->data(); } +{ return data(); } inline QByteArray::const_iterator QByteArray::constBegin() const -{ return d->data(); } +{ return data(); } inline QByteArray::iterator QByteArray::end() -{ detach(); return d->data() + d->size; } +{ return data() + size(); } inline QByteArray::const_iterator QByteArray::end() const -{ return d->data() + d->size; } +{ return data() + size(); } inline QByteArray::const_iterator QByteArray::cend() const -{ return d->data() + d->size; } +{ return data() + size(); } inline QByteArray::const_iterator QByteArray::constEnd() const -{ return d->data() + d->size; } +{ return data() + size(); } inline QByteArray &QByteArray::append(int n, char ch) -{ return insert(d->size, n, ch); } +{ return insert(size(), n, ch); } inline QByteArray &QByteArray::prepend(int n, char ch) { return insert(0, n, ch); } inline QByteArray &QByteArray::operator+=(char c) @@ -747,6 +655,50 @@ inline QByteArray qUncompress(const QByteArray& data) Q_DECLARE_SHARED(QByteArray) +class QByteArray::FromBase64Result +{ +public: + QByteArray decoded; + QByteArray::Base64DecodingStatus decodingStatus; + + void swap(QByteArray::FromBase64Result &other) noexcept + { + qSwap(decoded, other.decoded); + qSwap(decodingStatus, other.decodingStatus); + } + + explicit operator bool() const noexcept { return decodingStatus == QByteArray::Base64DecodingStatus::Ok; } + +#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(Q_QDOC) + QByteArray &operator*() & noexcept { return decoded; } + const QByteArray &operator*() const & noexcept { return decoded; } + QByteArray &&operator*() && noexcept { return std::move(decoded); } +#else + QByteArray &operator*() noexcept { return decoded; } + const QByteArray &operator*() const noexcept { return decoded; } +#endif +}; + +Q_DECLARE_SHARED(QByteArray::FromBase64Result) + +inline bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept +{ + if (lhs.decodingStatus != rhs.decodingStatus) + return false; + + if (lhs.decodingStatus == QByteArray::Base64DecodingStatus::Ok && lhs.decoded != rhs.decoded) + return false; + + return true; +} + +inline bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept +{ + return !operator==(lhs, rhs); +} + +Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QByteArray::FromBase64Result &key, uint seed = 0) noexcept; + QT_END_NAMESPACE #endif // QBYTEARRAY_H diff --git a/src/corelib/text/qbytearray_p.h b/src/corelib/text/qbytearray_p.h index 3c6257f786..d6a5e277b3 100644 --- a/src/corelib/text/qbytearray_p.h +++ b/src/corelib/text/qbytearray_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE enum { // Define as enum to force inlining. Don't expose MaxAllocSize in a public header. - MaxByteArraySize = MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPtr>::type) + MaxByteArraySize = MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPointer>::type) }; QT_END_NAMESPACE diff --git a/src/corelib/text/qbytearraylist.h b/src/corelib/text/qbytearraylist.h index 4b6c926960..d02fa6d20f 100644 --- a/src/corelib/text/qbytearraylist.h +++ b/src/corelib/text/qbytearraylist.h @@ -80,9 +80,6 @@ public: inline QByteArray join(char sep) const { return QtPrivate::QByteArrayList_join(self(), &sep, 1); } - inline int indexOf(const char *needle, int from = 0) const - { return QtPrivate::QByteArrayList_indexOf(self(), needle, from); } - private: typedef QVector<QByteArray> Self; Self *self() { return static_cast<Self *>(this); } diff --git a/src/corelib/text/qchar.cpp b/src/corelib/text/qchar.cpp index 9b03a93278..61b61125b1 100644 --- a/src/corelib/text/qchar.cpp +++ b/src/corelib/text/qchar.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -189,6 +189,9 @@ QT_BEGIN_NAMESPACE \value Unicode_8_0 Version 8.0 Since Qt 5.6 \value Unicode_9_0 Version 9.0 Since Qt 5.11 \value Unicode_10_0 Version 10.0 Since Qt 5.11 + \value Unicode_11_0 Version 11.0 Since Qt 5.15 + \value Unicode_12_0 Version 12.0 Since Qt 5.15 + \value Unicode_12_1 Version 12.1 Since Qt 5.15 \value Unicode_Unassigned The value is not assigned to any character in version 8.0 of Unicode. @@ -288,145 +291,156 @@ QT_BEGIN_NAMESPACE \value Script_Common For characters that may be used with multiple scripts and that do not inherit their script from the preceding characters. - \value Script_Latin - \value Script_Greek - \value Script_Cyrillic - \value Script_Armenian - \value Script_Hebrew + \value Script_Adlam Since Qt 5.11 + \value Script_Ahom Since Qt 5.6 + \value Script_AnatolianHieroglyphs Since Qt 5.6 \value Script_Arabic - \value Script_Syriac - \value Script_Thaana - \value Script_Devanagari + \value Script_Armenian + \value Script_Avestan + \value Script_Balinese + \value Script_Bamum + \value Script_BassaVah Since Qt 5.5 + \value Script_Batak \value Script_Bengali - \value Script_Gurmukhi - \value Script_Gujarati - \value Script_Oriya - \value Script_Tamil - \value Script_Telugu - \value Script_Kannada - \value Script_Malayalam - \value Script_Sinhala - \value Script_Thai - \value Script_Lao - \value Script_Tibetan - \value Script_Myanmar - \value Script_Georgian - \value Script_Hangul - \value Script_Ethiopic - \value Script_Cherokee - \value Script_CanadianAboriginal - \value Script_Ogham - \value Script_Runic - \value Script_Khmer - \value Script_Mongolian - \value Script_Hiragana - \value Script_Katakana + \value Script_Bhaiksuki Since Qt 5.11 \value Script_Bopomofo - \value Script_Han - \value Script_Yi - \value Script_OldItalic - \value Script_Gothic - \value Script_Deseret - \value Script_Tagalog - \value Script_Hanunoo - \value Script_Buhid - \value Script_Tagbanwa - \value Script_Coptic - \value Script_Limbu - \value Script_TaiLe - \value Script_LinearB - \value Script_Ugaritic - \value Script_Shavian - \value Script_Osmanya - \value Script_Cypriot + \value Script_Brahmi \value Script_Braille \value Script_Buginese - \value Script_NewTaiLue - \value Script_Glagolitic - \value Script_Tifinagh - \value Script_SylotiNagri - \value Script_OldPersian - \value Script_Kharoshthi - \value Script_Balinese - \value Script_Cuneiform - \value Script_Phoenician - \value Script_PhagsPa - \value Script_Nko - \value Script_Sundanese - \value Script_Lepcha - \value Script_OlChiki - \value Script_Vai - \value Script_Saurashtra - \value Script_KayahLi - \value Script_Rejang - \value Script_Lycian + \value Script_Buhid + \value Script_CanadianAboriginal \value Script_Carian - \value Script_Lydian + \value Script_CaucasianAlbanian Since Qt 5.5 + \value Script_Chakma \value Script_Cham - \value Script_TaiTham - \value Script_TaiViet - \value Script_Avestan + \value Script_Cherokee + \value Script_Coptic + \value Script_Cuneiform + \value Script_Cypriot + \value Script_Cyrillic + \value Script_Deseret + \value Script_Devanagari + \value Script_Dogra Since Qt 5.15 + \value Script_Duployan Since Qt 5.5 \value Script_EgyptianHieroglyphs - \value Script_Samaritan - \value Script_Lisu - \value Script_Bamum - \value Script_Javanese - \value Script_MeeteiMayek + \value Script_Elbasan Since Qt 5.5 + \value Script_Elymaic Since Qt 5.15 + \value Script_Ethiopic + \value Script_Georgian + \value Script_Glagolitic + \value Script_Gothic + \value Script_Grantha Since Qt 5.5 + \value Script_Greek + \value Script_Gujarati + \value Script_GunjalaGondi Since Qt 5.15 + \value Script_Gurmukhi + \value Script_Han + \value Script_Hangul + \value Script_HanifiRohingya Since Qt 5.15 + \value Script_Hanunoo + \value Script_Hatran Since Qt 5.6 + \value Script_Hebrew + \value Script_Hiragana \value Script_ImperialAramaic - \value Script_OldSouthArabian - \value Script_InscriptionalParthian \value Script_InscriptionalPahlavi - \value Script_OldTurkic + \value Script_InscriptionalParthian + \value Script_Javanese \value Script_Kaithi - \value Script_Batak - \value Script_Brahmi + \value Script_Kannada + \value Script_Katakana + \value Script_KayahLi + \value Script_Kharoshthi + \value Script_Khmer + \value Script_Khojki Since Qt 5.5 + \value Script_Khudawadi Since Qt 5.5 + \value Script_Lao + \value Script_Latin + \value Script_Lepcha + \value Script_Limbu + \value Script_LinearA Since Qt 5.5 + \value Script_LinearB + \value Script_Lisu + \value Script_Lycian + \value Script_Lydian + \value Script_Mahajani Since Qt 5.5 + \value Script_Makasar Since Qt 5.15 + \value Script_Malayalam \value Script_Mandaic - \value Script_Chakma + \value Script_Manichaean Since Qt 5.5 + \value Script_Marchen Since Qt 5.11 + \value Script_MasaramGondi Since Qt 5.11 + \value Script_Medefaidrin Since Qt 5.15 + \value Script_MeeteiMayek + \value Script_MendeKikakui Since Qt 5.5 \value Script_MeroiticCursive \value Script_MeroiticHieroglyphs \value Script_Miao + \value Script_Modi Since Qt 5.5 + \value Script_Mongolian + \value Script_Mro Since Qt 5.5 + \value Script_Multani Since Qt 5.6 + \value Script_Myanmar + \value Script_Nabataean Since Qt 5.5 + \value Script_Nandinagari Since Qt 5.15 + \value Script_Newa Since Qt 5.11 + \value Script_NewTaiLue + \value Script_Nko + \value Script_Nushu Since Qt 5.11 + \value Script_NyiakengPuachueHmong Since Qt 5.15 + \value Script_Ogham + \value Script_OlChiki + \value Script_OldHungarian Since Qt 5.6 + \value Script_OldItalic + \value Script_OldNorthArabian Since Qt 5.5 + \value Script_OldPermic Since Qt 5.5 + \value Script_OldPersian + \value Script_OldSogdian Since Qt 5.15 + \value Script_OldSouthArabian + \value Script_OldTurkic + \value Script_Oriya + \value Script_Osage Since Qt 5.11 + \value Script_Osmanya + \value Script_PahawhHmong Since Qt 5.5 + \value Script_Palmyrene Since Qt 5.5 + \value Script_PauCinHau Since Qt 5.5 + \value Script_PhagsPa + \value Script_Phoenician + \value Script_PsalterPahlavi Since Qt 5.5 + \value Script_Rejang + \value Script_Runic + \value Script_Samaritan + \value Script_Saurashtra \value Script_Sharada + \value Script_Shavian + \value Script_Siddham Since Qt 5.5 + \value Script_SignWriting Since Qt 5.6 + \value Script_Sinhala + \value Script_Sogdian Since Qt 5.15 \value Script_SoraSompeng + \value Script_Soyombo Since Qt 5.11 + \value Script_Sundanese + \value Script_SylotiNagri + \value Script_Syriac + \value Script_Tagalog + \value Script_Tagbanwa + \value Script_TaiLe + \value Script_TaiTham + \value Script_TaiViet \value Script_Takri - \value Script_CaucasianAlbanian - \value Script_BassaVah - \value Script_Duployan - \value Script_Elbasan - \value Script_Grantha - \value Script_PahawhHmong - \value Script_Khojki - \value Script_LinearA - \value Script_Mahajani - \value Script_Manichaean - \value Script_MendeKikakui - \value Script_Modi - \value Script_Mro - \value Script_OldNorthArabian - \value Script_Nabataean - \value Script_Palmyrene - \value Script_PauCinHau - \value Script_OldPermic - \value Script_PsalterPahlavi - \value Script_Siddham - \value Script_Khudawadi - \value Script_Tirhuta - \value Script_WarangCiti - \value Script_Ahom - \value Script_AnatolianHieroglyphs - \value Script_Hatran - \value Script_Multani - \value Script_OldHungarian - \value Script_SignWriting - \value Script_Adlam - \value Script_Bhaiksuki - \value Script_Marchen - \value Script_Newa - \value Script_Osage - \value Script_Tangut - \value Script_MasaramGondi - \value Script_Nushu - \value Script_Soyombo - \value Script_ZanabazarSquare + \value Script_Tamil + \value Script_Tangut Since Qt 5.11 + \value Script_Telugu + \value Script_Thaana + \value Script_Thai + \value Script_Tibetan + \value Script_Tifinagh + \value Script_Tirhuta Since Qt 5.5 + \value Script_Ugaritic + \value Script_Vai + \value Script_Wancho Since Qt 5.15 + \value Script_WarangCiti Since Qt 5.5 + \value Script_Yi + \value Script_ZanabazarSquare Since Qt 5.11 \omitvalue ScriptCount diff --git a/src/corelib/text/qchar.h b/src/corelib/text/qchar.h index 85a380e7cf..9d0741af8b 100644 --- a/src/corelib/text/qchar.h +++ b/src/corelib/text/qchar.h @@ -437,9 +437,8 @@ public: Unicode_10_0, Unicode_11_0, Unicode_12_0, - Unicode_12_1, + Unicode_12_1 }; - // ****** WHEN ADDING FUNCTIONS, CONSIDER ADDING TO QCharRef TOO inline Category category() const noexcept { return QChar::category(ucs); } inline Direction direction() const noexcept { return QChar::direction(ucs); } diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 75a5bc802e..93a8abb1ce 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2019 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_SYSTEMLOCALE -static QSystemLocale *_systemLocale = 0; +static QSystemLocale *_systemLocale = nullptr; class QSystemLocaleSingleton: public QSystemLocale { public: @@ -651,7 +651,6 @@ int qt_repeatCount(QStringView s) } static const QLocaleData *default_data = nullptr; -static QLocale::NumberOptions default_number_options = QLocale::DefaultNumberOptions; static const QLocaleData *const c_data = locale_data; static QLocalePrivate *c_private() @@ -695,7 +694,7 @@ QSystemLocale::QSystemLocale(bool) QSystemLocale::~QSystemLocale() { if (_systemLocale == this) { - _systemLocale = 0; + _systemLocale = nullptr; globalLocaleData.m_language_id = 0; } @@ -834,7 +833,7 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l) static const int locale_data_size = sizeof(locale_data)/sizeof(QLocaleData) - 1; Q_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<QLocalePrivate>, defaultLocalePrivate, - (QLocalePrivate::create(defaultData(), default_number_options))) + (QLocalePrivate::create(defaultData()))) Q_GLOBAL_STATIC_WITH_ARGS(QExplicitlySharedDataPointer<QLocalePrivate>, systemLocalePrivate, (QLocalePrivate::create(systemData()))) @@ -862,8 +861,9 @@ static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Sc QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions; // If not found, should default to system - if (data->m_language_id == QLocale::C && language != QLocale::C) { - numberOptions = default_number_options; + if (data->m_language_id == QLocale::C) { + if (defaultLocalePrivate.exists()) + numberOptions = defaultLocalePrivate->data()->m_numberOptions; data = defaultData(); } return QLocalePrivate::create(data, offset, numberOptions); @@ -1048,6 +1048,8 @@ uint qHash(const QLocale &key, uint seed) noexcept Sets the \a options related to number conversions for this QLocale instance. + + \sa numberOptions() */ void QLocale::setNumberOptions(NumberOptions options) { @@ -1060,7 +1062,10 @@ void QLocale::setNumberOptions(NumberOptions options) Returns the options related to number conversions for this QLocale instance. - By default, no options are set for the standard locales. + By default, no options are set for the standard locales, except + for the "C" locale, which has OmitGroupSeparator set by default. + + \sa setNumberOptions(), toString(), groupSeparator() */ QLocale::NumberOptions QLocale::numberOptions() const { @@ -1170,12 +1175,9 @@ QString QLocale::createSeparatedList(const QStringList &list) const void QLocale::setDefault(const QLocale &locale) { default_data = locale.d->m_data; - default_number_options = locale.numberOptions(); - if (defaultLocalePrivate.exists()) { - // update the cached private + if (defaultLocalePrivate.exists()) // update the cached private *defaultLocalePrivate = locale.d; - } } /*! @@ -1962,14 +1964,15 @@ double QLocale::toDouble(QStringView s, bool *ok) const /*! Returns a localized string representation of \a i. - \sa toLongLong() + \sa toLongLong(), numberOptions(), zeroDigit(), positiveSign() */ QString QLocale::toString(qlonglong i) const { int flags = d->m_numberOptions & OmitGroupSeparator ? 0 - : QLocaleData::ThousandsGroup; + : (d->m_data->m_country_id == Country::India) + ? QLocaleData::IndianNumberGrouping : QLocaleData::ThousandsGroup; return d->m_data->longLongToString(i, -1, 10, -1, flags); } @@ -1977,14 +1980,15 @@ QString QLocale::toString(qlonglong i) const /*! \overload - \sa toULongLong() + \sa toULongLong(), numberOptions(), zeroDigit(), positiveSign() */ QString QLocale::toString(qulonglong i) const { int flags = d->m_numberOptions & OmitGroupSeparator ? 0 - : QLocaleData::ThousandsGroup; + : (d->m_data->m_country_id == Country::India) + ? QLocaleData::IndianNumberGrouping : QLocaleData::ThousandsGroup; return d->m_data->unsLongLongToString(i, -1, 10, -1, flags); } @@ -2429,7 +2433,7 @@ QTime QLocale::toTime(const QString &string, const QString &format, QCalendar ca QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString, cal); dt.setDefaultLocale(*this); if (dt.parseFormat(format)) - dt.fromString(string, 0, &time); + dt.fromString(string, nullptr, &time); #else Q_UNUSED(cal); Q_UNUSED(string); @@ -2468,7 +2472,7 @@ QDate QLocale::toDate(const QString &string, const QString &format, QCalendar ca QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString, cal); dt.setDefaultLocale(*this); if (dt.parseFormat(format)) - dt.fromString(string, &date, 0); + dt.fromString(string, &date, nullptr); #else Q_UNUSED(string); Q_UNUSED(format); @@ -2523,6 +2527,12 @@ QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCal \since 4.1 Returns the decimal point character of this locale. + + \note This function shall change to return a QString instead of QChar in + Qt6. Callers are encouraged to exploit the QString(QChar) constructor to + convert early in preparation for this. + + \sa groupSeparator(), toString() */ QChar QLocale::decimalPoint() const { @@ -2533,6 +2543,12 @@ QChar QLocale::decimalPoint() const \since 4.1 Returns the group separator character of this locale. + + \note This function shall change to return a QString instead of QChar in + Qt6. Callers are encouraged to exploit the QString(QChar) constructor to + convert early in preparation for this. + + \sa decimalPoint(), toString() */ QChar QLocale::groupSeparator() const { @@ -2543,6 +2559,12 @@ QChar QLocale::groupSeparator() const \since 4.1 Returns the percent character of this locale. + + \note This function shall change to return a QString instead of QChar in + Qt6. Callers are encouraged to exploit the QString(QChar) constructor to + convert early in preparation for this. + + \sa toString() */ QChar QLocale::percent() const { @@ -2553,6 +2575,12 @@ QChar QLocale::percent() const \since 4.1 Returns the zero digit character of this locale. + + \note This function shall change to return a QString instead of QChar in + Qt6. Callers are encouraged to exploit the QString(QChar) constructor to + convert early in preparation for this. + + \sa toString() */ QChar QLocale::zeroDigit() const { @@ -2563,6 +2591,12 @@ QChar QLocale::zeroDigit() const \since 4.1 Returns the negative sign character of this locale. + + \note This function shall change to return a QString instead of QChar in + Qt6. Callers are encouraged to exploit the QString(QChar) constructor to + convert early in preparation for this. + + \sa positiveSign(), toString() */ QChar QLocale::negativeSign() const { @@ -2573,6 +2607,12 @@ QChar QLocale::negativeSign() const \since 4.5 Returns the positive sign character of this locale. + + \note This function shall change to return a QString instead of QChar in + Qt6. Callers are encouraged to exploit the QString(QChar) constructor to + convert early in preparation for this. + + \sa negativeSign(), toString() */ QChar QLocale::positiveSign() const { @@ -2582,7 +2622,14 @@ QChar QLocale::positiveSign() const /*! \since 4.1 - Returns the exponential character of this locale. + Returns the exponential character of this locale, used to separate exponent + from mantissa in some floating-point numeric representations. + + \note This function shall change to return a QString instead of QChar in + Qt6. Callers are encouraged to exploit the QString(QChar) constructor to + convert early in preparation for this. + + \sa toString(double, char, int) */ QChar QLocale::exponential() const { @@ -2607,7 +2654,7 @@ static char qToLower(char c) \a f and \a prec have the same meaning as in QString::number(double, char, int). - \sa toDouble() + \sa toDouble(), numberOptions(), exponential(), decimalPoint(), zeroDigit(), positiveSign(), percent() */ QString QLocale::toString(double i, char f, int prec) const @@ -3065,7 +3112,7 @@ QList<Qt::DayOfWeek> QLocale::weekdays() const if (d->m_data == systemData()) { QVariant res = systemLocale()->query(QSystemLocale::Weekdays, QVariant()); if (!res.isNull()) - return static_cast<QList<Qt::DayOfWeek> >(res.value<QList<Qt::DayOfWeek> >()); + return static_cast<QList<Qt::DayOfWeek> >(qvariant_cast<QList<Qt::DayOfWeek> >(res)); } #endif QList<Qt::DayOfWeek> weekdays; @@ -3626,10 +3673,19 @@ QT_WARNING_DISABLE_MSVC(4146) QT_WARNING_POP uint cnt_thousand_sep = 0; - if (flags & ThousandsGroup && base == 10) { - for (int i = num_str.length() - 3; i > 0; i -= 3) { - num_str.insert(i, group); - ++cnt_thousand_sep; + if (base == 10){ + if (flags & ThousandsGroup) { + for (int i = num_str.length() - 3; i > 0; i -= 3) { + num_str.insert(i, group); + ++cnt_thousand_sep; + } + } else if (flags & IndianNumberGrouping) { + if (num_str.length() > 3) + num_str.insert(num_str.length() - 3 , group); + for (int i = num_str.length() - 6; i > 0; i -= 2) { + num_str.insert(i, group); + ++cnt_thousand_sep; + } } } @@ -3713,10 +3769,19 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group, } uint cnt_thousand_sep = 0; - if (flags & ThousandsGroup && base == 10) { - for (int i = num_str.length() - 3; i > 0; i -=3) { - num_str.insert(i, group); - ++cnt_thousand_sep; + if (base == 10) { + if (flags & ThousandsGroup) { + for (int i = num_str.length() - 3; i > 0; i -=3) { + num_str.insert(i, group); + ++cnt_thousand_sep; + } + } else if (flags & IndianNumberGrouping) { + if (num_str.length() > 3) + num_str.insert(num_str.length() - 3 , group); + for (int i = num_str.length() - 6; i > 0; i -= 2) { + num_str.insert(i, group); + ++cnt_thousand_sep; + } } } @@ -3851,7 +3916,10 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o // check distance from the last separator or from the beginning of the digits // ### FIXME: Some locales allow other groupings! // See https://en.wikipedia.org/wiki/Thousands_separator - if (last_separator_idx != -1 && idx - last_separator_idx != 4) + if (m_country_id == QLocale::India) { + if (last_separator_idx != -1 && idx - last_separator_idx != 3) + return false; + } else if (last_separator_idx != -1 && idx - last_separator_idx != 4) return false; if (last_separator_idx == -1 && (start_of_digits_idx == -1 || idx - start_of_digits_idx > 3)) { diff --git a/src/corelib/text/qlocale.h b/src/corelib/text/qlocale.h index 8b73eb5493..513e0f097b 100644 --- a/src/corelib/text/qlocale.h +++ b/src/corelib/text/qlocale.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -1044,8 +1044,8 @@ public: QDateTime toDateTime(const QString &string, const QString &format, QCalendar cal) const; #endif - // ### Qt 5: We need to return QString from these function since - // unicode data contains several characters for these fields. + // ### Qt 6: We need to return QString from these function since + // UTF-16 may need surrogate pairs to represent these fields. QChar decimalPoint() const; QChar groupSeparator() const; QChar percent() const; diff --git a/src/corelib/text/qlocale.qdoc b/src/corelib/text/qlocale.qdoc index 6c9d6f9d11..592f9d0785 100644 --- a/src/corelib/text/qlocale.qdoc +++ b/src/corelib/text/qlocale.qdoc @@ -174,7 +174,7 @@ \value Chewa Obsolete, please use Nyanja \value Chickasaw Since Qt 5.14 \value Chiga - \value Chinese + \value Chinese (Mandarin) \value Church \value Chuvash \value ClassicalMandaic Since Qt 5.1 @@ -1202,14 +1202,6 @@ */ /*! -\fn QString QLocale::toString(ushort i) const - -\overload - -\sa toUShort() -*/ - -/*! \fn QString QLocale::toString(int i) const \overload diff --git a/src/corelib/text/qlocale_mac.mm b/src/corelib/text/qlocale_mac.mm index 9719278426..31ede1352b 100644 --- a/src/corelib/text/qlocale_mac.mm +++ b/src/corelib/text/qlocale_mac.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -67,16 +67,16 @@ static QByteArray envVarLocale() return lang; } -static QByteArray getMacLocaleName() +static QString getMacLocaleName() { - QByteArray result = envVarLocale(); + QString result = QString::fromLocal8Bit(envVarLocale()); QString lang, script, cntry; if (result.isEmpty() - || (result != "C" && !qt_splitLocaleName(QString::fromLocal8Bit(result), lang, script, cntry))) { + || (result != QLatin1String("C") && !qt_splitLocaleName(result, lang, script, cntry))) { QCFType<CFLocaleRef> l = CFLocaleCopyCurrent(); CFStringRef locale = CFLocaleGetIdentifier(l); - result = QString::fromCFString(locale).toUtf8(); + result = QString::fromCFString(locale); } return result; } @@ -402,10 +402,10 @@ static QVariant macQuoteString(QSystemLocale::QueryType type, const QStringRef & QLocale QSystemLocale::fallbackUiLocale() const { - return QLocale(QString::fromUtf8(getMacLocaleName().constData())); + return QLocale(getMacLocaleName()); } -QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const +QVariant QSystemLocale::query(QueryType type, QVariant in) const { QMacAutoReleasePool pool; switch(type) { diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index edee3a89c7..bb24009523 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -213,7 +213,8 @@ public: ShowBase = 0x80, UppercaseBase = 0x100, ZeroPadExponent = 0x200, - ForcePoint = 0x400 + ForcePoint = 0x400, + IndianNumberGrouping= 0x800 }; enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode }; diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp index c246028b4d..0da769d694 100644 --- a/src/corelib/text/qlocale_tools.cpp +++ b/src/corelib/text/qlocale_tools.cpp @@ -322,7 +322,7 @@ double qt_asciiToDouble(const char *num, int numLen, bool &ok, int &processed, conv_flags = double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES | double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES; } - double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_qnan(), 0, 0); + double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_qnan(), nullptr, nullptr); d = conv.StringToDouble(num, numLen, &processed); if (!qIsFinite(d)) { diff --git a/src/corelib/text/qlocale_unix.cpp b/src/corelib/text/qlocale_unix.cpp index ff4274d932..5e1e47eae7 100644 --- a/src/corelib/text/qlocale_unix.cpp +++ b/src/corelib/text/qlocale_unix.cpp @@ -283,9 +283,9 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const return d->uiLanguages.isEmpty() ? QVariant() : QVariant(d->uiLanguages); } case StringToStandardQuotation: - return lc_messages.quoteString(in.value<QStringRef>()); + return lc_messages.quoteString(qvariant_cast<QStringRef>(in)); case StringToAlternateQuotation: - return lc_messages.quoteString(in.value<QStringRef>(), QLocale::AlternateQuotation); + return lc_messages.quoteString(qvariant_cast<QStringRef>(in), QLocale::AlternateQuotation); case ListToSeparatedString: return lc_messages.createSeparatedList(in.toStringList()); case LocaleChanged: diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp index 79ea67f966..4b4152c519 100644 --- a/src/corelib/text/qlocale_win.cpp +++ b/src/corelib/text/qlocale_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -106,11 +106,11 @@ struct QSystemLocalePrivate { QSystemLocalePrivate(); - QChar zeroDigit(); - QChar decimalPoint(); - QChar groupSeparator(); - QChar negativeSign(); - QChar positiveSign(); + QString zeroDigit(); + QString decimalPoint(); + QString groupSeparator(); + QString negativeSign(); + QString positiveSign(); QVariant dateFormat(QLocale::FormatType); QVariant timeFormat(QLocale::FormatType); QVariant dateTimeFormat(QLocale::FormatType); @@ -147,12 +147,11 @@ private: WCHAR lcName[LOCALE_NAME_MAX_LENGTH]; #endif SubstitutionType substitutionType; - QChar zero; + QString zero; // cached value for zeroDigit() int getLocaleInfo(LCTYPE type, LPWSTR data, int size); QString getLocaleInfo(LCTYPE type, int maxlen = 0); int getLocaleInfo_int(LCTYPE type, int maxlen = 0); - QChar getLocaleInfo_qchar(LCTYPE type); int getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size); int getDateFormat(DWORD flags, const SYSTEMTIME * date, LPCWSTR format, LPWSTR data, int size); @@ -236,12 +235,6 @@ int QSystemLocalePrivate::getLocaleInfo_int(LCTYPE type, int maxlen) return ok ? v : 0; } -QChar QSystemLocalePrivate::getLocaleInfo_qchar(LCTYPE type) -{ - QString str = getLocaleInfo(type); - return str.isEmpty() ? QChar() : str.at(0); -} - QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution() { if (substitutionType == SUnknown) { @@ -257,13 +250,12 @@ QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution() else if (buf[0] == '2') substitutionType = QSystemLocalePrivate::SAlways; else { - wchar_t digits[11]; + wchar_t digits[11]; // See zeroDigit() for why 11. if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) { substitutionType = QSystemLocalePrivate::SNever; return substitutionType; } - const wchar_t zero = digits[0]; - if (buf[0] == zero + 2) + if (buf[0] == digits[0] + 2) substitutionType = QSystemLocalePrivate::SAlways; else substitutionType = QSystemLocalePrivate::SNever; @@ -274,40 +266,75 @@ QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution() QString &QSystemLocalePrivate::substituteDigits(QString &string) { - ushort zero = zeroDigit().unicode(); - ushort *qch = reinterpret_cast<ushort *>(string.data()); - for (ushort *end = qch + string.size(); qch != end; ++qch) { - if (*qch >= '0' && *qch <= '9') - *qch = zero + (*qch - '0'); + zeroDigit(); // Ensure zero is set. + switch (zero.size()) { + case 1: { + const ushort offset = zero.at(0).unicode() - '0'; + if (!offset) // Nothing to do + break; + Q_ASSERT(offset > 9); + ushort *const qch = reinterpret_cast<ushort *>(string.data()); + for (int i = 0, stop = string.size(); i < stop; ++i) { + ushort &ch = qch[i]; + if (ch >= '0' && ch <= '9') + ch += offset; + } + break; + } + case 2: { + // Surrogate pair (high, low): + uint digit = QChar::surrogateToUcs4(zero.at(0), zero.at(1)); + for (int i = 0; i < 10; i++) { + const QChar s[2] = { QChar::highSurrogate(digit + i), QChar::lowSurrogate(digit + i) }; + string.replace(QString(QLatin1Char('0' + i)), QString(s, 2)); + } + break; + } + default: + Q_ASSERT(!"Expected zero digit to be a single UCS2 code-point or a surrogate pair"); + case 0: // Apparently this locale info was not available. + break; } return string; } -QChar QSystemLocalePrivate::zeroDigit() +QString QSystemLocalePrivate::zeroDigit() { - if (zero.isNull()) - zero = getLocaleInfo_qchar(LOCALE_SNATIVEDIGITS); + if (zero.isEmpty()) { + /* Ten digits plus a terminator. + + https://docs.microsoft.com/en-us/windows/win32/intl/locale-snative-constants + "Native equivalents of ASCII 0 through 9. The maximum number of + characters allowed for this string is eleven, including a terminating + null character." + */ + wchar_t digits[11]; + if (getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) { + // assert all(digits[i] == i + digits[0] for i in range(1, 10)), assumed above + zero = QString::fromWCharArray(digits, 1); + } + } return zero; } -QChar QSystemLocalePrivate::decimalPoint() +QString QSystemLocalePrivate::decimalPoint() { - return getLocaleInfo_qchar(LOCALE_SDECIMAL); + return getLocaleInfo(LOCALE_SDECIMAL); } -QChar QSystemLocalePrivate::groupSeparator() +QString QSystemLocalePrivate::groupSeparator() { - return getLocaleInfo_qchar(LOCALE_STHOUSAND); + return getLocaleInfo(LOCALE_STHOUSAND); } -QChar QSystemLocalePrivate::negativeSign() +QString QSystemLocalePrivate::negativeSign() { - return getLocaleInfo_qchar(LOCALE_SNEGATIVESIGN); + return getLocaleInfo(LOCALE_SNEGATIVESIGN); } -QChar QSystemLocalePrivate::positiveSign() +QString QSystemLocalePrivate::positiveSign() { - return getLocaleInfo_qchar(LOCALE_SPOSITIVESIGN); + return getLocaleInfo(LOCALE_SPOSITIVESIGN); } QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type) @@ -677,7 +704,7 @@ void QSystemLocalePrivate::update() GetUserDefaultLocaleName(lcName, LOCALE_NAME_MAX_LENGTH); #endif substitutionType = SUnknown; - zero = QChar(); + zero.resize(0); } QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt) @@ -749,7 +776,7 @@ QLocale QSystemLocale::fallbackUiLocale() const return QLocale(QString::fromLatin1(getWinLocaleName())); } -QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const +QVariant QSystemLocale::query(QueryType type, QVariant in) const { QSystemLocalePrivate *d = systemLocalePrivate(); switch(type) { diff --git a/src/corelib/text/qregexp.cpp b/src/corelib/text/qregexp.cpp index ac4d9bbc36..9301a7e573 100644 --- a/src/corelib/text/qregexp.cpp +++ b/src/corelib/text/qregexp.cpp @@ -2528,7 +2528,7 @@ void QRegExpEngine::Box::cat(const Box &b) eng->addCatTransitions(rs, b.ls); addAnchorsToEngine(b); if (minl == 0) { - lanchors.unite(b.lanchors); + lanchors.insert(b.lanchors); if (skipanchors != 0) { for (int i = 0; i < b.ls.size(); i++) { int a = eng->anchorConcatenation(lanchors.value(b.ls.at(i), 0), skipanchors); @@ -2538,7 +2538,7 @@ void QRegExpEngine::Box::cat(const Box &b) mergeInto(&ls, b.ls); } if (b.minl == 0) { - ranchors.unite(b.ranchors); + ranchors.insert(b.ranchors); if (b.skipanchors != 0) { for (int i = 0; i < rs.size(); i++) { int a = eng->anchorConcatenation(ranchors.value(rs.at(i), 0), b.skipanchors); @@ -2596,9 +2596,9 @@ void QRegExpEngine::Box::cat(const Box &b) void QRegExpEngine::Box::orx(const Box &b) { mergeInto(&ls, b.ls); - lanchors.unite(b.lanchors); + lanchors.insert(b.lanchors); mergeInto(&rs, b.rs); - ranchors.unite(b.ranchors); + ranchors.insert(b.ranchors); if (b.minl == 0) { if (minl == 0) diff --git a/src/corelib/text/qregularexpression.cpp b/src/corelib/text/qregularexpression.cpp index 8d2187eb28..d74b759aa9 100644 --- a/src/corelib/text/qregularexpression.cpp +++ b/src/corelib/text/qregularexpression.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 Giuseppe D'Angelo <dangelog@gmail.com>. -** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +** Copyright (C) 2020 Giuseppe D'Angelo <dangelog@gmail.com>. +** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** @@ -443,6 +443,38 @@ QT_BEGIN_NAMESPACE Other differences are outlined below. + \section2 Different pattern syntax + + Porting a regular expression from QRegExp to QRegularExpression may require + changes to the pattern itself. + + In certain scenarios, QRegExp was too lenient and accepted patterns that + are simply invalid when using QRegularExpression. These are somehow easy + to detect, because the QRegularExpression objects built with these patterns + are not valid (cf. isValid()). + + In other cases, a pattern ported from QRegExp to QRegularExpression may + silently change semantics. Therefore, it is necessary to review the + patterns used. The most notable cases of silent incompatibility are: + + \list + + \li Curly braces are needed in order to use a hexadecimal escape like + \c{\xHHHH} with more than 2 digits. A pattern like \c{\x2022} neeeds to + be ported to \c{\x{2022}}, or it will match a space (\c{0x20}) followed + by the string \c{"22"}. In general, it is highly recommended to always use + curly braces with the \c{\x} escape, no matter the amount of digits + specified. + + \li A 0-to-n quantification like \c{{,n}} needs to be ported to \c{{0,n}} to + preserve semantics. Otherwise, a pattern such as \c{\d{,3}} would + actually match a digit followed by the exact string \c{"{,3}"}. + + \li QRegExp by default does Unicode-aware matching, while + QRegularExpression requires a separate option; see below for more details. + + \endlist + \section2 Porting from QRegExp::exactMatch() QRegExp::exactMatch() in Qt 4 served two purposes: it exactly matched @@ -831,7 +863,7 @@ struct QRegularExpressionPrivate : QSharedData QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString, - const QRegularExpressionMatchPrivate *previous = 0) const; + const QRegularExpressionMatchPrivate *previous = nullptr) const; int captureIndexForName(QStringView name) const; @@ -912,7 +944,7 @@ QRegularExpression::QRegularExpression(QRegularExpressionPrivate &dd) */ QRegularExpressionPrivate::QRegularExpressionPrivate() : QSharedData(), - patternOptions(0), + patternOptions(), pattern(), mutex(), compiledPattern(nullptr), @@ -990,7 +1022,7 @@ void QRegularExpressionPrivate::compilePattern() options, &errorCode, &patternErrorOffset, - NULL); + nullptr); if (!compiledPattern) { errorOffset = static_cast<int>(patternErrorOffset); @@ -1049,7 +1081,7 @@ public: { // The default JIT stack size in PCRE is 32K, // we allocate from 32K up to 512K. - stack = pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL); + stack = pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, nullptr); } /*! \internal @@ -1073,7 +1105,7 @@ static pcre2_jit_stack_16 *qtPcreCallback(void *) if (jitStacks()->hasLocalData()) return jitStacks()->localData()->stack; - return 0; + return nullptr; } /*! @@ -1240,9 +1272,9 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString previousMatchWasEmpty = true; } - pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(NULL); - pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, NULL); - pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, NULL); + pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(nullptr); + pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, nullptr); + pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, nullptr); const unsigned short * const subjectUtf16 = subject.utf16() + subjectStart; @@ -1797,7 +1829,19 @@ uint qHash(const QRegularExpression &key, uint seed) noexcept return seed; } +#if QT_STRINGVIEW_LEVEL < 2 +/*! + \overload +*/ +QString QRegularExpression::escape(const QString &str) +{ + return escape(QStringView(str)); +} +#endif // QT_STRINGVIEW_LEVEL < 2 + /*! + \since 5.15 + Escapes all characters of \a str so that they no longer have any special meaning when used as a regular expression pattern string, and returns the escaped string. For instance: @@ -1815,7 +1859,7 @@ uint qHash(const QRegularExpression &key, uint seed) noexcept inside \a str is escaped with the sequence \c{"\\0"} (backslash + \c{'0'}), instead of \c{"\\\0"} (backslash + \c{NUL}). */ -QString QRegularExpression::escape(const QString &str) +QString QRegularExpression::escape(QStringView str) { QString result; const int count = str.size(); @@ -1850,8 +1894,19 @@ QString QRegularExpression::escape(const QString &str) return result; } +#if QT_STRINGVIEW_LEVEL < 2 /*! \since 5.12 + \overload +*/ +QString QRegularExpression::wildcardToRegularExpression(const QString &pattern) +{ + return wildcardToRegularExpression(QStringView(pattern)); +} +#endif // QT_STRINGVIEW_LEVEL < 2 + +/*! + \since 5.15 Returns a regular expression representation of the given glob \a pattern. The transformation is targeting file path globbing, which means in particular @@ -1860,6 +1915,10 @@ QString QRegularExpression::escape(const QString &str) \snippet code/src_corelib_tools_qregularexpression.cpp 31 + The returned regular expression is already fully anchored. In other + words, there is no need of calling anchoredPattern() again on the + result. + \warning Unlike QRegExp, this implementation follows closely the definition of wildcard for glob patterns: \table @@ -1886,23 +1945,23 @@ QString QRegularExpression::escape(const QString &str) \note The backslash (\\) character is \e not an escape char in this context. In order to match one of the special characters, place it in square brackets - (for example, "[?]"). + (for example, \c{[?]}). More information about the implementation can be found in: \list \li \l {https://en.wikipedia.org/wiki/Glob_(programming)} {The Wikipedia Glob article} - \li \c man 7 glob + \li \c {man 7 glob} \endlist \sa escape() */ -QString QRegularExpression::wildcardToRegularExpression(const QString &pattern) +QString QRegularExpression::wildcardToRegularExpression(QStringView pattern) { const int wclen = pattern.length(); QString rx; rx.reserve(wclen + wclen / 16); int i = 0; - const QChar *wc = pattern.unicode(); + const QChar *wc = pattern.data(); #ifdef Q_OS_WIN const QLatin1Char nativePathSeparator('\\'); @@ -1974,16 +2033,31 @@ QString QRegularExpression::wildcardToRegularExpression(const QString &pattern) return anchoredPattern(rx); } +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn QRegularExpression::anchoredPattern(const QString &expression) \since 5.12 + \overload +*/ +#endif // QT_STRINGVIEW_LEVEL < 2 + +/*! + \since 5.15 + Returns the \a expression wrapped between the \c{\A} and \c{\z} anchors to be used for exact matching. \sa {Porting from QRegExp's Exact Matching} */ +QString QRegularExpression::anchoredPattern(QStringView expression) +{ + return QString() + + QLatin1String("\\A(?:") + + expression + + QLatin1String(")\\z"); +} /*! \since 5.1 @@ -2835,7 +2909,7 @@ static const char *pcreCompileErrorCodes[] = QT_TRANSLATE_NOOP("QRegularExpression", "numbers out of order in {} quantifier"), QT_TRANSLATE_NOOP("QRegularExpression", "number too big in {} quantifier"), QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"), - QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in character class"), + QT_TRANSLATE_NOOP("QRegularExpression", "escape sequence is invalid in character class"), QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"), QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"), QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"), @@ -2852,46 +2926,46 @@ static const char *pcreCompileErrorCodes[] = QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"), QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"), QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"), - QT_TRANSLATE_NOOP("QRegularExpression", "letter or underscore expected after (?< or (?'"), + QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis for condition"), QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"), - QT_TRANSLATE_NOOP("QRegularExpression", "malformed number or name after (?("), - QT_TRANSLATE_NOOP("QRegularExpression", "conditional group contains more than two branches"), + QT_TRANSLATE_NOOP("QRegularExpression", "a relative value of zero is not allowed"), + QT_TRANSLATE_NOOP("QRegularExpression", "conditional subpattern contains more than two branches"), QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"), - QT_TRANSLATE_NOOP("QRegularExpression", "(?R or (?[+-]digits must be followed by )"), + QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+ or (?-"), QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"), QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"), QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"), QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"), QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"), - QT_TRANSLATE_NOOP("QRegularExpression", "invalid condition (?(0)"), - QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion"), - QT_TRANSLATE_NOOP("QRegularExpression", "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u"), + QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind is too complicated"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion in UTF-" "16" " mode"), + QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u"), QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"), QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"), QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"), QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"), - QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator)"), + QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator?)"), QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"), - QT_TRANSLATE_NOOP("QRegularExpression", "group name must start with a non-digit"), + QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name must start with a non-digit"), QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"), QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"), QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"), - QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "10000" " characters)"), - QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "256" ")"), + QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "32" " code units)"), + QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "10000" ")"), QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"), QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"), QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"), QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"), - QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE group contains more than one branch"), + QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE subpattern contains more than one branch"), QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"), QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"), QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"), - QT_TRANSLATE_NOOP("QRegularExpression", "a numbered reference must not be zero"), - QT_TRANSLATE_NOOP("QRegularExpression", "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)"), + QT_TRANSLATE_NOOP("QRegularExpression", "(?R (recursive pattern call) must be followed by a closing parenthesis"), + QT_TRANSLATE_NOOP("QRegularExpression", "obsolete error (should not occur)"), QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"), - QT_TRANSLATE_NOOP("QRegularExpression", "number is too big"), + QT_TRANSLATE_NOOP("QRegularExpression", "subpattern number is too big"), QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"), - QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: parsed pattern overflow"), QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"), QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"), QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"), @@ -2899,16 +2973,16 @@ static const char *pcreCompileErrorCodes[] = QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"), QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"), QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"), - QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in find_fixedlength()"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown meta code in check_lookbehinds()"), QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"), - QT_TRANSLATE_NOOP("QRegularExpression", "SPARE ERROR"), + QT_TRANSLATE_NOOP("QRegularExpression", "callout string is too long"), QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"), QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"), QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"), QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"), QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"), - QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{}"), - QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in (?(VERSION condition"), + QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{} or \\N{U+}"), + QT_TRANSLATE_NOOP("QRegularExpression", "syntax error or number too big in (?(VERSION condition"), QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"), QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"), QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"), @@ -2918,6 +2992,16 @@ static const char *pcreCompileErrorCodes[] = QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"), QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"), QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown code in parsed pattern"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: bad code value in parsed_skip()"), + QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode"), + QT_TRANSLATE_NOOP("QRegularExpression", "invalid option bits with PCRE2_LITERAL"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\N{U+dddd} is supported only in Unicode (UTF) mode"), + QT_TRANSLATE_NOOP("QRegularExpression", "invalid hyphen in option setting"), + QT_TRANSLATE_NOOP("QRegularExpression", "(*alpha_assertion) not recognized"), + QT_TRANSLATE_NOOP("QRegularExpression", "script runs require Unicode support, which this version of PCRE2 does not have"), + QT_TRANSLATE_NOOP("QRegularExpression", "too many capturing groups (maximum 65535)"), + QT_TRANSLATE_NOOP("QRegularExpression", "atomic assertion expected after (?( or (?(?C)"), QT_TRANSLATE_NOOP("QRegularExpression", "no error"), QT_TRANSLATE_NOOP("QRegularExpression", "no match"), QT_TRANSLATE_NOOP("QRegularExpression", "partial match"), @@ -2955,7 +3039,7 @@ static const char *pcreCompileErrorCodes[] = QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"), QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"), QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"), - QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"), /* Never returned by PCRE2 itself */ + QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"), QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"), QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"), QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"), @@ -2971,15 +3055,20 @@ static const char *pcreCompileErrorCodes[] = QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"), QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"), QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"), - QT_TRANSLATE_NOOP("QRegularExpression", "recursion limit exceeded"), + QT_TRANSLATE_NOOP("QRegularExpression", "matching depth limit exceeded"), QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"), QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"), QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"), QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"), QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"), QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"), - QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start is not supported"), - QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)") + QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start or start moved backwards is not supported"), + QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)"), + QT_TRANSLATE_NOOP("QRegularExpression", "bad serialized data"), + QT_TRANSLATE_NOOP("QRegularExpression", "heap limit exceeded"), + QT_TRANSLATE_NOOP("QRegularExpression", "invalid syntax"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error - duplicate substitution match"), + QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching") }; #endif // #if 0 diff --git a/src/corelib/text/qregularexpression.h b/src/corelib/text/qregularexpression.h index f799a38ae4..4fa258b080 100644 --- a/src/corelib/text/qregularexpression.h +++ b/src/corelib/text/qregularexpression.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>. -** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +** Copyright (C) 2020 Giuseppe D'Angelo <dangelog@gmail.com>. +** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -42,9 +42,8 @@ #define QREGULAREXPRESSION_H #include <QtCore/qglobal.h> - #include <QtCore/qstring.h> -#include <QtCore/qstringlist.h> +#include <QtCore/qstringview.h> #include <QtCore/qshareddata.h> #include <QtCore/qvariant.h> @@ -52,7 +51,8 @@ QT_REQUIRE_CONFIG(regularexpression); QT_BEGIN_NAMESPACE -class QStringView; +class QStringList; +class QLatin1String; class QRegularExpressionMatch; class QRegularExpressionMatchIterator; @@ -137,14 +137,18 @@ public: void optimize() const; +#if QT_STRINGVIEW_LEVEL < 2 static QString escape(const QString &str); static QString wildcardToRegularExpression(const QString &str); static inline QString anchoredPattern(const QString &expression) { - return QLatin1String("\\A(?:") - + expression - + QLatin1String(")\\z"); + return anchoredPattern(QStringView(expression)); } +#endif + + static QString escape(QStringView str); + static QString wildcardToRegularExpression(QStringView str); + static QString anchoredPattern(QStringView expression); bool operator==(const QRegularExpression &re) const; inline bool operator!=(const QRegularExpression &re) const { return !operator==(re); } diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index dcdc87181e..877f5df462 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -100,7 +100,7 @@ #define ULLONG_MAX quint64_C(18446744073709551615) #endif -#define IS_RAW_DATA(d) ((d)->offset != sizeof(QStringData)) +#define IS_RAW_DATA(d) ((d.d)->flags & QArrayData::RawDataType) QT_BEGIN_NAMESPACE @@ -146,6 +146,9 @@ qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringVie static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept; template <typename Haystack> static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept; +template <> +inline qsizetype qLastIndexOf(QString haystack, QChar needle, + qsizetype from, Qt::CaseSensitivity cs) noexcept = delete; // unwanted, would detach static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs); static inline qsizetype qt_string_count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs); @@ -160,7 +163,7 @@ qsizetype QtPrivate::qustrlen(const ushort *str) noexcept { qsizetype result = 0; -#ifdef __SSE2__ +#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || QT_HAS_FEATURE(address_sanitizer)) // find the 16-byte alignment immediately prior or equal to str quintptr misalignment = quintptr(str) & 0xf; Q_ASSERT((misalignment & 1) == 0); @@ -588,6 +591,20 @@ bool QtPrivate::isLatin1(QStringView s) noexcept return true; } +bool QtPrivate::isValidUtf16(QStringView s) noexcept +{ + Q_CONSTEXPR uint InvalidCodePoint = UINT_MAX; + + QStringIterator i(s); + while (i.hasNext()) { + uint c = i.next(InvalidCodePoint); + if (c == InvalidCodePoint) + return false; + } + + return true; +} + // conversion between Latin 1 and UTF-16 void qt_from_latin1(ushort *dst, const char *str, size_t size) noexcept { @@ -912,7 +929,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) }; // we're going to read a[0..15] and b[0..15] (32 bytes) - for ( ; a + offset + 16 <= end; offset += 16) { + for ( ; end - a >= offset + 16; offset += 16) { #ifdef __AVX2__ __m256i a_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(a + offset)); __m256i b_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(b + offset)); @@ -936,7 +953,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) } // we're going to read a[0..7] and b[0..7] (16 bytes) - if (a + offset + 8 <= end) { + if (end - a >= offset + 8) { __m128i a_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset)); __m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset)); if (isDifferent(a_data, b_data)) @@ -946,7 +963,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) } // we're going to read a[0..3] and b[0..3] (8 bytes) - if (a + offset + 4 <= end) { + if (end - a >= offset + 4) { __m128i a_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(a + offset)); __m128i b_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(b + offset)); if (isDifferent(a_data, b_data)) @@ -967,7 +984,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) if (l >= 8) { const QChar *end = a + l; const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; - while (a + 7 < end) { + while (end - a > 7) { uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a)); uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b)); @@ -1360,28 +1377,6 @@ const QString::Null QString::null = { }; */ /*! - \class QCharRef - \inmodule QtCore - \reentrant - \brief The QCharRef class is a helper class for QString. - - \internal - - \ingroup string-processing - - When you get an object of type QCharRef, if you can assign to it, - the assignment will apply to the character in the string from - which you got the reference. That is its whole purpose in life. - The QCharRef becomes invalid once modifications are made to the - string: if you want to keep the character, copy it into a QChar. - - Most of the QChar member functions also exist in QCharRef. - However, they are not explicitly documented here. - - \sa QString::operator[](), QString::at(), QChar -*/ - -/*! \class QString \inmodule QtCore \reentrant @@ -2100,8 +2095,8 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out) */ QString::QString(const QChar *unicode, int size) { - if (!unicode) { - d = Data::sharedNull(); + if (!unicode) { + d.clear(); } else { if (size < 0) { size = 0; @@ -2109,13 +2104,11 @@ QString::QString(const QChar *unicode, int size) ++size; } if (!size) { - d = Data::allocate(0); + d = DataPointer(Data::allocate(0), 0); } else { - d = Data::allocate(size + 1); - Q_CHECK_PTR(d); - d->size = size; - memcpy(d->data(), unicode, size * sizeof(QChar)); - d->data()[size] = '\0'; + d = DataPointer(Data::allocate(size + 1), size); + memcpy(d.data(), unicode, size * sizeof(QChar)); + d.data()[size] = '\0'; } } } @@ -2128,15 +2121,13 @@ QString::QString(const QChar *unicode, int size) */ QString::QString(int size, QChar ch) { - if (size <= 0) { - d = Data::allocate(0); + if (size <= 0) { + d = DataPointer(Data::allocate(0), 0); } else { - d = Data::allocate(size + 1); - Q_CHECK_PTR(d); - d->size = size; - d->data()[size] = '\0'; - ushort *i = d->data() + size; - ushort *b = d->data(); + d = DataPointer(Data::allocate(size + 1), size); + d.data()[size] = '\0'; + ushort *i = d.data() + size; + ushort *b = d.data(); const ushort value = ch.unicode(); while (i != b) *--i = value; @@ -2151,10 +2142,8 @@ QString::QString(int size, QChar ch) */ QString::QString(int size, Qt::Initialization) { - d = Data::allocate(size + 1); - Q_CHECK_PTR(d); - d->size = size; - d->data()[size] = '\0'; + d = DataPointer(Data::allocate(size + 1), size); + d.data()[size] = '\0'; } /*! \fn QString::QString(QLatin1String str) @@ -2169,11 +2158,9 @@ QString::QString(int size, Qt::Initialization) */ QString::QString(QChar ch) { - d = Data::allocate(2); - Q_CHECK_PTR(d); - d->size = 1; - d->data()[0] = ch.unicode(); - d->data()[1] = '\0'; + d = DataPointer(Data::allocate(2), 1); + d.data()[0] = ch.unicode(); + d.data()[1] = '\0'; } /*! \fn QString::QString(const QByteArray &ba) @@ -2195,7 +2182,7 @@ QString::QString(QChar ch) \internal */ -/*! \fn QString::QString(QStringDataPtr) +/*! \fn QString::QString(QStringPrivate) \internal */ @@ -2265,16 +2252,16 @@ void QString::resize(int size) if (size < 0) size = 0; - if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) { - d->size = size; + if (!d->isShared() && !d->isMutable() && size < int(d.size)) { + d.size = size; return; } - if (d->ref.isShared() || uint(size) + 1u > d->alloc) + if (d->needsDetach() || size > capacity()) reallocData(uint(size) + 1u, true); - if (d->alloc) { - d->size = size; - d->data()[size] = '\0'; + d.size = size; + if (d->isMutable()) { + d.data()[size] = '\0'; } } @@ -2294,7 +2281,7 @@ void QString::resize(int size, QChar fillChar) resize(size); const int difference = length() - oldSize; if (difference > 0) - std::fill_n(d->begin() + oldSize, difference, fillChar.unicode()); + std::fill_n(d.data() + oldSize, difference, fillChar.unicode()); } /*! \fn int QString::capacity() const @@ -2351,28 +2338,22 @@ void QString::reallocData(uint alloc, bool grow) { auto allocOptions = d->detachFlags(); if (grow) - allocOptions |= QArrayData::Grow; - - if (d->ref.isShared() || IS_RAW_DATA(d)) { - Data *x = Data::allocate(alloc, allocOptions); - Q_CHECK_PTR(x); - x->size = qMin(int(alloc) - 1, d->size); - ::memcpy(x->data(), d->data(), x->size * sizeof(QChar)); - x->data()[x->size] = 0; - if (!d->ref.deref()) - Data::deallocate(d); - d = x; + allocOptions |= QArrayData::GrowsForward; + + if (d->needsDetach()) { + DataPointer dd(Data::allocate(alloc, allocOptions), qMin(int(alloc) - 1, d.size)); + ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar)); + dd.data()[dd.size] = 0; + d = dd; } else { - Data *p = Data::reallocateUnaligned(d, alloc, allocOptions); - Q_CHECK_PTR(p); - d = p; + d.reallocate(alloc, allocOptions); } } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void QString::expand(int i) { - resize(qMax(i + 1, d->size), QLatin1Char(' ')); + resize(qMax(i + 1, size()), QLatin1Char(' ')); } #endif @@ -2391,9 +2372,6 @@ void QString::expand(int i) QString &QString::operator=(const QString &other) noexcept { - other.d->ref.ref(); - if (!d->ref.deref()) - Data::deallocate(d); d = other.d; return *this; } @@ -2415,9 +2393,9 @@ QString &QString::operator=(const QString &other) noexcept QString &QString::operator=(QLatin1String other) { if (isDetached() && other.size() <= capacity()) { // assumes d->alloc == 0 -> !isDetached() (sharedNull) - d->size = other.size(); - d->data()[other.size()] = 0; - qt_from_latin1(d->data(), other.latin1(), other.size()); + d.size = other.size(); + d.data()[other.size()] = 0; + qt_from_latin1(d.data(), other.latin1(), other.size()); } else { *this = fromLatin1(other.latin1(), other.size()); } @@ -2480,10 +2458,9 @@ QString &QString::operator=(QChar ch) { if (isDetached() && capacity() >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull) // re-use existing capacity: - ushort *dat = d->data(); - dat[0] = ch.unicode(); - dat[1] = 0; - d->size = 1; + d.data()[0] = ch.unicode(); + d.data()[1] = 0; + d.size = 1; } else { operator=(QString(ch)); } @@ -2569,13 +2546,13 @@ QString &QString::insert(int i, QLatin1String str) return *this; int len = str.size(); - if (Q_UNLIKELY(i > d->size)) + if (Q_UNLIKELY(i > size())) resize(i + len, QLatin1Char(' ')); else - resize(d->size + len); + resize(size() + len); - ::memmove(d->data() + i + len, d->data() + i, (d->size - i - len) * sizeof(QChar)); - qt_from_latin1(d->data() + i, s, uint(len)); + ::memmove(d.data() + i + len, d.data() + i, (d.size - i - len) * sizeof(QChar)); + qt_from_latin1(d.data() + i, s, uint(len)); return *this; } @@ -2592,7 +2569,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.size) { // Part of me - take a copy ushort *tmp = static_cast<ushort *>(::malloc(size * sizeof(QChar))); Q_CHECK_PTR(tmp); @@ -2602,13 +2579,13 @@ QString& QString::insert(int i, const QChar *unicode, int size) return *this; } - if (Q_UNLIKELY(i > d->size)) + if (Q_UNLIKELY(i > int(d.size))) resize(i + size, QLatin1Char(' ')); else - resize(d->size + size); + resize(d.size + size); - ::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; } @@ -2622,15 +2599,15 @@ QString& QString::insert(int i, const QChar *unicode, int size) QString& QString::insert(int i, QChar ch) { if (i < 0) - i += d->size; + i += d.size; if (i < 0) return *this; - if (Q_UNLIKELY(i > d->size)) + if (Q_UNLIKELY(i > size())) resize(i + 1, QLatin1Char(' ')); else - resize(d->size + 1); - ::memmove(d->data() + i + 1, d->data() + i, (d->size - i - 1) * sizeof(QChar)); - d->data()[i] = ch.unicode(); + resize(d.size + 1); + ::memmove(d.data() + i + 1, d.data() + i, (d.size - i - 1) * sizeof(QChar)); + d.data()[i] = ch.unicode(); return *this; } @@ -2654,15 +2631,15 @@ QString& QString::insert(int i, QChar ch) */ QString &QString::append(const QString &str) { - if (str.d != Data::sharedNull()) { - if (d == Data::sharedNull()) { + if (!str.isNull()) { + if (isNull()) { operator=(str); } else { - if (d->ref.isShared() || uint(d->size + str.d->size) + 1u > d->alloc) - reallocData(uint(d->size + str.d->size) + 1u, true); - memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); - d->size += str.d->size; - d->data()[d->size] = '\0'; + if (d->needsDetach() || size() + str.size() > capacity()) + reallocData(uint(size() + str.size()) + 1u, true); + memcpy(d.data() + d.size, str.d.data(), str.d.size * sizeof(QChar)); + d.size += str.d.size; + d.data()[d.size] = '\0'; } } return *this; @@ -2677,11 +2654,11 @@ QString &QString::append(const QString &str) QString &QString::append(const QChar *str, int len) { if (str && len > 0) { - if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc) - reallocData(uint(d->size + len) + 1u, true); - memcpy(d->data() + d->size, str, len * sizeof(QChar)); - d->size += len; - d->data()[d->size] = '\0'; + if (d->needsDetach() || size() + len > capacity()) + reallocData(uint(size() + len) + 1u, true); + memcpy(d.data() + d.size, str, len * sizeof(QChar)); + d.size += len; + d.data()[d.size] = '\0'; } return *this; } @@ -2696,12 +2673,12 @@ QString &QString::append(QLatin1String str) const char *s = str.latin1(); if (s) { int len = str.size(); - if (d->ref.isShared() || uint(d->size + len) + 1u > d->alloc) - reallocData(uint(d->size + len) + 1u, true); - ushort *i = d->data() + d->size; + if (d->needsDetach() || size() + len > capacity()) + reallocData(uint(size() + len) + 1u, true); + ushort *i = d.data() + d.size; qt_from_latin1(i, s, uint(len)); i[len] = '\0'; - d->size += len; + d.size += len; } return *this; } @@ -2743,10 +2720,10 @@ QString &QString::append(QLatin1String str) */ QString &QString::append(QChar ch) { - if (d->ref.isShared() || uint(d->size) + 2u > d->alloc) - reallocData(uint(d->size) + 2u, true); - d->data()[d->size++] = ch.unicode(); - d->data()[d->size] = '\0'; + if (d->needsDetach() || size() + 1 > capacity()) + reallocData(uint(d.size) + 2u, true); + d.data()[d.size++] = ch.unicode(); + d.data()[d.size] = '\0'; return *this; } @@ -2839,16 +2816,16 @@ QString &QString::append(QChar ch) QString &QString::remove(int pos, int len) { if (pos < 0) // count from end of string - pos += d->size; - if (uint(pos) >= uint(d->size)) { + pos += size(); + if (uint(pos) >= uint(size())) { // range problems - } else if (len >= d->size - pos) { + } else if (len >= size() - pos) { resize(pos); // truncate } else if (len > 0) { detach(); - memmove(d->data() + pos, d->data() + pos + len, - (d->size - pos - len + 1) * sizeof(ushort)); - d->size -= len; + memmove(d.data() + pos, d.data() + pos + len, + (d.size - pos - len + 1) * sizeof(ushort)); + d.size -= len; } return *this; } @@ -2993,10 +2970,10 @@ QString &QString::replace(int pos, int len, const QString &after) */ QString &QString::replace(int pos, int len, const QChar *unicode, int size) { - if (uint(pos) > uint(d->size)) + if (uint(pos) > uint(this->size())) return *this; - if (len > d->size - pos) - len = d->size - pos; + if (len > this->size() - pos) + len = this->size() - pos; uint index = pos; replace_helper(&index, 1, len, unicode, size); @@ -3060,10 +3037,10 @@ bool pointsIntoRange(const QChar *ptr, const ushort *base, int len) */ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen) { - // Copy after if it lies inside our own d->data() area (which we could + // Copy after if it lies inside our own d.b area (which we could // possibly invalidate via a realloc or modify by replacement). QChar *afterBuffer = nullptr; - if (pointsIntoRange(after, d->data(), d->size)) // Use copy in place of vulnerable original: + if (pointsIntoRange(after, d.data(), d.size)) // Use copy in place of vulnerable original: after = afterBuffer = textCopy(after, alen); QT_TRY { @@ -3071,36 +3048,36 @@ 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], after, alen * sizeof(QChar)); + memcpy(d.data() + indices[i], after, 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, after, alen * sizeof(QChar)); + memcpy(d.data() + to, after, alen * sizeof(QChar)); to += alen; } movestart = indices[i] + blen; } - int msize = d->size - movestart; + int msize = d.size - movestart; if (msize > 0) - memmove(d->data() + to, d->data() + movestart, msize * sizeof(QChar)); - resize(d->size - nIndices*(blen-alen)); + memmove(d.data() + to, d.data() + movestart, msize * sizeof(QChar)); + resize(d.size - nIndices*(blen-alen)); } else { // replace from back int adjust = nIndices*(alen-blen); - int newLen = d->size + adjust; - int moveend = d->size; + int newLen = d.size + adjust; + int moveend = d.size; resize(newLen); while (nIndices) { @@ -3108,9 +3085,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, after, alen * sizeof(QChar)); + memcpy(d.data() + insertstart, after, alen * sizeof(QChar)); moveend = movestart-blen; } } @@ -3136,7 +3113,7 @@ QString &QString::replace(const QChar *before, int blen, const QChar *after, int alen, Qt::CaseSensitivity cs) { - if (d->size == 0) { + if (d.size == 0) { if (blen) return *this; } else { @@ -3171,10 +3148,10 @@ QString &QString::replace(const QChar *before, int blen, We're about to change data, that before and after might point into, and we'll need that data for our next batch of indices. */ - if (!afterBuffer && pointsIntoRange(after, d->data(), d->size)) + if (!afterBuffer && pointsIntoRange(after, d.data(), d.size)) after = afterBuffer = textCopy(after, alen); - if (!beforeBuffer && pointsIntoRange(before, d->data(), d->size)) { + if (!beforeBuffer && pointsIntoRange(before, d.data(), d.size)) { beforeBuffer = textCopy(before, blen); matcher = QStringMatcher(beforeBuffer, blen, cs); } @@ -3203,13 +3180,13 @@ QString &QString::replace(const QChar *before, int blen, */ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs) { - if (after.d->size == 0) + if (after.size() == 0) return remove(ch, cs); - if (after.d->size == 1) + if (after.size() == 1) return replace(ch, after.front(), cs); - if (d->size == 0) + if (size() == 0) return *this; ushort cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode()); @@ -3219,14 +3196,14 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs uint indices[1024]; uint pos = 0; if (cs == Qt::CaseSensitive) { - while (pos < 1024 && index < d->size) { - if (d->data()[index] == cc) + while (pos < 1024 && index < size()) { + if (d.data()[index] == cc) indices[pos++] = index; index++; } } else { - while (pos < 1024 && index < d->size) { - if (QChar::toCaseFolded(d->data()[index]) == cc) + while (pos < 1024 && index < size()) { + if (QChar::toCaseFolded(d.data()[index]) == cc) indices[pos++] = index; index++; } @@ -3234,12 +3211,12 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs if (!pos) // Nothing to replace break; - replace_helper(indices, pos, 1, after.constData(), after.d->size); + replace_helper(indices, pos, 1, after.constData(), after.size()); if (Q_LIKELY(index == -1)) // Nothing left to replace break; // The call to replace_helper just moved what index points at: - index += pos*(after.d->size - 1); + index += pos*(after.size() - 1); } return *this; } @@ -3254,13 +3231,13 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs */ QString& QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs) { - if (d->size) { + if (d.size) { const int idx = indexOf(before, 0, cs); if (idx != -1) { detach(); const ushort a = after.unicode(); - ushort *i = d->data(); - const ushort *e = i + d->size; + ushort *i = d.data(); + ushort *const e = i + d.size; i += idx; *i = a; if (cs == Qt::CaseSensitive) { @@ -3321,7 +3298,7 @@ QString &QString::replace(QLatin1String before, const QString &after, Qt::CaseSe int blen = before.size(); QVarLengthArray<ushort> b(blen); qt_from_latin1(b.data(), before.latin1(), blen); - return replace((const QChar *)b.data(), blen, after.constData(), after.d->size, cs); + return replace((const QChar *)b.data(), blen, after.constData(), after.d.size, cs); } /*! @@ -3341,7 +3318,7 @@ QString &QString::replace(const QString &before, QLatin1String after, Qt::CaseSe int alen = after.size(); QVarLengthArray<ushort> a(alen); qt_from_latin1(a.data(), after.latin1(), alen); - return replace(before.constData(), before.d->size, (const QChar *)a.data(), alen, cs); + return replace(before.constData(), before.d.size, (const QChar *)a.data(), alen, cs); } /*! @@ -3377,7 +3354,7 @@ QString &QString::replace(QChar c, QLatin1String after, Qt::CaseSensitivity cs) */ bool operator==(const QString &s1, const QString &s2) noexcept { - if (s1.d->size != s2.d->size) + if (s1.d.size != s2.d.size) return false; return qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0; @@ -3390,7 +3367,7 @@ bool operator==(const QString &s1, const QString &s2) noexcept */ bool QString::operator==(QLatin1String other) const noexcept { - if (d->size != other.size()) + if (size() != other.size()) return false; return qt_compare_strings(*this, other, Qt::CaseSensitive) == 0; @@ -3817,7 +3794,7 @@ int QString::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) co int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { // ### Qt6: qsizetype - return int(QtPrivate::lastIndexOf(*this, from, str, cs)); + return int(QtPrivate::lastIndexOf(QStringView(*this), from, str, cs)); } #endif // QT_STRINGVIEW_LEVEL < 2 @@ -3856,7 +3833,7 @@ int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) co int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { // ### Qt6: qsizetype - return int(qLastIndexOf(*this, ch, from, cs)); + return int(qLastIndexOf(QStringView(*this), ch, from, cs)); } #if QT_STRINGVIEW_LEVEL < 2 @@ -3936,7 +3913,7 @@ QString& QString::replace(const QRegExp &rx, const QString &after) if (isEmpty() && rx2.indexIn(*this) == -1) return *this; - reallocData(uint(d->size) + 1u); + reallocData(uint(d.size) + 1u); int index = 0; int numCaptures = rx2.captureCount(); @@ -4035,8 +4012,8 @@ QString& QString::replace(const QRegExp &rx, const QString &after) } if (!pos) break; - replacements[pos].pos = d->size; - int newlen = d->size + adjust; + replacements[pos].pos = d.size; + int newlen = d.size + adjust; // to continue searching at the right position after we did // the first round of replacements @@ -4051,14 +4028,14 @@ QString& QString::replace(const QRegExp &rx, const QString &after) while (i < pos) { int copyend = replacements[i].pos; int size = copyend - copystart; - memcpy(static_cast<void*>(uc), static_cast<const void *>(d->data() + copystart), size * sizeof(QChar)); + memcpy(static_cast<void*>(uc), static_cast<const void *>(d.data() + copystart), size * sizeof(QChar)); uc += size; - memcpy(static_cast<void *>(uc), static_cast<const void *>(after.d->data()), al * sizeof(QChar)); + memcpy(static_cast<void *>(uc), static_cast<const void *>(after.d.data()), al * sizeof(QChar)); uc += al; copystart = copyend + replacements[i].length; i++; } - memcpy(static_cast<void *>(uc), static_cast<const void *>(d->data() + copystart), (d->size - copystart) * sizeof(QChar)); + memcpy(static_cast<void *>(uc), static_cast<const void *>(d.data() + copystart), (d.size - copystart) * sizeof(QChar)); newstring.resize(newlen); *this = newstring; caretMode = QRegExp::CaretWontMatch; @@ -4098,7 +4075,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) if (!iterator.hasNext()) // no matches at all return *this; - reallocData(uint(d->size) + 1u); + reallocData(uint(d.size) + 1u); int numCaptures = re.captureCount(); @@ -4850,9 +4827,9 @@ QString QString::section(const QRegularExpression &re, int start, int end, Secti */ QString QString::left(int n) const { - if (uint(n) >= uint(d->size)) + if (uint(n) >= uint(size())) return *this; - return QString((const QChar*) d->data(), n); + return QString((const QChar*) d.data(), n); } /*! @@ -4868,9 +4845,9 @@ QString QString::left(int n) const */ QString QString::right(int n) const { - if (uint(n) >= uint(d->size)) + if (uint(n) >= uint(size())) return *this; - return QString((const QChar*) d->data() + d->size - n, n); + return QString(constData() + size() - n, n); } /*! @@ -4893,18 +4870,19 @@ QString QString::right(int n) const QString QString::mid(int position, int n) const { using namespace QtPrivate; - switch (QContainerImplHelper::mid(d->size, &position, &n)) { + switch (QContainerImplHelper::mid(size(), &position, &n)) { case QContainerImplHelper::Null: return QString(); case QContainerImplHelper::Empty: { - QStringDataPtr empty = { Data::allocate(0) }; + QPair<Data *, ushort *> pair = Data::allocate(0); + DataPointer empty = { pair.first, pair.second, 0 }; return QString(empty); } case QContainerImplHelper::Full: return *this; case QContainerImplHelper::Subset: - return QString((const QChar*)d->data() + position, n); + return QString(constData() + position, n); } Q_UNREACHABLE(); return QString(); @@ -5058,21 +5036,25 @@ bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const } /*! - Returns \c true if the string only contains uppercase letters, - otherwise returns \c false. + Returns \c true if the string is uppercase, that is, it's identical + to its toUpper() folding. + + Note that this does \e not mean that the string does not contain + lowercase letters (some lowercase letters do not have a uppercase + folding; they are left unchanged by toUpper()). + For more information, refer to the Unicode standard, section 3.13. + \since 5.12 - \sa QChar::isUpper(), isLower() + \sa QChar::toUpper(), isLower() */ bool QString::isUpper() const { - if (isEmpty()) - return false; - - const QChar *d = data(); + QStringIterator it(*this); - for (int i = 0, max = size(); i < max; ++i) { - if (!d[i].isUpper()) + while (it.hasNext()) { + uint uc = it.nextUnchecked(); + if (qGetProp(uc)->cases[QUnicodeTables::UpperCase].diff) return false; } @@ -5080,21 +5062,25 @@ bool QString::isUpper() const } /*! - Returns \c true if the string only contains lowercase letters, - otherwise returns \c false. + Returns \c true if the string is lowercase, that is, it's identical + to its toLower() folding. + + Note that this does \e not mean that the string does not contain + uppercase letters (some uppercase letters do not have a lowercase + folding; they are left unchanged by toLower()). + For more information, refer to the Unicode standard, section 3.13. + \since 5.12 - \sa QChar::isLower(), isUpper() + \sa QChar::toLower(), isUpper() */ bool QString::isLower() const { - if (isEmpty()) - return false; + QStringIterator it(*this); - const QChar *d = data(); - - for (int i = 0, max = size(); i < max; ++i) { - if (!d[i].isLower()) + while (it.hasNext()) { + uint uc = it.nextUnchecked(); + if (qGetProp(uc)->cases[QUnicodeTables::LowerCase].diff) return false; } @@ -5146,29 +5132,29 @@ QByteArray QString::toLatin1_helper_inplace(QString &s) // We can return our own buffer to the caller. // Conversion to Latin-1 always shrinks the buffer by half. - const ushort *data = reinterpret_cast<const ushort *>(s.constData()); - uint length = s.size(); + const ushort *data = s.d.data(); + int length = s.d.size; - // Swap the d pointers. + // Move the d pointer over to the bytearray. // Kids, avert your eyes. Don't try this at home. - QArrayData *ba_d = s.d; - // multiply the allocated capacity by sizeof(ushort) - ba_d->alloc *= sizeof(ushort); + // this relies on the fact that we use QArrayData for everything behind the scenes which has the same layout + static_assert(sizeof(QByteArray::DataPointer) == sizeof(QString::DataPointer), "sizes have to be equal"); + QByteArray::DataPointer ba_d(reinterpret_cast<QByteArray::Data *>(s.d.d_ptr()), reinterpret_cast<char *>(s.d.data()), length); + ba_d.ref(); + s.clear(); - // reset ourselves to QString() - s.d = QString().d; + char *ddata = ba_d.data(); - // do the in-place conversion - uchar *dst = reinterpret_cast<uchar *>(ba_d->data()); - qt_to_latin1(dst, data, length); - dst[length] = '\0'; + // multiply the allocated capacity by sizeof(ushort) + ba_d.d_ptr()->alloc *= sizeof(ushort); - QByteArrayDataPtr badptr = { ba_d }; - return QByteArray(badptr); + // do the in-place conversion + qt_to_latin1(reinterpret_cast<uchar *>(ddata), data, length); + ddata[length] = '\0'; + return QByteArray(ba_d); } - /*! \fn QByteArray QString::toLatin1() const @@ -5348,34 +5334,25 @@ QVector<uint> QtPrivate::convertToUcs4(QStringView string) return qt_convert_to_ucs4(string); } -QString::Data *QString::fromLatin1_helper(const char *str, int size) +QString::DataPointer QString::fromLatin1_helper(const char *str, int size) { - Data *d; + DataPointer d; if (!str) { - d = Data::sharedNull(); + // nothing to do } else if (size == 0 || (!*str && size < 0)) { - d = Data::allocate(0); + d = DataPointer(Data::allocate(0), 0); } else { if (size < 0) size = qstrlen(str); - d = Data::allocate(size + 1); - Q_CHECK_PTR(d); - d->size = size; - d->data()[size] = '\0'; - ushort *dst = d->data(); + d = DataPointer(Data::allocate(size + 1), size); + d.data()[size] = '\0'; + ushort *dst = d.data(); qt_from_latin1(dst, str, uint(size)); } return d; } -QString::Data *QString::fromAscii_helper(const char *str, int size) -{ - QString s = fromUtf8(str, size); - s.d->ref.ref(); - return s.d; -} - /*! \fn QString QString::fromLatin1(const char *str, int size) Returns a QString initialized with the first \a size characters of the Latin-1 string \a str. @@ -5418,7 +5395,8 @@ QString QString::fromLocal8Bit_helper(const char *str, int size) if (!str) return QString(); if (size == 0 || (!*str && size < 0)) { - QStringDataPtr empty = { Data::allocate(0) }; + QPair<Data *, ushort *> pair = Data::allocate(0); + QString::DataPointer empty = { pair.first, pair.second, 0 }; return QString(empty); } #if QT_CONFIG(textcodec) @@ -5588,7 +5566,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; } @@ -5710,7 +5688,7 @@ QString QString::trimmed_helper(QString &str) */ /*! - \fn QCharRef QString::operator[](int position) + \fn QChar &QString::operator[](int position) Returns the character at the specified \a position in the string as a modifiable reference. @@ -5719,20 +5697,6 @@ QString QString::trimmed_helper(QString &str) \snippet qstring/main.cpp 85 - The return value is of type QCharRef, a helper class for QString. - When you get an object of type QCharRef, you can use it as if it - were a reference to a QChar. If you assign to it, the assignment will apply to - the character in the QString from which you got the reference. - - \note Before Qt 5.14 it was possible to use this operator to access - a character at an out-of-bounds position in the string, and - then assign to such a position, causing the string to be - automatically resized. Furthermore, assigning a value to the - returned QCharRef would cause a detach of the string, even if the - string has been copied in the meanwhile (and the QCharRef kept - alive while the copy was taken). These behaviors are deprecated, - and will be changed in a future version of Qt. - \sa at() */ @@ -5742,19 +5706,6 @@ QString QString::trimmed_helper(QString &str) \overload operator[]() */ -/*! \fn QCharRef QString::operator[](uint position) - -\overload operator[]() - -Returns the character at the specified \a position in the string as a -modifiable reference. -*/ - -/*! \fn const QChar QString::operator[](uint position) const - Equivalent to \c at(position). -\overload operator[]() -*/ - /*! \fn QChar QString::front() const \since 5.10 @@ -5786,7 +5737,7 @@ modifiable reference. */ /*! - \fn QCharRef QString::front() + \fn QChar &QString::front() \since 5.10 Returns a reference to the first character in the string. @@ -5801,7 +5752,7 @@ modifiable reference. */ /*! - \fn QCharRef QString::back() + \fn QChar &QString::back() \since 5.10 Returns a reference to the last character in the string. @@ -5834,7 +5785,7 @@ modifiable reference. void QString::truncate(int pos) { - if (pos < d->size) + if (pos < size()) resize(pos); } @@ -5856,7 +5807,7 @@ void QString::truncate(int pos) void QString::chop(int n) { if (n > 0) - resize(d->size - n); + resize(d.size - n); } /*! @@ -5873,10 +5824,10 @@ void QString::chop(int n) 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(); + resize(size < 0 ? d.size : size); + if (d.size) { + QChar *i = (QChar*)d.data() + d.size; + QChar *b = (QChar*)d.data(); while (i != b) *--i = ch; } @@ -6457,11 +6408,11 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1, const ushort *QString::utf16() const { - if (IS_RAW_DATA(d)) { + if (!d->isMutable()) { // ensure '\0'-termination for ::fromRawData strings - const_cast<QString*>(this)->reallocData(uint(d->size) + 1u); + const_cast<QString*>(this)->reallocData(uint(d.size) + 1u); } - return d->data(); + return d.data(); } /*! @@ -6490,8 +6441,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 { @@ -6528,11 +6479,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(static_cast<void *>(uc), static_cast<const void *>(d->data()), sizeof(QChar)*len); + memcpy(static_cast<void *>(uc), static_cast<const void *>(d.data()), sizeof(QChar)*len); } else { if (truncate) result = left(width); @@ -7941,7 +7892,7 @@ QVector<QStringRef> QString::splitRef(const QRegularExpression &re, SplitBehavio */ QString QString::repeated(int times) const { - if (d->size == 0) + if (d.size == 0) return *this; if (times <= 1) { @@ -7950,27 +7901,27 @@ QString QString::repeated(int times) const return QString(); } - const int resultSize = times * d->size; + const int resultSize = times * d.size; QString result; result.reserve(resultSize); - if (result.d->alloc != uint(resultSize) + 1u) + if (result.capacity() != 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; + int sizeSoFar = d.size; + 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'; - result.d->size = resultSize; + memcpy(end, result.d.data(), (resultSize - sizeSoFar) * sizeof(ushort)); + result.d.data()[resultSize] = '\0'; + result.d.size = resultSize; return result; } @@ -8970,8 +8921,8 @@ QString QtPrivate::argToQString(QLatin1String pattern, size_t n, const ArgBase * */ bool QString::isSimpleText() const { - const ushort *p = d->data(); - const ushort * const end = p + d->size; + 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 @@ -8995,6 +8946,21 @@ bool QString::isRightToLeft() const return QtPrivate::isRightToLeft(QStringView(*this)); } +/*! + \fn bool QString::isValidUtf16() const noexcept + \since 5.15 + + Returns \c true if the string contains valid UTF-16 encoded data, + or \c false otherwise. + + Note that this function does not perform any special validation of the + data; it merely checks if it can be successfully decoded from UTF-16. + The data is assumed to be in host byte order; the presence of a BOM + is meaningless. + + \sa QStringView::isValidUtf16() +*/ + /*! \fn QChar *QString::data() Returns a pointer to the data stored in the QString. The pointer @@ -9120,17 +9086,14 @@ bool QString::isRightToLeft() const */ QString QString::fromRawData(const QChar *unicode, int size) { - Data *x; + QString::DataPointer x; if (!unicode) { - x = Data::sharedNull(); } else if (!size) { - x = Data::allocate(0); + x = DataPointer(Data::allocate(0), 0); } else { x = Data::fromRawData(reinterpret_cast<const ushort *>(unicode), size); - Q_CHECK_PTR(x); } - QStringDataPtr dataPtr = { x }; - return QString(dataPtr); + return QString(x); } /*! @@ -9149,17 +9112,10 @@ QString QString::fromRawData(const QChar *unicode, int size) */ QString &QString::setRawData(const QChar *unicode, int size) { - if (d->ref.isShared() || d->alloc) { - *this = fromRawData(unicode, size); - } else { - if (unicode) { - d->size = size; - d->offset = reinterpret_cast<const char *>(unicode) - reinterpret_cast<char *>(d); - } else { - d->offset = sizeof(QStringData); - d->size = 0; - } + if (!unicode || !size) { + clear(); } + *this = fromRawData(unicode, size); return *this; } diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 4635962057..65d702ff1c 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2019 Intel Corporation. ** Copyright (C) 2019 Mail.ru Group. ** Contact: https://www.qt.io/licensing/ ** @@ -48,7 +48,7 @@ #include <QtCore/qchar.h> #include <QtCore/qbytearray.h> -#include <QtCore/qrefcount.h> +#include <QtCore/qarraydata.h> #include <QtCore/qnamespace.h> #include <QtCore/qstringliteral.h> #include <QtCore/qstringalgorithms.h> @@ -70,7 +70,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSString); QT_BEGIN_NAMESPACE -class QCharRef; class QRegExp; class QRegularExpression; class QRegularExpressionMatch; @@ -246,8 +245,9 @@ qsizetype QStringView::lastIndexOf(QLatin1String s, qsizetype from, Qt::CaseSens class Q_CORE_EXPORT QString { + typedef QTypedArrayData<ushort> Data; public: - typedef QStringData Data; + typedef QStringPrivate DataPointer; inline QString() noexcept; explicit QString(const QChar *unicode, int size = -1); @@ -259,12 +259,13 @@ public: QString &operator=(QChar c); QString &operator=(const QString &) noexcept; QString &operator=(QLatin1String latin1); - inline QString(QString && other) noexcept : d(other.d) { other.d = Data::sharedNull(); } + inline QString(QString &&other) noexcept + { qSwap(d, other.d); } inline QString &operator=(QString &&other) noexcept { qSwap(d, other.d); return *this; } inline void swap(QString &other) noexcept { qSwap(d, other.d); } - inline int size() const { return d->size; } - inline int count() const { return d->size; } + inline int size() const { return int(d.size); } + inline int count() const { return int(d.size); } inline int length() const; inline bool isEmpty() const; void resize(int size); @@ -274,7 +275,7 @@ public: void truncate(int pos); void chop(int n); - int capacity() const; + inline int capacity() const; inline void reserve(int size); inline void squeeze(); @@ -285,19 +286,17 @@ public: inline void detach(); inline bool isDetached() const; - inline bool isSharedWith(const QString &other) const { return d == other.d; } + inline bool isSharedWith(const QString &other) const { return d.isSharedWith(other.d); } void clear(); inline const QChar at(int i) const; const QChar operator[](int i) const; - Q_REQUIRED_RESULT QCharRef operator[](int i); - const QChar operator[](uint i) const; - Q_REQUIRED_RESULT QCharRef operator[](uint i); + Q_REQUIRED_RESULT QChar &operator[](int i); Q_REQUIRED_RESULT inline QChar front() const { return at(0); } - Q_REQUIRED_RESULT inline QCharRef front(); + Q_REQUIRED_RESULT inline QChar &front(); Q_REQUIRED_RESULT inline QChar back() const { return at(size() - 1); } - Q_REQUIRED_RESULT inline QCharRef back(); + Q_REQUIRED_RESULT inline QChar &back(); Q_REQUIRED_RESULT QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar = QLatin1Char(' ')) const; @@ -486,7 +485,7 @@ public: Q_REQUIRED_RESULT QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const; #if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC) -# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_CPP_ATTRIBUTE(nodiscard) +# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_cpp_attribute(nodiscard) // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 # pragma push_macro("Q_REQUIRED_RESULT") # undef Q_REQUIRED_RESULT @@ -542,10 +541,10 @@ public: inline QString &prepend(QLatin1String s) { return insert(0, s); } inline QString &operator+=(QChar c) { - if (d->ref.isShared() || uint(d->size) + 2u > d->alloc) - reallocData(uint(d->size) + 2u, true); - d->data()[d->size++] = c.unicode(); - d->data()[d->size] = '\0'; + if (d->needsDetach() || int(d.size + 1) > capacity()) + reallocData(uint(d.size) + 2u, true); + d->data()[d.size++] = c.unicode(); + d->data()[d.size] = '\0'; return *this; } @@ -658,8 +657,7 @@ public: // note - this are all inline so we can benefit from strlen() compile time optimizations static inline QString fromLatin1(const char *str, int size = -1) { - QStringDataPtr dataPtr = { fromLatin1_helper(str, (str && size == -1) ? int(strlen(str)) : size) }; - return QString(dataPtr); + return QString(fromLatin1_helper(str, (str && size == -1) ? int(strlen(str)) : size)); } static inline QString fromUtf8(const char *str, int size = -1) { @@ -791,10 +789,10 @@ public: #endif #if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline QT_ASCII_CAST_WARN QString(const char *ch) - : d(fromAscii_helper(ch, ch ? int(strlen(ch)) : -1)) + : QString(fromUtf8(ch)) {} inline QT_ASCII_CAST_WARN QString(const QByteArray &a) - : d(fromAscii_helper(a.constData(), qstrnlen(a.constData(), a.size()))) + : QString(fromUtf8(a)) {} inline QT_ASCII_CAST_WARN QString &operator=(const char *ch) { return (*this = fromUtf8(ch)); } @@ -910,17 +908,19 @@ public: struct Null { }; QT_DEPRECATED_X("use QString()") static const Null null; - inline QString(const Null &): d(Data::sharedNull()) {} + inline QString(const Null &) {} inline QString &operator=(const Null &) { *this = QString(); return *this; } #endif - inline bool isNull() const { return d == Data::sharedNull(); } + inline bool isNull() const { return d->isNull(); } bool isSimpleText() const; bool isRightToLeft() const; + Q_REQUIRED_RESULT bool isValidUtf16() const noexcept + { return QStringView(*this).isValidUtf16(); } QString(int size, Qt::Initialization); - Q_DECL_CONSTEXPR inline QString(QStringDataPtr dd) : d(dd.ptr) {} + explicit QString(DataPointer dd) : d(dd) {} private: #if defined(QT_NO_CAST_FROM_ASCII) @@ -932,7 +932,7 @@ private: QString &operator=(const QByteArray &a); #endif - Data *d; + DataPointer d; friend inline bool operator==(QChar, const QString &) noexcept; friend inline bool operator< (QChar, const QString &) noexcept; @@ -970,8 +970,7 @@ private: static QString trimmed_helper(QString &str); static QString simplified_helper(const QString &str); static QString simplified_helper(QString &str); - static Data *fromLatin1_helper(const char *str, int size = -1); - static Data *fromAscii_helper(const char *str, int size = -1); + static DataPointer fromLatin1_helper(const char *str, int size = -1); static QString fromUtf8_helper(const char *str, int size); static QString fromLocal8Bit_helper(const char *, int size); static QByteArray toLatin1_helper(const QString &); @@ -982,7 +981,6 @@ private: static qlonglong toIntegral_helper(const QChar *data, int len, bool *ok, int base); static qulonglong toIntegral_helper(const QChar *data, uint len, bool *ok, int base); void replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen); - friend class QCharRef; friend class QTextCodec; friend class QStringRef; friend class QStringView; @@ -1007,8 +1005,7 @@ private: } public: - typedef Data * DataPtr; - inline DataPtr &data_ptr() { return d; } + inline DataPointer &data_ptr() { return d; } }; // @@ -1023,33 +1020,31 @@ QString QStringView::toString() const inline QString::QString(QLatin1String aLatin1) : d(fromLatin1_helper(aLatin1.latin1(), aLatin1.size())) { } inline int QString::length() const -{ return d->size; } +{ return int(d.size); } inline const QChar QString::at(int i) const -{ Q_ASSERT(uint(i) < uint(size())); return QChar(d->data()[i]); } +{ Q_ASSERT(uint(i) < uint(size())); return QChar(d.data()[i]); } inline const QChar QString::operator[](int i) const -{ Q_ASSERT(uint(i) < uint(size())); return QChar(d->data()[i]); } -inline const QChar QString::operator[](uint i) const -{ Q_ASSERT(i < uint(size())); return QChar(d->data()[i]); } +{ Q_ASSERT(uint(i) < uint(size())); return QChar(d.data()[i]); } inline bool QString::isEmpty() const -{ return d->size == 0; } +{ 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.isShared() || (d->offset != sizeof(QStringData))) reallocData(uint(d->size) + 1u); } +{ if (d->needsDetach()) reallocData(d.size + 1u); } inline bool QString::isDetached() const -{ return !d->ref.isShared(); } +{ return !d->isShared(); } inline void QString::clear() { if (!isNull()) *this = QString(); } inline QString::QString(const QString &other) noexcept : d(other.d) -{ Q_ASSERT(&other != this); d->ref.ref(); } +{ } inline int QString::capacity() const -{ return d->alloc ? d->alloc - 1 : 0; } +{ const auto realCapacity = d->constAllocatedCapacity(); return realCapacity ? int(realCapacity) - 1 : 0; } inline QString &QString::setNum(short n, int base) { return setNum(qlonglong(n), base); } inline QString &QString::setNum(ushort n, int base) @@ -1136,178 +1131,51 @@ inline QString QString::fromWCharArray(const wchar_t *string, int size) : fromUcs4(reinterpret_cast<const uint *>(string), size); } -class -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -Q_CORE_EXPORT -#endif -QCharRef { // ### Qt 7: remove - QString &s; - int i; - inline QCharRef(QString &str, int idx) - : s(str),i(idx) {} - friend class QString; -public: - - // most QChar operations repeated here - - // all this is not documented: We just say "like QChar" and let it be. - inline operator QChar() const - { - using namespace QtPrivate::DeprecatedRefClassBehavior; - if (Q_LIKELY(i < s.d->size)) - return QChar(s.d->data()[i]); -#ifdef QT_DEBUG - warn(WarningType::OutOfRange, EmittingClass::QCharRef); -#endif - return QChar(); - } - inline QCharRef &operator=(QChar c) - { - using namespace QtPrivate::DeprecatedRefClassBehavior; - if (Q_UNLIKELY(i >= s.d->size)) { -#ifdef QT_DEBUG - warn(WarningType::OutOfRange, EmittingClass::QCharRef); -#endif - s.resize(i + 1, QLatin1Char(' ')); - } else { -#ifdef QT_DEBUG - if (Q_UNLIKELY(!s.isDetached())) - warn(WarningType::DelayedDetach, EmittingClass::QCharRef); -#endif - s.detach(); - } - s.d->data()[i] = c.unicode(); - return *this; - } - - // An operator= for each QChar cast constructors -#ifndef QT_NO_CAST_FROM_ASCII - inline QT_ASCII_CAST_WARN QCharRef &operator=(char c) - { return operator=(QChar::fromLatin1(c)); } - inline QT_ASCII_CAST_WARN QCharRef &operator=(uchar c) - { return operator=(QChar::fromLatin1(c)); } -#endif - inline QCharRef &operator=(const QCharRef &c) { return operator=(QChar(c)); } - inline QCharRef &operator=(ushort rc) { return operator=(QChar(rc)); } - inline QCharRef &operator=(short rc) { return operator=(QChar(rc)); } - inline QCharRef &operator=(uint rc) { return operator=(QChar(rc)); } - inline QCharRef &operator=(int rc) { return operator=(QChar(rc)); } - - // each function... - inline bool isNull() const { return QChar(*this).isNull(); } - inline bool isPrint() const { return QChar(*this).isPrint(); } - inline bool isPunct() const { return QChar(*this).isPunct(); } - inline bool isSpace() const { return QChar(*this).isSpace(); } - inline bool isMark() const { return QChar(*this).isMark(); } - inline bool isLetter() const { return QChar(*this).isLetter(); } - inline bool isNumber() const { return QChar(*this).isNumber(); } - inline bool isLetterOrNumber() { return QChar(*this).isLetterOrNumber(); } - inline bool isDigit() const { return QChar(*this).isDigit(); } - inline bool isLower() const { return QChar(*this).isLower(); } - inline bool isUpper() const { return QChar(*this).isUpper(); } - inline bool isTitleCase() const { return QChar(*this).isTitleCase(); } - - inline int digitValue() const { return QChar(*this).digitValue(); } - QChar toLower() const { return QChar(*this).toLower(); } - QChar toUpper() const { return QChar(*this).toUpper(); } - QChar toTitleCase () const { return QChar(*this).toTitleCase(); } - - QChar::Category category() const { return QChar(*this).category(); } - QChar::Direction direction() const { return QChar(*this).direction(); } - QChar::JoiningType joiningType() const { return QChar(*this).joiningType(); } -#if QT_DEPRECATED_SINCE(5, 3) - QT_DEPRECATED QChar::Joining joining() const - { - switch (QChar(*this).joiningType()) { - case QChar::Joining_Causing: return QChar::Center; - case QChar::Joining_Dual: return QChar::Dual; - case QChar::Joining_Right: return QChar::Right; - case QChar::Joining_None: - case QChar::Joining_Left: - case QChar::Joining_Transparent: - default: return QChar::OtherJoining; - } - } -#endif - bool hasMirrored() const { return QChar(*this).hasMirrored(); } - QChar mirroredChar() const { return QChar(*this).mirroredChar(); } - QString decomposition() const { return QChar(*this).decomposition(); } - QChar::Decomposition decompositionTag() const { return QChar(*this).decompositionTag(); } - uchar combiningClass() const { return QChar(*this).combiningClass(); } - - inline QChar::Script script() const { return QChar(*this).script(); } - - QChar::UnicodeVersion unicodeVersion() const { return QChar(*this).unicodeVersion(); } - - inline uchar cell() const { return QChar(*this).cell(); } - inline uchar row() const { return QChar(*this).row(); } - inline void setCell(uchar cell); - inline void setRow(uchar row); - -#if QT_DEPRECATED_SINCE(5, 0) - QT_DEPRECATED char toAscii() const { return QChar(*this).toLatin1(); } -#endif - char toLatin1() const { return QChar(*this).toLatin1(); } - ushort unicode() const { return QChar(*this).unicode(); } - ushort& unicode() { return s.data()[i].unicode(); } - -}; -Q_DECLARE_TYPEINFO(QCharRef, Q_MOVABLE_TYPE); - -inline void QCharRef::setRow(uchar arow) { QChar(*this).setRow(arow); } -inline void QCharRef::setCell(uchar acell) { QChar(*this).setCell(acell); } - - -inline QString::QString() noexcept : d(Data::sharedNull()) {} -inline QString::~QString() { if (!d->ref.deref()) Data::deallocate(d); } +inline QString::QString() noexcept {} +inline QString::~QString() {} inline void QString::reserve(int asize) { - if (d->ref.isShared() || uint(asize) >= d->alloc) - reallocData(qMax(asize, d->size) + 1u); + if (d->needsDetach() || asize >= capacity()) + reallocData(uint(qMax(asize, size())) + 1u); - if (!d->capacityReserved) { - // cannot set unconditionally, since d could be the shared_null/shared_empty (which is const) - d->capacityReserved = true; - } + // we're not shared anymore, for sure + d->flags() |= Data::CapacityReserved; } inline void QString::squeeze() { - if (d->ref.isShared() || uint(d->size) + 1u < d->alloc) - reallocData(uint(d->size) + 1u); + if ((d->flags() & Data::CapacityReserved) == 0) + return; + if (d->needsDetach() || int(d.size) < capacity()) + reallocData(uint(d.size) + 1u); - if (d->capacityReserved) { - // cannot set unconditionally, since d could be shared_null or - // otherwise static. - d->capacityReserved = false; - } + // we're not shared anymore, for sure + d->flags() &= uint(~Data::CapacityReserved); } inline QString &QString::setUtf16(const ushort *autf16, int asize) { return setUnicode(reinterpret_cast<const QChar *>(autf16), asize); } -inline QCharRef QString::operator[](int i) -{ Q_ASSERT(i >= 0); detach(); return QCharRef(*this, i); } -inline QCharRef QString::operator[](uint i) -{ detach(); return QCharRef(*this, i); } -inline QCharRef QString::front() { return operator[](0); } -inline QCharRef QString::back() { return operator[](size() - 1); } +inline QChar &QString::operator[](int i) +{ Q_ASSERT(i >= 0 && i < size()); return data()[i]; } +inline QChar &QString::front() { return operator[](0); } +inline QChar &QString::back() { return operator[](size() - 1); } 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::cbegin() 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::cend() 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); } #if QT_STRINGVIEW_LEVEL < 2 inline bool QString::contains(const QString &s, Qt::CaseSensitivity cs) const { return indexOf(s, 0, cs) != -1; } @@ -1534,7 +1402,8 @@ inline QString QString::fromStdU32String(const std::u32string &s) inline std::u32string QString::toStdU32String() const { std::u32string u32str(length(), char32_t(0)); - int len = toUcs4_helper(d->data(), length(), reinterpret_cast<uint*>(&u32str[0])); + int len = toUcs4_helper(reinterpret_cast<const ushort *>(constData()), length(), + reinterpret_cast<uint*>(&u32str[0])); u32str.resize(len); return u32str; } @@ -1666,7 +1535,7 @@ public: inline const QChar *unicode() const { if (!m_string) - return reinterpret_cast<const QChar *>(QString::Data::sharedNull()->data()); + return reinterpret_cast<const QChar *>(QString::Data::sharedNullData()); return m_string->unicode() + m_position; } inline const QChar *data() const { return unicode(); } diff --git a/src/corelib/text/qstringalgorithms.h b/src/corelib/text/qstringalgorithms.h index d54e376aa9..0b7774b4f3 100644 --- a/src/corelib/text/qstringalgorithms.h +++ b/src/corelib/text/qstringalgorithms.h @@ -99,6 +99,7 @@ Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isAscii(QLatin1String Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isAscii(QStringView s) noexcept; Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline bool isLatin1(QLatin1String s) noexcept; Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isLatin1(QStringView s) noexcept; +Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isValidUtf16(QStringView s) noexcept; } // namespace QtPRivate diff --git a/src/corelib/text/qstringbuilder.cpp b/src/corelib/text/qstringbuilder.cpp index cf443ec369..29bd216e80 100644 --- a/src/corelib/text/qstringbuilder.cpp +++ b/src/corelib/text/qstringbuilder.cpp @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE \list \li QString, QStringRef, (since 5.10:) QStringView - \li QChar, QCharRef, QLatin1Char, (since 5.10:) \c char16_t, + \li QChar, QLatin1Char, (since 5.10:) \c char16_t, \li QLatin1String, \li (since 5.10:) \c{const char16_t[]} (\c{u"foo"}), \li QByteArray, \c char, \c{const char[]}. @@ -108,7 +108,7 @@ QT_BEGIN_NAMESPACE This function is usable with arguments of type \c QString, \c QLatin1String, \c QStringRef, - \c QChar, \c QCharRef, \c QLatin1Char, and \c char. + \c QChar, \c QLatin1Char, and \c char. */ /* \fn template <typename A, typename B> QByteArray QStringBuilder<A, B>::toLatin1() const diff --git a/src/corelib/text/qstringbuilder.h b/src/corelib/text/qstringbuilder.h index 288d98d633..45fd270b66 100644 --- a/src/corelib/text/qstringbuilder.h +++ b/src/corelib/text/qstringbuilder.h @@ -231,16 +231,6 @@ template <> struct QConcatenable<QChar::SpecialCharacter> : private QAbstractCon { *out++ = c; } }; -template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable -{ - typedef QCharRef type; - typedef QString ConvertTo; - enum { ExactSize = true }; - static int size(QCharRef) { return 1; } - static inline void appendTo(QCharRef c, QChar *&out) - { *out++ = QChar(c); } -}; - template <> struct QConcatenable<QLatin1String> : private QAbstractConcatenable { typedef QLatin1String type; diff --git a/src/corelib/text/qstringliteral.h b/src/corelib/text/qstringliteral.h index 2a7e607c63..742d38de7d 100644 --- a/src/corelib/text/qstringliteral.h +++ b/src/corelib/text/qstringliteral.h @@ -42,6 +42,7 @@ #define QSTRINGLITERAL_H #include <QtCore/qarraydata.h> +#include <QtCore/qarraydatapointer.h> #if 0 #pragma qt_class(QStringLiteral) @@ -49,8 +50,6 @@ QT_BEGIN_NAMESPACE -typedef QTypedArrayData<ushort> QStringData; - // all our supported compilers support Unicode string literals, // even if their Q_COMPILER_UNICODE_STRING has been revoked due // to lacking stdlib support. But QStringLiteral only needs the @@ -65,44 +64,23 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2, #define QStringLiteral(str) \ ([]() noexcept -> QString { \ enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ - static const QStaticStringData<Size> qstring_literal = { \ - Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \ - QT_UNICODE_LITERAL(str) }; \ - QStringDataPtr holder = { qstring_literal.data_ptr() }; \ - const QString qstring_literal_temp(holder); \ - return qstring_literal_temp; \ + static const QArrayData qstring_literal = { \ + Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 \ + }; \ + QStringPrivate holder = { \ + static_cast<QTypedArrayData<ushort> *>(const_cast<QArrayData *>(&qstring_literal)), \ + reinterpret_cast<ushort *>(const_cast<qunicodechar *>(QT_UNICODE_LITERAL(str))), \ + Size \ + }; \ + return QString(holder); \ }()) \ /**/ -#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \ - { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \ - /**/ - -#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \ - Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QStringData)) \ - /**/ - #if QT_DEPRECATED_SINCE(5, 14) # define QStringViewLiteral(str) QStringView(QT_UNICODE_LITERAL(str), QtPrivate::Deprecated) #endif -template <int N> -struct QStaticStringData -{ - QArrayData str; - qunicodechar data[N + 1]; - - QStringData *data_ptr() const - { - Q_ASSERT(str.ref.isStatic()); - return const_cast<QStringData *>(static_cast<const QStringData*>(&str)); - } -}; - -struct QStringDataPtr -{ - QStringData *ptr; -}; +using QStringPrivate = QArrayDataPointer<ushort>; QT_END_NAMESPACE diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index 75de827583..c4ddb06ea4 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -865,6 +865,21 @@ QT_BEGIN_NAMESPACE */ /*! + \fn bool QStringView::isValidUtf16() const + \since 5.15 + + Returns \c true if the string contains valid UTF-16 encoded data, + or \c false otherwise. + + Note that this function does not perform any special validation of the + data; it merely checks if it can be successfully decoded from UTF-16. + The data is assumed to be in host byte order; the presence of a BOM + is meaningless. + + \sa QString::isValidUtf16() +*/ + +/*! \fn QStringView::toWCharArray(wchar_t *array) const \since 5.14 diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index 4ab4d2570f..06391ffef4 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -294,6 +294,8 @@ public: Q_REQUIRED_RESULT bool isRightToLeft() const noexcept { return QtPrivate::isRightToLeft(*this); } + Q_REQUIRED_RESULT bool isValidUtf16() const noexcept + { return QtPrivate::isValidUtf16(*this); } Q_REQUIRED_RESULT inline int toWCharArray(wchar_t *array) const; // defined in qstring.h diff --git a/src/corelib/text/qtextboundaryfinder.cpp b/src/corelib/text/qtextboundaryfinder.cpp index 67dd15377b..ebdba6b2c5 100644 --- a/src/corelib/text/qtextboundaryfinder.cpp +++ b/src/corelib/text/qtextboundaryfinder.cpp @@ -71,7 +71,7 @@ static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int } } - QUnicodeTools::CharAttributeOptions options = 0; + QUnicodeTools::CharAttributeOptions options; switch (type) { case QTextBoundaryFinder::Grapheme: options |= QUnicodeTools::GraphemeBreaks; break; case QTextBoundaryFinder::Word: options |= QUnicodeTools::WordBreaks; break; @@ -161,10 +161,10 @@ static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int */ QTextBoundaryFinder::QTextBoundaryFinder() : t(Grapheme) - , chars(0) + , chars(nullptr) , length(0) , freePrivate(true) - , d(0) + , d(nullptr) { } @@ -178,7 +178,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(const QTextBoundaryFinder &other) , length(other.length) , pos(other.pos) , freePrivate(true) - , d(0) + , d(nullptr) { if (other.d) { Q_ASSERT(length > 0); @@ -199,7 +199,7 @@ QTextBoundaryFinder &QTextBoundaryFinder::operator=(const QTextBoundaryFinder &o if (other.d) { Q_ASSERT(other.length > 0); uint newCapacity = (other.length + 1) * sizeof(QCharAttributes); - QTextBoundaryFinderPrivate *newD = (QTextBoundaryFinderPrivate *) realloc(freePrivate ? d : 0, newCapacity); + QTextBoundaryFinderPrivate *newD = (QTextBoundaryFinderPrivate *) realloc(freePrivate ? d : nullptr, newCapacity); Q_CHECK_PTR(newD); freePrivate = true; d = newD; @@ -216,7 +216,7 @@ QTextBoundaryFinder &QTextBoundaryFinder::operator=(const QTextBoundaryFinder &o } else { if (freePrivate) free(d); - d = 0; + d = nullptr; } return *this; @@ -242,7 +242,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QString &strin , length(string.length()) , pos(0) , freePrivate(true) - , d(0) + , d(nullptr) { if (length > 0) { d = (QTextBoundaryFinderPrivate *) malloc((length + 1) * sizeof(QCharAttributes)); @@ -271,7 +271,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QChar *chars, , length(length) , pos(0) , freePrivate(true) - , d(0) + , d(nullptr) { if (!chars) { length = 0; diff --git a/src/corelib/text/qunicodetables_p.h b/src/corelib/text/qunicodetables_p.h index 79878a859f..81efc09773 100644 --- a/src/corelib/text/qunicodetables_p.h +++ b/src/corelib/text/qunicodetables_p.h @@ -122,7 +122,8 @@ enum GraphemeBreakClass { Graphemebreak_E_Modifier, Graphemebreak_Glue_After_Zwj, Graphemebreak_E_Base_GAZ, - NumGraphemeBreakClasses, + + NumGraphemeBreakClasses }; enum WordBreakClass { @@ -149,7 +150,8 @@ enum WordBreakClass { WordBreak_Glue_After_Zwj, WordBreak_E_Base_GAZ, WordBreak_WSegSpace, - NumWordBreakClasses, + + NumWordBreakClasses }; enum SentenceBreakClass { @@ -167,6 +169,7 @@ enum SentenceBreakClass { SentenceBreak_SContinue, SentenceBreak_STerm, SentenceBreak_Close, + NumSentenceBreakClasses }; @@ -182,6 +185,7 @@ enum LineBreakClass { LineBreak_EB, LineBreak_EM, LineBreak_ZWJ, LineBreak_SA, LineBreak_SG, LineBreak_SP, LineBreak_CR, LineBreak_LF, LineBreak_BK, + NumLineBreakClasses }; |