summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qarraydata.cpp51
-rw-r--r--src/corelib/tools/qarraydata.h11
-rw-r--r--src/corelib/tools/qarraydataops.h14
-rw-r--r--src/corelib/tools/qbytearray.cpp163
-rw-r--r--src/corelib/tools/qbytearray.h17
-rw-r--r--src/corelib/tools/qbytearraymatcher.cpp108
-rw-r--r--src/corelib/tools/qbytearraymatcher.h81
-rw-r--r--src/corelib/tools/qchar.cpp4
-rw-r--r--src/corelib/tools/qcollator.h2
-rw-r--r--src/corelib/tools/qcollator_icu.cpp5
-rw-r--r--src/corelib/tools/qcollator_macx.cpp7
-rw-r--r--src/corelib/tools/qcollator_p.h9
-rw-r--r--src/corelib/tools/qcollator_posix.cpp2
-rw-r--r--src/corelib/tools/qcollator_win.cpp5
-rw-r--r--src/corelib/tools/qdatetime.cpp77
-rw-r--r--src/corelib/tools/qdatetime_p.h7
-rw-r--r--src/corelib/tools/qeasingcurve.h2
-rw-r--r--src/corelib/tools/qhash.cpp25
-rw-r--r--src/corelib/tools/qhash.h1
-rw-r--r--src/corelib/tools/qlist.h1
-rw-r--r--src/corelib/tools/qlocale.cpp74
-rw-r--r--src/corelib/tools/qlocale.h4
-rw-r--r--src/corelib/tools/qlocale.qdoc11
-rw-r--r--src/corelib/tools/qlocale_mac.mm33
-rw-r--r--src/corelib/tools/qlocale_p.h7
-rw-r--r--src/corelib/tools/qlocale_win.cpp15
-rw-r--r--src/corelib/tools/qmap.h5
-rw-r--r--src/corelib/tools/qregularexpression.cpp565
-rw-r--r--src/corelib/tools/qringbuffer.cpp1
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h4
-rw-r--r--src/corelib/tools/qstring.cpp199
-rw-r--r--src/corelib/tools/qstring.h69
-rw-r--r--src/corelib/tools/qstring_compat.cpp2
-rw-r--r--src/corelib/tools/qstringbuilder.h22
-rw-r--r--src/corelib/tools/qtimezone.h12
-rw-r--r--src/corelib/tools/qtimezoneprivate.cpp249
-rw-r--r--src/corelib/tools/qtimezoneprivate_android.cpp54
-rw-r--r--src/corelib/tools/qtimezoneprivate_icu.cpp4
-rw-r--r--src/corelib/tools/qtimezoneprivate_mac.mm7
-rw-r--r--src/corelib/tools/qtimezoneprivate_p.h34
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp139
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp4
-rw-r--r--src/corelib/tools/qvarlengtharray.h15
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc28
-rw-r--r--src/corelib/tools/qvector.h8
-rw-r--r--src/corelib/tools/qvsnprintf.cpp2
-rw-r--r--src/corelib/tools/tools.pri3
47 files changed, 1391 insertions, 771 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 55af7256be..a04536b18b 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -63,6 +63,29 @@ QT_WARNING_POP
static const QArrayData &qt_array_empty = qt_array[0];
static const QArrayData &qt_array_unsharable_empty = qt_array[1];
+static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize,
+ uint options)
+{
+ // Calculate the byte size
+ // allocSize = objectSize * capacity + headerSize, but checked for overflow
+ // plus padded to grow in size
+ if (options & QArrayData::Grow) {
+ auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
+ capacity = r.elementCount;
+ return r.size;
+ } else {
+ return qCalculateBlockSize(capacity, objectSize, headerSize);
+ }
+}
+
+static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint options)
+{
+ header = static_cast<QArrayData *>(::realloc(header, allocSize));
+ if (header)
+ header->capacityReserved = bool(options & QArrayData::CapacityReserved);
+ return header;
+}
+
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options) Q_DECL_NOTHROW
{
@@ -91,18 +114,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
if (headerSize > size_t(MaxAllocSize))
return 0;
- // Calculate the byte size
- // allocSize = objectSize * capacity + headerSize, but checked for overflow
- // plus padded to grow in size
- size_t allocSize;
- if (options & Grow) {
- auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
- capacity = r.elementCount;
- allocSize = r.size;
- } else {
- allocSize = qCalculateBlockSize(capacity, objectSize, headerSize);
- }
-
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
if (header) {
quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
@@ -122,6 +134,21 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
return header;
}
+QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity,
+ AllocationOptions options) Q_DECL_NOTHROW
+{
+ Q_ASSERT(data);
+ Q_ASSERT(data->isMutable());
+ Q_ASSERT(!data->ref.isShared());
+
+ size_t headerSize = sizeof(QArrayData);
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
+ QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options));
+ if (header)
+ header->alloc = capacity;
+ return header;
+}
+
void QArrayData::deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW
{
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index 5a369baf08..bc20932cca 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -115,6 +115,9 @@ struct Q_CORE_EXPORT QArrayData
static QArrayData *allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options = Default)
Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+ static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize,
+ size_t newCapacity, AllocationOptions newOptions = Default)
+ Q_DECL_NOTHROW Q_REQUIRED_RESULT;
static void deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW;
@@ -222,6 +225,14 @@ struct QTypedArrayData
Q_ALIGNOF(AlignmentDummy), capacity, options));
}
+ static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity,
+ AllocationOptions options = Default)
+ {
+ Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
+ return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T),
+ capacity, options));
+ }
+
static void deallocate(QArrayData *data)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 6bb8280ca8..ae83e6986e 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -145,7 +145,7 @@ struct QGenericArrayOps
T *const begin = this->begin();
do {
- new (begin + this->size) T();
+ new (begin + this->size) T;
} while (uint(++this->size) != newSize);
}
@@ -411,18 +411,18 @@ struct QArrayOpsSelector
template <class T>
struct QArrayOpsSelector<T,
- typename QEnableIf<
- !QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
- >::Type>
+ typename std::enable_if<
+ !QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ >::type>
{
typedef QPodArrayOps<T> Type;
};
template <class T>
struct QArrayOpsSelector<T,
- typename QEnableIf<
- QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
- >::Type>
+ typename std::enable_if<
+ QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ >::type>
{
typedef QMovableArrayOps<T> Type;
};
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 9298472305..329cc358d4 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -541,15 +541,40 @@ static const quint16 crc_tbl[16] = {
Returns the CRC-16 checksum of the first \a len bytes of \a data.
- The checksum is independent of the byte order (endianness).
+ The checksum is independent of the byte order (endianness) and will be
+ calculated accorded to the algorithm published in ISO 3309 (Qt::ChecksumIso3309).
\note This function is a 16-bit cache conserving (16 entry table)
implementation of the CRC-16-CCITT algorithm.
*/
-
quint16 qChecksum(const char *data, uint len)
{
- quint16 crc = 0xffff;
+ return qChecksum(data, len, Qt::ChecksumIso3309);
+}
+
+/*!
+ \relates QByteArray
+ \since 5.9
+
+ Returns the CRC-16 checksum of the first \a len bytes of \a data.
+
+ The checksum is independent of the byte order (endianness) and will
+ be calculated accorded to the algorithm published in \a standard.
+
+ \note This function is a 16-bit cache conserving (16 entry table)
+ implementation of the CRC-16-CCITT algorithm.
+*/
+quint16 qChecksum(const char *data, uint len, Qt::ChecksumType standard)
+{
+ quint16 crc = 0x0000;
+ switch (standard) {
+ case Qt::ChecksumIso3309:
+ crc = 0xffff;
+ break;
+ case Qt::ChecksumItuV41:
+ crc = 0x6363;
+ break;
+ }
uchar c;
const uchar *p = reinterpret_cast<const uchar *>(data);
while (len--) {
@@ -558,7 +583,14 @@ quint16 qChecksum(const char *data, uint len)
c >>= 4;
crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)];
}
- return ~crc & 0xffff;
+ switch (standard) {
+ case Qt::ChecksumIso3309:
+ crc = ~crc;
+ break;
+ case Qt::ChecksumItuV41:
+ break;
+ }
+ return crc & 0xffff;
}
/*!
@@ -663,6 +695,20 @@ QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel)
*/
#ifndef QT_NO_COMPRESS
+namespace {
+struct QByteArrayDataDeleter
+{
+ static inline void cleanup(QTypedArrayData<char> *d)
+ { if (d) QTypedArrayData<char>::deallocate(d); }
+};
+}
+
+static QByteArray invalidCompressedData()
+{
+ qWarning("qUncompress: Input data is corrupted");
+ return QByteArray();
+}
+
QByteArray qUncompress(const uchar* data, int nbytes)
{
if (!data) {
@@ -677,53 +723,29 @@ QByteArray qUncompress(const uchar* data, int nbytes)
ulong expectedSize = uint((data[0] << 24) | (data[1] << 16) |
(data[2] << 8) | (data[3] ));
ulong len = qMax(expectedSize, 1ul);
- QScopedPointer<QByteArray::Data, QScopedPointerPodDeleter> d;
+ const ulong maxPossibleSize = MaxAllocSize - sizeof(QByteArray::Data);
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ }
+
+ QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1));
+ if (Q_UNLIKELY(d.data() == nullptr))
+ return invalidCompressedData();
+ d->size = expectedSize;
forever {
ulong alloc = len;
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + alloc + 1));
- if (!p) {
- // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
- qWarning("qUncompress: could not allocate enough memory to uncompress data");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- d->offset = sizeof(QByteArrayData);
- d->size = 0; // Shut up valgrind "uninitialized variable" warning
int res = ::uncompress((uchar*)d->data(), &len,
data+4, nbytes-4);
switch (res) {
case Z_OK:
- if (len != alloc) {
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + len + 1));
- if (!p) {
- // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
- qWarning("qUncompress: could not allocate enough memory to uncompress data");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- }
- d->ref.initializeOwned();
+ Q_ASSERT(len <= alloc);
+ Q_UNUSED(alloc);
d->size = len;
- d->alloc = uint(len) + 1u;
- d->capacityReserved = false;
- d->offset = sizeof(QByteArrayData);
d->data()[len] = 0;
-
{
QByteArrayDataPtr dataPtr = { d.take() };
return QByteArray(dataPtr);
@@ -735,6 +757,17 @@ QByteArray qUncompress(const uchar* data, int nbytes)
case Z_BUF_ERROR:
len *= 2;
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ } else {
+ // grow the block
+ QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), len + 1);
+ if (Q_UNLIKELY(p == nullptr))
+ return invalidCompressedData();
+ d.take(); // don't free
+ d.reset(p);
+ }
continue;
case Z_DATA_ERROR:
@@ -1707,19 +1740,8 @@ void QByteArray::reallocData(uint alloc, Data::AllocationOptions options)
Data::deallocate(d);
d = x;
} else {
- size_t blockSize;
- if (options & Data::Grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
-
- Data *x = static_cast<Data *>(::realloc(d, blockSize));
+ Data *x = Data::reallocateUnaligned(d, alloc, options);
Q_CHECK_PTR(x);
- x->alloc = alloc;
- x->capacityReserved = (options & Data::CapacityReserved) ? 1 : 0;
d = x;
}
}
@@ -4365,12 +4387,41 @@ QByteArray QByteArray::fromHex(const QByteArray &hexEncoded)
*/
QByteArray QByteArray::toHex() const
{
- QByteArray hex(d->size * 2, Qt::Uninitialized);
+ return toHex('\0');
+}
+
+/*! \overload
+ \since 5.9
+
+ Returns a hex encoded copy of the byte array. The hex encoding uses the numbers 0-9 and
+ the letters a-f.
+
+ If \a separator is not '\0', the separator character is inserted between the hex bytes.
+
+ Example:
+ \code
+ QByteArray macAddress = QByteArray::fromHex("123456abcdef");
+ macAddress.toHex(':'); // returns "12:34:56:ab:cd:ef"
+ macAddress.toHex(0); // returns "123456abcdef"
+ \endcode
+
+ \sa fromHex()
+*/
+QByteArray QByteArray::toHex(char separator) const
+{
+ if (!d->size)
+ return QByteArray();
+
+ const int length = separator ? (d->size * 3 - 1) : (d->size * 2);
+ QByteArray hex(length, Qt::Uninitialized);
char *hexData = hex.data();
const uchar *data = (const uchar *)d->data();
- for (int i = 0; i < d->size; ++i) {
- hexData[i*2] = QtMiscUtils::toHexLower(data[i] >> 4);
- hexData[i*2+1] = QtMiscUtils::toHexLower(data[i] & 0xf);
+ for (int i = 0, o = 0; i < d->size; ++i) {
+ hexData[o++] = QtMiscUtils::toHexLower(data[i] >> 4);
+ hexData[o++] = QtMiscUtils::toHexLower(data[i] & 0xf);
+
+ if ((separator) && (o < length))
+ hexData[o++] = separator;
}
return hex;
}
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 477402d6de..06a50e5990 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -105,8 +105,8 @@ Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap);
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt, ...);
// qChecksum: Internet checksum
-
-Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len);
+Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len); // ### Qt 6: Remove
+Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len, Qt::ChecksumType standard); // ### Qt 6: Use Qt::ChecksumType standard = Qt::ChecksumIso3309
class QByteRef;
class QString;
@@ -140,8 +140,6 @@ struct QByteArrayDataPtr
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QByteArrayData)) \
/**/
-#if defined(Q_COMPILER_LAMBDA)
-
# define QByteArrayLiteral(str) \
([]() -> QByteArray { \
enum { Size = sizeof(str) - 1 }; \
@@ -154,14 +152,6 @@ struct QByteArrayDataPtr
}()) \
/**/
-#endif
-
-#ifndef QByteArrayLiteral
-// no lambdas, not GCC, just return a temporary QByteArray
-
-# define QByteArrayLiteral(str) QByteArray(str, sizeof(str) - 1)
-#endif
-
class Q_CORE_EXPORT QByteArray
{
private:
@@ -252,7 +242,7 @@ public:
void truncate(int pos);
void chop(int n);
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT")
@@ -357,6 +347,7 @@ public:
QByteArray toBase64(Base64Options options) const;
QByteArray toBase64() const; // ### Qt6 merge with previous
QByteArray toHex() const;
+ QByteArray toHex(char separator) const; // ### Qt6 merge with previous
QByteArray toPercentEncoding(const QByteArray &exclude = QByteArray(),
const QByteArray &include = QByteArray(),
char percent = '%') const;
diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp
index d06ca1292a..76af726ef9 100644
--- a/src/corelib/tools/qbytearraymatcher.cpp
+++ b/src/corelib/tools/qbytearraymatcher.cpp
@@ -323,4 +323,112 @@ int qFindByteArray(
return -1;
}
+/*!
+ \class QStaticByteArrayMatcherBase
+ \since 5.9
+ \internal
+ \brief Non-template base class of QStaticByteArrayMatcher.
+*/
+
+/*!
+ \class QStaticByteArrayMatcher
+ \since 5.9
+ \inmodule QtCore
+ \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher
+
+ \ingroup tools
+ \ingroup string-processing
+
+ This class is useful when you have a sequence of bytes that you
+ want to repeatedly match against some byte arrays (perhaps in a
+ loop), or when you want to search for the same sequence of bytes
+ multiple times in the same byte array. Using a matcher object and
+ indexIn() is faster than matching a plain QByteArray with
+ QByteArray::indexOf(), in particular if repeated matching takes place.
+
+ Unlike QByteArrayMatcher, this class calculates the internal
+ representation at \e{compile-time}, if your compiler supports
+ C++14-level \c{constexpr} (C++11 is not sufficient), so it can
+ even benefit if you are doing one-off byte array matches.
+
+ Create the QStaticByteArrayMatcher by calling qMakeStaticByteArrayMatcher(),
+ passing it the C string literal you want to search for. Store the return
+ value of that function in a \c{static const auto} variable, so you don't need
+ to pass the \c{N} template parameter explicitly:
+
+ \code
+ static const auto matcher = qMakeStaticByteArrayMatcher("needle");
+ \endcode
+
+ Then call indexIn() on the QByteArray in which you want to search, just like
+ with QByteArrayMatcher.
+
+ Since this class is designed to do all the up-front calculations at compile-time,
+ it does not offer a setPattern() method.
+
+ \sa QByteArrayMatcher, QStringMatcher
+*/
+
+/*!
+ \fn int QStaticByteArrayMatcher::indexIn(const char *haystack, int hlen, int from = 0) const
+
+ Searches the char string \a haystack, which has length \a hlen, from
+ byte position \a from (default 0, i.e. from the first byte), for
+ the byte array pattern() that was set in the constructor.
+
+ Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
+*/
+
+/*!
+ \fn int QStaticByteArrayMatcher::indexIn(const QByteArray &haystack, int from = 0) const
+
+ Searches the char string \a haystack, from byte position \a from
+ (default 0, i.e. from the first byte), for the byte array pattern()
+ that was set in the constructor.
+
+ Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
+*/
+
+/*!
+ \fn QByteArray QStaticByteArrayMatcher::pattern() const
+
+ Returns the byte array pattern that this byte array matcher will
+ search for.
+
+ \sa setPattern()
+*/
+
+/*!
+ \internal
+*/
+int QStaticByteArrayMatcherBase::indexOfIn(const char *needle, uint nlen, const char *haystack, int hlen, int from) const Q_DECL_NOTHROW
+{
+ if (from < 0)
+ from = 0;
+ return bm_find(reinterpret_cast<const uchar *>(haystack), hlen, from,
+ reinterpret_cast<const uchar *>(needle), nlen, m_skiptable.data);
+}
+
+/*!
+ \fn QStaticByteArrayMatcher::QStaticByteArrayMatcher(const char (&pattern)[N])
+ \internal
+*/
+
+/*!
+ \fn qMakeStaticByteArrayMatcher(const char (&pattern)[N])
+ \since 5.9
+ \relates QStaticByteArrayMatcher
+
+ Return a QStaticByteArrayMatcher with the correct \c{N} determined
+ automatically from the \a pattern passed.
+
+ To take full advantage of this function, assign the result to an
+ \c{auto} variable:
+
+ \code
+ static const auto matcher = qMakeStaticByteArrayMatcher("needle");
+ \endcode
+*/
+
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h
index aac62715a1..c1c0c3a660 100644
--- a/src/corelib/tools/qbytearraymatcher.h
+++ b/src/corelib/tools/qbytearraymatcher.h
@@ -83,6 +83,87 @@ private:
};
};
+class QStaticByteArrayMatcherBase
+{
+ Q_DECL_ALIGN(16)
+ struct Skiptable {
+ uchar data[256];
+ } m_skiptable;
+protected:
+ explicit Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcherBase(const char *pattern, uint n) Q_DECL_NOTHROW
+ : m_skiptable(generate(pattern, n)) {}
+ // compiler-generated copy/more ctors/assignment operators are ok!
+ // compiler-generated dtor is ok!
+
+ Q_CORE_EXPORT int indexOfIn(const char *needle, uint nlen, const char *haystack, int hlen, int from) const Q_DECL_NOTHROW;
+
+private:
+ static Q_DECL_RELAXED_CONSTEXPR Skiptable generate(const char *pattern, uint n) Q_DECL_NOTHROW
+ {
+ const auto uchar_max = (std::numeric_limits<uchar>::max)();
+ uchar max = n > uchar_max ? uchar_max : n;
+ Skiptable table = {
+ // this verbose initialization code aims to avoid some opaque error messages
+ // even on powerful compilers such as GCC 5.3. Even though for GCC a loop
+ // format can be found that v5.3 groks, it's probably better to go with this
+ // for the time being:
+ {
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ }
+ };
+ pattern += n - max;
+ while (max--)
+ table.data[uchar(*pattern++)] = max;
+ return table;
+ }
+};
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_MSVC(4351) // MSVC 2013: "new behavior: elements of array ... will be default initialized"
+ // remove once we drop MSVC 2013 support
+template <uint N>
+class QStaticByteArrayMatcher : QStaticByteArrayMatcherBase
+{
+ char m_pattern[N];
+ Q_STATIC_ASSERT_X(N > 2, "QStaticByteArrayMatcher makes no sense for finding a single-char pattern");
+public:
+ explicit Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcher(const char (&patternToMatch)[N]) Q_DECL_NOTHROW
+ : QStaticByteArrayMatcherBase(patternToMatch, N - 1), m_pattern()
+ {
+ for (uint i = 0; i < N; ++i)
+ m_pattern[i] = patternToMatch[i];
+ }
+
+ int indexIn(const QByteArray &haystack, int from = 0) const Q_DECL_NOTHROW
+ { return this->indexOfIn(m_pattern, N - 1, haystack.data(), haystack.size(), from); }
+ int indexIn(const char *haystack, int hlen, int from = 0) const Q_DECL_NOTHROW
+ { return this->indexOfIn(m_pattern, N - 1, haystack, hlen, from); }
+
+ QByteArray pattern() const { return QByteArray(m_pattern, int(N - 1)); }
+};
+
+QT_WARNING_POP
+
+template <uint N>
+Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcher<N> qMakeStaticByteArrayMatcher(const char (&pattern)[N]) Q_DECL_NOTHROW
+{ return QStaticByteArrayMatcher<N>(pattern); }
+
QT_END_NAMESPACE
#endif // QBYTEARRAYMATCHER_H
diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp
index 5f918aab0f..1d3293e85e 100644
--- a/src/corelib/tools/qchar.cpp
+++ b/src/corelib/tools/qchar.cpp
@@ -101,7 +101,7 @@ QT_BEGIN_NAMESPACE
In Qt, Unicode characters are 16-bit entities without any markup
or structure. This class represents such an entity. It is
lightweight, so it can be used everywhere. Most compilers treat
- it like a \c{unsigned short}.
+ it like an \c{unsigned short}.
QChar provides a full complement of testing/classification
functions, converting to and from other formats, converting from
@@ -424,7 +424,7 @@ QT_BEGIN_NAMESPACE
\enum QChar::Direction
This enum type defines the Unicode direction attributes. See the
- \l{http://www.unicode.org/}{Unicode Standard} for a description
+ \l{http://www.unicode.org/reports/tr9/tr9-35.html#Table_Bidirectional_Character_Types}{Unicode Standard} for a description
of the values.
In order to conform to C/C++ naming conventions "Dir" is prepended
diff --git a/src/corelib/tools/qcollator.h b/src/corelib/tools/qcollator.h
index 5ff74fd69a..d81c7c85e3 100644
--- a/src/corelib/tools/qcollator.h
+++ b/src/corelib/tools/qcollator.h
@@ -69,7 +69,7 @@ public:
protected:
QCollatorSortKey(QCollatorSortKeyPrivate*);
- QSharedDataPointer<QCollatorSortKeyPrivate> d;
+ QExplicitlySharedDataPointer<QCollatorSortKeyPrivate> d;
private:
QCollatorSortKey();
diff --git a/src/corelib/tools/qcollator_icu.cpp b/src/corelib/tools/qcollator_icu.cpp
index 1e94798c5b..ad98a187c5 100644
--- a/src/corelib/tools/qcollator_icu.cpp
+++ b/src/corelib/tools/qcollator_icu.cpp
@@ -39,6 +39,7 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
@@ -56,7 +57,7 @@ void QCollatorPrivate::init()
cleanup();
UErrorCode status = U_ZERO_ERROR;
- QByteArray name = locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')).toLatin1();
+ QByteArray name = QLocalePrivate::get(locale)->bcp47Name('_');
collator = ucol_open(name.constData(), &status);
if (U_FAILURE(status)) {
qWarning("Could not create collator: %d", status);
@@ -144,7 +145,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
string.size(), (uint8_t *)result.data(), result.size());
}
result.truncate(size);
- return QCollatorSortKey(new QCollatorSortKeyPrivate(result));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(result)));
}
return QCollatorSortKey(new QCollatorSortKeyPrivate(QByteArray()));
diff --git a/src/corelib/tools/qcollator_macx.cpp b/src/corelib/tools/qcollator_macx.cpp
index b4d93e58d4..d468272430 100644
--- a/src/corelib/tools/qcollator_macx.cpp
+++ b/src/corelib/tools/qcollator_macx.cpp
@@ -38,9 +38,12 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
+
#include <QtCore/private/qcore_mac_p.h>
+
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFLocale.h>
@@ -53,7 +56,7 @@ void QCollatorPrivate::init()
{
cleanup();
LocaleRef localeRef;
- int rc = LocaleRefFromLocaleString(locale.bcp47Name().toLocal8Bit(), &localeRef);
+ int rc = LocaleRefFromLocaleString(QLocalePrivate::get(locale)->bcp47Name().constData(), &localeRef);
if (rc != 0)
qWarning("couldn't initialize the locale");
@@ -128,7 +131,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
ret.size(), &actualSize, ret.data());
}
ret[actualSize] = 0;
- return QCollatorSortKey(new QCollatorSortKeyPrivate(ret));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(ret)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &key) const
diff --git a/src/corelib/tools/qcollator_p.h b/src/corelib/tools/qcollator_p.h
index 423ba0325a..c03a3431db 100644
--- a/src/corelib/tools/qcollator_p.h
+++ b/src/corelib/tools/qcollator_p.h
@@ -85,7 +85,7 @@ typedef QVector<wchar_t> CollatorKeyType;
typedef int CollatorType;
#endif
-class Q_CORE_EXPORT QCollatorPrivate
+class QCollatorPrivate
{
public:
QAtomicInt ref;
@@ -127,13 +127,14 @@ private:
Q_DISABLE_COPY(QCollatorPrivate)
};
-class Q_CORE_EXPORT QCollatorSortKeyPrivate : public QSharedData
+class QCollatorSortKeyPrivate : public QSharedData
{
friend class QCollator;
public:
- QCollatorSortKeyPrivate(const CollatorKeyType &key)
+ template <typename...T>
+ explicit QCollatorSortKeyPrivate(T &&...args)
: QSharedData()
- , m_key(key)
+ , m_key(std::forward<T>(args)...)
{
}
diff --git a/src/corelib/tools/qcollator_posix.cpp b/src/corelib/tools/qcollator_posix.cpp
index da424970e6..42413a4a82 100644
--- a/src/corelib/tools/qcollator_posix.cpp
+++ b/src/corelib/tools/qcollator_posix.cpp
@@ -110,7 +110,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
}
result.resize(size+1);
result[size] = 0;
- return QCollatorSortKey(new QCollatorSortKeyPrivate(result));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(result)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
diff --git a/src/corelib/tools/qcollator_win.cpp b/src/corelib/tools/qcollator_win.cpp
index fcd8d069eb..bce896278e 100644
--- a/src/corelib/tools/qcollator_win.cpp
+++ b/src/corelib/tools/qcollator_win.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
@@ -61,7 +62,7 @@ void QCollatorPrivate::init()
collator = 0;
#ifndef USE_COMPARESTRINGEX
- localeID = qt_inIsoNametoLCID(locale.bcp47Name().toUtf8().constData());
+ localeID = qt_inIsoNametoLCID(QLocalePrivate::get(locale)->bcp47Name().constData());
#else
localeName = locale.bcp47Name();
#endif
@@ -146,7 +147,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
if (finalSize == 0) {
qWarning() << "there were problems when generating the ::sortKey by LCMapStringW with error:" << GetLastError();
}
- return QCollatorSortKey(new QCollatorSortKeyPrivate(ret));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(ret)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index bf92be2dd4..bcdbc5af2a 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -929,7 +929,7 @@ QString QDate::toString(Qt::DateFormat format) const
*/
QString QDate::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -1333,6 +1333,7 @@ QDate QDate::fromString(const QString &string, const QString &format)
QDate date;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, &date, 0);
#else
@@ -1676,7 +1677,7 @@ QString QTime::toString(Qt::DateFormat format) const
*/
QString QTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
/*!
@@ -1970,7 +1971,7 @@ QTime QTime::fromString(const QString& string, Qt::DateFormat format)
case Qt::ISODateWithMs:
case Qt::TextDate:
default:
- return fromIsoTimeString(&string, format, 0);
+ return fromIsoTimeString(QStringRef(&string), format, 0);
}
}
@@ -2030,6 +2031,7 @@ QTime QTime::fromString(const QString &string, const QString &format)
QTime time;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, 0, &time);
#else
@@ -2285,10 +2287,11 @@ static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localT
tm local;
bool valid = false;
-#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
// localtime() is required to work as if tzset() was called before it.
// localtime_r() does not have this requirement, so make an explicit call.
+ // The explicit call should also request the timezone info be re-parsed.
qt_tzset();
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
// Use the reentrant version of localtime() where available
// as is thread-safe and doesn't use a shared static data area
tm *res = 0;
@@ -2574,6 +2577,13 @@ static inline Qt::TimeSpec getSpec(const QDateTimeData &d)
return extractSpec(getStatus(d));
}
+#if QT_CONFIG(timezone)
+void QDateTimePrivate::setUtcOffsetByTZ(qint64 atMSecsSinceEpoch)
+{
+ m_offsetFromUtc = m_timeZone.d->offsetFromUtc(atMSecsSinceEpoch);
+}
+#endif
+
// Refresh the LocalTime validity and offset
static void refreshDateTime(QDateTimeData &d)
{
@@ -2589,10 +2599,12 @@ static void refreshDateTime(QDateTimeData &d)
#if QT_CONFIG(timezone)
// If not valid time zone then is invalid
if (spec == Qt::TimeZone) {
- if (!d->m_timeZone.isValid())
+ if (!d->m_timeZone.isValid()) {
status &= ~QDateTimePrivate::ValidDateTime;
- else
- epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, &testDate, &testTime);
+ } else {
+ epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, extractDaylightStatus(status), &testDate, &testTime);
+ d->setUtcOffsetByTZ(epochMSecs);
+ }
}
#endif // timezone
@@ -2916,11 +2928,13 @@ inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime
}
// Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs
+// DST transitions are disambiguated by hint.
inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone,
+ DaylightStatus hint,
QDate *localDate, QTime *localTime)
{
// Get the effective data from QTimeZone
- QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs);
+ QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint));
// Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
// but all affected times afterwards will have DST applied.
if (data.atMSecsSinceEpoch >= 0) {
@@ -3533,7 +3547,8 @@ qint64 QDateTime::toMSecsSinceEpoch() const
#if !QT_CONFIG(timezone)
return 0;
#else
- return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone);
+ return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone,
+ extractDaylightStatus(getStatus(d)));
#endif
}
Q_UNREACHABLE();
@@ -3632,10 +3647,16 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
// Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
// but all affected times afterwards will have DST applied.
d.detach();
- if (msecs >= 0)
+ if (msecs >= 0) {
+ status = mergeDaylightStatus(status,
+ d->m_timeZone.d->isDaylightTime(msecs)
+ ? QDateTimePrivate::DaylightTime
+ : QDateTimePrivate::StandardTime);
d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs);
- else
+ } else {
+ status = mergeDaylightStatus(status, QDateTimePrivate::StandardTime);
d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(msecs);
+ }
msecs = msecs + (d->m_offsetFromUtc * 1000);
status = status
| QDateTimePrivate::ValidDate
@@ -3783,15 +3804,20 @@ QString QDateTime::toString(Qt::DateFormat format) const
#ifndef QT_NO_TEXTDATE
case Qt::TextDate: {
const QPair<QDate, QTime> p = getDateTime(d);
- const QDate &dt = p.first;
- const QTime &tm = p.second;
- //We cant use date.toString(Qt::TextDate) as we need to insert the time before the year
- buf = QString::fromLatin1("%1 %2 %3 %4 %5").arg(dt.shortDayName(dt.dayOfWeek()))
- .arg(dt.shortMonthName(dt.month()))
- .arg(dt.day())
- .arg(tm.toString(Qt::TextDate))
- .arg(dt.year());
- if (timeSpec() != Qt::LocalTime) {
+ buf = p.first.toString(Qt::TextDate);
+ // Insert time between date's day and year:
+ buf.insert(buf.lastIndexOf(QLatin1Char(' ')),
+ QLatin1Char(' ') + p.second.toString(Qt::TextDate));
+ // Append zone/offset indicator, as appropriate:
+ switch (timeSpec()) {
+ case Qt::LocalTime:
+ break;
+# if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+ buf += QLatin1Char(' ') + d->m_timeZone.abbreviation(*this);
+ break;
+# endif
+ default:
buf += QLatin1String(" GMT");
if (getSpec(d) == Qt::OffsetFromUTC)
buf += toOffsetString(Qt::TextDate, offsetFromUtc());
@@ -3814,6 +3840,9 @@ QString QDateTime::toString(Qt::DateFormat format) const
buf += QLatin1Char('Z');
break;
case Qt::OffsetFromUTC:
+#if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+#endif
buf += toOffsetString(Qt::ISODate, offsetFromUtc());
break;
default:
@@ -3899,7 +3928,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
*/
QString QDateTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -3923,7 +3952,10 @@ static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date,
localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time);
#if QT_CONFIG(timezone)
} else if (spec == Qt::TimeZone) {
- QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), d->m_timeZone, date, time);
+ QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time),
+ d->m_timeZone,
+ QDateTimePrivate::UnknownDaylightTime,
+ date, time);
#endif // timezone
}
}
@@ -4953,6 +4985,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format)
QDate date;
QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
return QDateTime(date, time);
#else
diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h
index eb33dddbb7..4d30d4192b 100644
--- a/src/corelib/tools/qdatetime_p.h
+++ b/src/corelib/tools/qdatetime_p.h
@@ -134,11 +134,12 @@ public:
#if QT_CONFIG(timezone)
static qint64 zoneMSecsToEpochMSecs(qint64 msecs, const QTimeZone &zone,
+ DaylightStatus hint = UnknownDaylightTime,
QDate *localDate = 0, QTime *localTime = 0);
-#endif // timezone
- static inline qint64 minJd() { return QDate::minJd(); }
- static inline qint64 maxJd() { return QDate::maxJd(); }
+ // Inlined for its one caller in qdatetime.cpp
+ inline void setUtcOffsetByTZ(qint64 atMSecsSinceEpoch);
+#endif // timezone
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index efed5d36ee..ba06de8f9e 100644
--- a/src/corelib/tools/qeasingcurve.h
+++ b/src/corelib/tools/qeasingcurve.h
@@ -125,7 +125,7 @@ private:
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QEasingCurve &);
#endif
};
-Q_DECLARE_TYPEINFO(QEasingCurve, Q_MOVABLE_TYPE);
+Q_DECLARE_SHARED(QEasingCurve)
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index abec9ebb79..334bd52f1e 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -199,14 +199,14 @@ static uint crc32(...)
}
#endif
-static inline uint hash(const uchar *p, int len, uint seed) Q_DECL_NOTHROW
+static inline uint hash(const uchar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
if (hasFastCrc32())
- return crc32(p, size_t(len), h);
+ return crc32(p, len, h);
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
h = 31 * h + p[i];
return h;
@@ -217,14 +217,14 @@ uint qHashBits(const void *p, size_t len, uint seed) Q_DECL_NOTHROW
return hash(static_cast<const uchar*>(p), int(len), seed);
}
-static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW
+static inline uint hash(const QChar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
if (hasFastCrc32())
- return crc32(p, size_t(len), h);
+ return crc32(p, len, h);
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
h = 31 * h + p[i].unicode();
return h;
@@ -232,23 +232,24 @@ static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW
uint qHash(const QByteArray &key, uint seed) Q_DECL_NOTHROW
{
- return hash(reinterpret_cast<const uchar *>(key.constData()), key.size(), seed);
+ return hash(reinterpret_cast<const uchar *>(key.constData()), size_t(key.size()), seed);
}
uint qHash(const QString &key, uint seed) Q_DECL_NOTHROW
{
- return hash(key.unicode(), key.size(), seed);
+ return hash(key.unicode(), size_t(key.size()), seed);
}
uint qHash(const QStringRef &key, uint seed) Q_DECL_NOTHROW
{
- return hash(key.unicode(), key.size(), seed);
+ return hash(key.unicode(), size_t(key.size()), seed);
}
uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW
{
int m = bitArray.d.size() - 1;
- uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()), qMax(0, m), seed);
+ uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()),
+ size_t(qMax(0, m)), seed);
// deal with the last 0 to 7 bits manually, because we can't trust that
// the padding is initialized to 0 in bitArray.d
@@ -260,7 +261,7 @@ uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW
uint qHash(QLatin1String key, uint seed) Q_DECL_NOTHROW
{
- return hash(reinterpret_cast<const uchar *>(key.data()), key.size(), seed);
+ return hash(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
}
/*!
@@ -324,7 +325,7 @@ static uint qt_create_qhash_seed()
/*
The QHash seed itself.
*/
-Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1);
+static QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1);
/*!
\internal
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 66b5e75a1a..c59f789cb2 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -432,6 +432,7 @@ public:
typedef const Key *pointer;
typedef const Key &reference;
+ key_iterator() = default;
explicit key_iterator(const_iterator o) : i(o) { }
const Key &operator*() const { return i.key(); }
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 5995be47a9..e2706de9ee 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -126,6 +126,7 @@ class QList
public:
struct MemoryLayout
: std::conditional<
+ // must stay isStatic until ### Qt 6 for BC reasons (don't use !isRelocatable)!
QTypeInfo<T>::isStatic || QTypeInfo<T>::isLarge,
QListData::IndirectLayout,
typename std::conditional<
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index c183224c82..bde4bf553e 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -972,7 +972,7 @@ QLocale::NumberOptions QLocale::numberOptions() const
*/
QString QLocale::quoteString(const QString &str, QuotationStyle style) const
{
- return quoteString(&str, style);
+ return quoteString(QStringRef(&str), style);
}
/*!
@@ -2058,6 +2058,8 @@ QString QLocale::toString(double i, char f, int prec) const
flags |= QLocaleData::ThousandsGroup;
if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
return d->m_data->doubleToString(i, prec, form, -1, flags);
}
@@ -2819,7 +2821,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
reinterpret_cast<ushort *>(digits.data())[i] += z;
}
- bool always_show_decpt = (flags & Alternate || flags & ForcePoint);
+ bool always_show_decpt = (flags & ForcePoint);
switch (form) {
case DFExponent: {
num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
@@ -2834,7 +2836,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
break;
}
case DFSignificantDigits: {
- PrecisionMode mode = (flags & Alternate) ?
+ PrecisionMode mode = (flags & AddTrailingZeroes) ?
PMSignificantDigits : PMChopTrailingZeros;
int cutoff = precision < 0 ? 6 : precision;
@@ -2889,7 +2891,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
num_str.prepend(QLatin1Char(' '));
if (flags & QLocaleData::CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
return num_str;
}
@@ -2939,7 +2941,7 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -2960,10 +2962,10 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
--num_pad_chars;
// leave space for optional '0x' in hex form
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && (flags & ShowBase))
num_pad_chars -= 2;
for (int i = 0; i < num_pad_chars; ++i)
@@ -2971,11 +2973,11 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
}
if (flags & CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- if (base == 2 && (flags & Alternate || flags & ShowBase))
+ if (base == 2 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -3024,7 +3026,7 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
if (zeroPadding > 0)
num_str.prepend(QString(zeroPadding, resultZero));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str.at(0).unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -3039,10 +3041,10 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
int num_pad_chars = width - num_str.length();
// leave space for optional '0x' in hex form
- if (base == 16 && flags & Alternate)
+ if (base == 16 && flags & ShowBase)
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && flags & Alternate)
+ else if (base == 2 && flags & ShowBase)
num_pad_chars -= 2;
if (num_pad_chars > 0)
@@ -3050,11 +3052,11 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
}
if (flags & CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -3115,25 +3117,37 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
out = in.toLatin1();
else
break;
+ } else if (out == '.') {
+ // Fail if more than one decimal point or point after e
+ if (decpt_idx != -1 || exponent_idx != -1)
+ return false;
+ decpt_idx = idx;
+ } else if (out == 'e' || out == 'E') {
+ exponent_idx = idx;
}
if (number_options & QLocale::RejectLeadingZeroInExponent) {
- if (out == 'e' || out == 'E') {
- exponent_idx = idx;
- } else if (exponent_idx != -1) {
- if (out >= '1' && out <= '9')
- exponent_idx = -1; // leading digit is not 0, forget exponent_idx
- else if (out == '0' && idx < l - 1)
+ if (exponent_idx != -1 && out == '0' && idx < l - 1) {
+ // After the exponent there can only be '+', '-' or digits.
+ // If we find a '0' directly after some non-digit, then that is a leading zero.
+ if (result->last() < '0' || result->last() > '9')
return false;
}
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // If we've seen a decimal point and the last character after the exponent is 0, then
+ // that is a trailing zero.
+ if (decpt_idx >= 0 && idx == exponent_idx && result->last() == '0')
+ return false;
+ }
+
if (!(number_options & QLocale::RejectGroupSeparator)) {
if (start_of_digits_idx == -1 && out >= '0' && out <= '9') {
start_of_digits_idx = idx;
} else if (out == ',') {
- // Don't allow group chars after the decimal point
- if (decpt_idx != -1)
+ // Don't allow group chars after the decimal point or exponent
+ if (decpt_idx != -1 || exponent_idx != -1)
return false;
// check distance from the last separator or from the beginning of the digits
@@ -3150,12 +3164,6 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
++idx;
continue;
} else if (out == '.' || out == 'e' || out == 'E') {
- // Fail if more than one decimal point
- if (out == '.' && decpt_idx != -1)
- return false;
- if (decpt_idx == -1)
- decpt_idx = idx;
-
// check distance from the last separator
// ### FIXME: Some locales allow other groupings! See https://en.wikipedia.org/wiki/Thousands_separator
if (last_separator_idx != -1 && idx - last_separator_idx != 4)
@@ -3181,6 +3189,12 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
return false;
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // In decimal form, the last character can be a trailing zero if we've seen a decpt.
+ if (decpt_idx != -1 && exponent_idx == -1 && result->last() == '0')
+ return false;
+ }
+
result->append('\0');
return idx == l;
}
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index 657fce9fa1..bd89e48234 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -897,7 +897,9 @@ public:
OmitGroupSeparator = 0x01,
RejectGroupSeparator = 0x02,
OmitLeadingZeroInExponent = 0x04,
- RejectLeadingZeroInExponent = 0x08
+ RejectLeadingZeroInExponent = 0x08,
+ IncludeTrailingZeroesAfterDot = 0x10,
+ RejectTrailingZeroesAfterDot = 0x20
};
Q_DECLARE_FLAGS(NumberOptions, NumberOption)
diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc
index 8c5711fb5e..d419172356 100644
--- a/src/corelib/tools/qlocale.qdoc
+++ b/src/corelib/tools/qlocale.qdoc
@@ -949,7 +949,8 @@
setNumberOptions().
\value DefaultNumberOptions This option represents the default behavior, with
- group separators and with one leading zero in single digit exponents.
+ group separators, with one leading zero in single digit exponents, and
+ without trailing zeroes after the decimal dot.
\value OmitGroupSeparator If this option is set, the number-to-string functions
will not insert group separators in their return values. The default
is to insert group separators.
@@ -964,6 +965,14 @@
functions will fail if they encounter an exponent padded with zeroes when
parsing a floating point number in scientific notation. The default is to
accept such padding.
+ \value IncludeTrailingZeroesAfterDot If this option is set, the number-to-string
+ functions will pad numbers with zeroes to the requested precision in "g"
+ or "most concise" mode, even if the number of significant digits is lower
+ than the requested precision. The default is to omit trailing zeroes.
+ \value RejectTrailingZeroesAfterDot If this option is set, the string-to-number
+ functions will fail if they encounter trailing zeroes after the decimal
+ dot when parsing a number in scientific or decimal representation. The
+ default is to accept trailing zeroes.
\sa setNumberOptions(), numberOptions()
*/
diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm
index 8587716446..c5519bfabf 100644
--- a/src/corelib/tools/qlocale_mac.mm
+++ b/src/corelib/tools/qlocale_mac.mm
@@ -43,9 +43,11 @@
#include "qvariant.h"
#include "qdatetime.h"
-#if !defined(QWS) && defined(Q_OS_MAC)
-# include "private/qcore_mac_p.h"
-# include <CoreFoundation/CoreFoundation.h>
+#ifdef Q_OS_DARWIN
+#include "qtimezone.h"
+#include "private/qcore_mac_p.h"
+#include <CoreFoundation/CoreFoundation.h>
+QT_REQUIRE_CONFIG(timezone);
#endif
QT_BEGIN_NAMESPACE
@@ -121,16 +123,7 @@ static QString macDayName(int day, bool short_format)
static QString macDateToString(const QDate &date, bool short_format)
{
- CFGregorianDate macGDate;
- macGDate.year = date.year();
- macGDate.month = date.month();
- macGDate.day = date.day();
- macGDate.hour = 0;
- macGDate.minute = 0;
- macGDate.second = 0.0;
- QCFType<CFDateRef> myDate
- = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
- QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
+ QCFType<CFDateRef> myDate = QDateTime(date, QTime()).toCFDate();
QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle;
QCFType<CFDateFormatterRef> myFormatter
@@ -142,19 +135,7 @@ static QString macDateToString(const QDate &date, bool short_format)
static QString macTimeToString(const QTime &time, bool short_format)
{
- CFGregorianDate macGDate;
- // Assume this is local time and the current date
- QDate dt = QDate::currentDate();
- macGDate.year = dt.year();
- macGDate.month = dt.month();
- macGDate.day = dt.day();
- macGDate.hour = time.hour();
- macGDate.minute = time.minute();
- macGDate.second = time.second();
- QCFType<CFDateRef> myDate
- = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
- QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
-
+ QCFType<CFDateRef> myDate = QDateTime(QDate::currentDate(), time).toCFDate();
QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle;
QCFType<CFDateFormatterRef> myFormatter = CFDateFormatterCreate(kCFAllocatorDefault,
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index 20eff8fd64..f7adb021b6 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -193,7 +193,7 @@ public:
enum Flags {
NoFlags = 0,
- Alternate = 0x01,
+ AddTrailingZeroes = 0x01,
ZeroPadded = 0x02,
LeftAdjusted = 0x04,
BlankBeforePositive = 0x08,
@@ -204,7 +204,7 @@ public:
ShowBase = 0x80,
UppercaseBase = 0x100,
ZeroPadExponent = 0x200,
- ForcePoint = Alternate
+ ForcePoint = 0x400
};
enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode };
@@ -332,6 +332,9 @@ public:
return retval;
}
+ static QLocalePrivate *get(QLocale &l) { return l.d; }
+ static const QLocalePrivate *get(const QLocale &l) { return l.d; }
+
QChar decimal() const { return QChar(m_data->m_decimal); }
QChar group() const { return QChar(m_data->m_group); }
QChar list() const { return QChar(m_data->m_list); }
diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp
index b5f97b5fe8..2475859abd 100644
--- a/src/corelib/tools/qlocale_win.cpp
+++ b/src/corelib/tools/qlocale_win.cpp
@@ -691,7 +691,7 @@ QString QSystemLocalePrivate::winToQtFormat(const QString &sys_fmt)
if (text == QLatin1String("'"))
result += QLatin1String("''");
else
- result += QString(QLatin1Char('\'') + text + QLatin1Char('\''));
+ result += QLatin1Char('\'') + text + QLatin1Char('\'');
continue;
}
@@ -1037,7 +1037,7 @@ static QString winIso639LangName(LPWSTR id)
if (!lang_code.isEmpty()) {
const char *endptr;
bool ok;
- QByteArray latin1_lang_code = lang_code.toLatin1();
+ QByteArray latin1_lang_code = std::move(lang_code).toLatin1();
int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok);
if (ok && *endptr == '\0') {
switch (i) {
@@ -1120,15 +1120,12 @@ static QByteArray getWinLocaleName(LPWSTR id)
id = lcName;
}
#endif // Q_OS_WINRT
- QString resultuage = winIso639LangName(id);
+ QString resultusage = winIso639LangName(id);
QString country = winIso3116CtryName(id);
- result = resultuage.toLatin1();
- if (!country.isEmpty()) {
- result += '_';
- result += country.toLatin1();
- }
+ if (!country.isEmpty())
+ resultusage += QLatin1Char('_') + country;
- return result;
+ return std::move(resultusage).toLatin1();
}
Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index da77ba4458..a3b11eddcf 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -99,10 +99,10 @@ struct Q_CORE_EXPORT QMapNodeBase
void setParent(QMapNodeBase *pp) { p = (p & Mask) | quintptr(pp); }
template <typename T>
- static typename QtPrivate::QEnableIf<QTypeInfo<T>::isComplex>::Type
+ static typename std::enable_if<QTypeInfo<T>::isComplex>::type
callDestructorIfNecessary(T &t) Q_DECL_NOTHROW { Q_UNUSED(t); t.~T(); } // Q_UNUSED: silence MSVC unused 't' warning
template <typename T>
- static typename QtPrivate::QEnableIf<!QTypeInfo<T>::isComplex>::Type
+ static typename std::enable_if<!QTypeInfo<T>::isComplex>::type
callDestructorIfNecessary(T &) Q_DECL_NOTHROW {}
};
@@ -533,6 +533,7 @@ public:
typedef const Key *pointer;
typedef const Key &reference;
+ key_iterator() = default;
explicit key_iterator(const_iterator o) : i(o) { }
const Key &operator*() const { return i.key(); }
diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp
index 4a30daa72c..88b696f53a 100644
--- a/src/corelib/tools/qregularexpression.cpp
+++ b/src/corelib/tools/qregularexpression.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>.
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+** 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) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -45,7 +45,7 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qhashfunctions.h>
-#include <QtCore/qmutex.h>
+#include <QtCore/qreadwritelock.h>
#include <QtCore/qvector.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qdebug.h>
@@ -54,7 +54,9 @@
#include <QtCore/qatomic.h>
#include <QtCore/qdatastream.h>
-#include <pcre.h>
+#define PCRE2_CODE_UNIT_WIDTH 16
+
+#include <pcre2.h>
QT_BEGIN_NAMESPACE
@@ -443,19 +445,25 @@ QT_BEGIN_NAMESPACE
Other differences are outlined below.
- \section2 Exact matching
+ \section2 Porting from QRegExp::exactMatch()
QRegExp::exactMatch() in Qt 4 served two purposes: it exactly matched
a regular expression against a subject string, and it implemented partial
- matching. In fact, if an exact match was not found, one could still find
- out how much of the subject string was matched by the regular expression
- by calling QRegExp::matchedLength(). If the returned length was equal
- to the subject string's length, then one could desume that a partial match
- was found.
+ matching.
- QRegularExpression supports partial matching explicitly by means of the
- appropriate MatchType. If instead you simply want to be sure that the
- subject string matches the regular expression exactly, you can wrap the
+ \section3 Porting from QRegExp's Exact Matching
+
+ Exact matching indicates whether the regular expression matches the entire
+ subject string. For example, the classes yield on the subject string \c{"abc123"}:
+
+ \table
+ \header \li \li QRegExp::exactMatch() \li QRegularExpressionMatch::hasMatch()
+ \row \li \c{"\\d+"} \li \b false \li \b true
+ \row \li \c{"[a-z]+\\d+"} \li \b true \li \b true
+ \endtable
+
+ Exact matching is not reflected in QRegularExpression. If you want to be
+ sure that the subject string matches the regular expression exactly, you can wrap the
pattern between a couple of anchoring expressions. Simply
putting the pattern between the \c{^} and the \c{$} anchors is enough
in most cases:
@@ -477,6 +485,17 @@ QT_BEGIN_NAMESPACE
Note the usage of the non-capturing group in order to preserve the meaning
of the branch operator inside the pattern.
+ \section3 Porting from QRegExp's Partial Matching
+
+ When using QRegExp::exactMatch(), if an exact match was not found, one
+ could still find out how much of the subject string was matched by the
+ regular expression by calling QRegExp::matchedLength(). If the returned length
+ was equal to the subject string's length, then one could conclude that a partial
+ match was found.
+
+ QRegularExpression supports partial matching explicitly by means of the
+ appropriate MatchType.
+
\section2 Global matching
Due to limitations of the QRegExp API it was impossible to implement global
@@ -548,7 +567,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\reentrant
- \brief The QRegularExpressionMatch class provides the results of matching
+ \brief The QRegularExpressionMatch class provides the results of a matching
a QRegularExpression against a string.
\since 5.0
@@ -789,19 +808,19 @@ static int convertToPcreOptions(QRegularExpression::PatternOptions patternOption
int options = 0;
if (patternOptions & QRegularExpression::CaseInsensitiveOption)
- options |= PCRE_CASELESS;
+ options |= PCRE2_CASELESS;
if (patternOptions & QRegularExpression::DotMatchesEverythingOption)
- options |= PCRE_DOTALL;
+ options |= PCRE2_DOTALL;
if (patternOptions & QRegularExpression::MultilineOption)
- options |= PCRE_MULTILINE;
+ options |= PCRE2_MULTILINE;
if (patternOptions & QRegularExpression::ExtendedPatternSyntaxOption)
- options |= PCRE_EXTENDED;
+ options |= PCRE2_EXTENDED;
if (patternOptions & QRegularExpression::InvertedGreedinessOption)
- options |= PCRE_UNGREEDY;
+ options |= PCRE2_UNGREEDY;
if (patternOptions & QRegularExpression::DontCaptureOption)
- options |= PCRE_NO_AUTO_CAPTURE;
+ options |= PCRE2_NO_AUTO_CAPTURE;
if (patternOptions & QRegularExpression::UseUnicodePropertiesOption)
- options |= PCRE_UCP;
+ options |= PCRE2_UCP;
return options;
}
@@ -814,7 +833,9 @@ static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
int options = 0;
if (matchOptions & QRegularExpression::AnchoredMatchOption)
- options |= PCRE_ANCHORED;
+ options |= PCRE2_ANCHORED;
+ if (matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption)
+ options |= PCRE2_NO_UTF_CHECK;
return options;
}
@@ -856,20 +877,16 @@ struct QRegularExpressionPrivate : QSharedData
QRegularExpression::PatternOptions patternOptions;
QString pattern;
- // *All* of the following members are set managed while holding this mutex,
+ // *All* of the following members are managed while holding this mutex,
// except for isDirty which is set to true by QRegularExpression setters
// (right after a detach happened).
- // On the other hand, after the compilation and studying,
- // it's safe to *use* (i.e. read) them from multiple threads at the same time.
- // Therefore, doMatch doesn't need to lock this mutex.
- QMutex mutex;
+ mutable QReadWriteLock mutex;
- // The PCRE pointers are reference-counted by the QRegularExpressionPrivate
+ // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
// objects themselves; when the private is copied (i.e. a detach happened)
// they are set to 0
- pcre16 *compiledPattern;
- QAtomicPointer<pcre16_extra> studyData;
- const char *errorString;
+ pcre2_code_16 *compiledPattern;
+ int errorCode;
int errorOffset;
int capturingCount;
unsigned int usedCount;
@@ -884,8 +901,7 @@ struct QRegularExpressionMatchPrivate : QSharedData
int subjectStart,
int subjectLength,
QRegularExpression::MatchType matchType,
- QRegularExpression::MatchOptions matchOptions,
- int capturingCount = 0);
+ QRegularExpression::MatchOptions matchOptions);
QRegularExpressionMatch nextMatch() const;
@@ -934,10 +950,13 @@ QRegularExpression::QRegularExpression(QRegularExpressionPrivate &dd)
\internal
*/
QRegularExpressionPrivate::QRegularExpressionPrivate()
- : patternOptions(0), pattern(),
+ : QSharedData(),
+ patternOptions(0),
+ pattern(),
mutex(),
- compiledPattern(0), studyData(0),
- errorString(0), errorOffset(-1),
+ compiledPattern(0),
+ errorCode(0),
+ errorOffset(-1),
capturingCount(0),
usedCount(0),
usingCrLfNewlines(false),
@@ -964,13 +983,16 @@ QRegularExpressionPrivate::~QRegularExpressionPrivate()
*/
QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPrivate &other)
: QSharedData(other),
- patternOptions(other.patternOptions), pattern(other.pattern),
+ patternOptions(other.patternOptions),
+ pattern(other.pattern),
mutex(),
- compiledPattern(0), studyData(0),
- errorString(0),
- errorOffset(-1), capturingCount(0),
+ compiledPattern(0),
+ errorCode(0),
+ errorOffset(-1),
+ capturingCount(0),
usedCount(0),
- usingCrLfNewlines(false), isDirty(true)
+ usingCrLfNewlines(false),
+ isDirty(true)
{
}
@@ -979,14 +1001,13 @@ QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPri
*/
void QRegularExpressionPrivate::cleanCompiledPattern()
{
- pcre16_free(compiledPattern);
- pcre16_free_study(studyData.load());
- usedCount = 0;
+ pcre2_code_free_16(compiledPattern);
compiledPattern = 0;
- studyData.store(0);
- usingCrLfNewlines = false;
+ errorCode = 0;
errorOffset = -1;
capturingCount = 0;
+ usedCount = 0;
+ usingCrLfNewlines = false;
}
/*!
@@ -994,7 +1015,7 @@ void QRegularExpressionPrivate::cleanCompiledPattern()
*/
void QRegularExpressionPrivate::compilePattern()
{
- QMutexLocker lock(&mutex);
+ const QWriteLocker lock(&mutex);
if (!isDirty)
return;
@@ -1003,18 +1024,23 @@ void QRegularExpressionPrivate::compilePattern()
cleanCompiledPattern();
int options = convertToPcreOptions(patternOptions);
- options |= PCRE_UTF16;
+ options |= PCRE2_UTF;
- int errorCode;
- compiledPattern = pcre16_compile2(pattern.utf16(), options,
- &errorCode, &errorString, &errorOffset, 0);
+ PCRE2_SIZE patternErrorOffset;
+ compiledPattern = pcre2_compile_16(pattern.utf16(),
+ pattern.length(),
+ options,
+ &errorCode,
+ &patternErrorOffset,
+ NULL);
- if (!compiledPattern)
+ if (!compiledPattern) {
+ errorOffset = static_cast<int>(patternErrorOffset);
return;
-
- Q_ASSERT(errorCode == 0);
- Q_ASSERT(studyData.load() == 0); // studying (=>optimizing) is always done later
- errorOffset = -1;
+ } else {
+ // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
+ errorCode = 0;
+ }
getPatternInfo();
}
@@ -1025,53 +1051,31 @@ void QRegularExpressionPrivate::compilePattern()
void QRegularExpressionPrivate::getPatternInfo()
{
Q_ASSERT(compiledPattern);
- Q_ASSERT(studyData.load() == 0);
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_CAPTURECOUNT, &capturingCount);
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
// detect the settings for the newline
- unsigned long int patternNewlineSetting;
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_OPTIONS, &patternNewlineSetting);
- patternNewlineSetting &= PCRE_NEWLINE_CR | PCRE_NEWLINE_LF | PCRE_NEWLINE_CRLF
- | PCRE_NEWLINE_ANY | PCRE_NEWLINE_ANYCRLF;
- if (patternNewlineSetting == 0) {
+ unsigned int patternNewlineSetting;
+ if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
// no option was specified in the regexp, grab PCRE build defaults
- int pcreNewlineSetting;
- pcre16_config(PCRE_CONFIG_NEWLINE, &pcreNewlineSetting);
- switch (pcreNewlineSetting) {
- case 13:
- patternNewlineSetting = PCRE_NEWLINE_CR; break;
- case 10:
- patternNewlineSetting = PCRE_NEWLINE_LF; break;
- case 3338: // (13<<8 | 10)
- patternNewlineSetting = PCRE_NEWLINE_CRLF; break;
- case -2:
- patternNewlineSetting = PCRE_NEWLINE_ANYCRLF; break;
- case -1:
- patternNewlineSetting = PCRE_NEWLINE_ANY; break;
- default:
- qWarning("QRegularExpressionPrivate::compilePattern(): "
- "PCRE_CONFIG_NEWLINE returned an unknown newline");
- break;
- }
+ pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
}
- usingCrLfNewlines = (patternNewlineSetting == PCRE_NEWLINE_CRLF) ||
- (patternNewlineSetting == PCRE_NEWLINE_ANY) ||
- (patternNewlineSetting == PCRE_NEWLINE_ANYCRLF);
+ usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
+ (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
+ (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
- int hasJOptionChanged;
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_JCHANGED, &hasJOptionChanged);
- if (hasJOptionChanged) {
- qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%s'\n"
- " is using the (?J) option; duplicate capturing group names are not supported by Qt",
+ unsigned int hasJOptionChanged;
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
+ if (Q_UNLIKELY(hasJOptionChanged)) {
+ qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%s'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
qPrintable(pattern));
}
}
/*
- Simple "smartpointer" wrapper around a pcre_jit_stack, to be used with
+ Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
QThreadStorage.
*/
class QPcreJitStackPointer
@@ -1086,7 +1090,7 @@ public:
{
// The default JIT stack size in PCRE is 32K,
// we allocate from 32K up to 512K.
- stack = pcre16_jit_stack_alloc(32*1024, 512*1024);
+ stack = pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL);
}
/*!
\internal
@@ -1094,10 +1098,10 @@ public:
~QPcreJitStackPointer()
{
if (stack)
- pcre16_jit_stack_free(stack);
+ pcre2_jit_stack_free_16(stack);
}
- pcre16_jit_stack *stack;
+ pcre2_jit_stack_16 *stack;
};
Q_GLOBAL_STATIC(QThreadStorage<QPcreJitStackPointer *>, jitStacks)
@@ -1105,7 +1109,7 @@ Q_GLOBAL_STATIC(QThreadStorage<QPcreJitStackPointer *>, jitStacks)
/*!
\internal
*/
-static pcre16_jit_stack *qtPcreCallback(void *)
+static pcre2_jit_stack_16 *qtPcreCallback(void *)
{
if (jitStacks()->hasLocalData())
return jitStacks()->localData()->stack;
@@ -1135,53 +1139,32 @@ static bool isJitEnabled()
/*!
\internal
- The purpose of the function is to call pcre16_study (which allows some
- optimizations to be performed, including JIT-compiling the pattern), and
- setting the studyData member variable to the result of the study. It gets
- called by doMatch() every time a match is performed. As of now, the
- optimizations on the pattern are performed after a certain number of usages
- (i.e. the qt_qregularexpression_optimize_after_use_count constant) unless
- the DontAutomaticallyOptimizeOption option is set on the QRegularExpression
- object, or anyhow by calling optimize() (which will pass
- ImmediateOptimizeOption).
+ The purpose of the function is to call pcre2_jit_compile_16, which
+ JIT-compiles the pattern.
- Notice that although the method is protected by a mutex, one thread may
- invoke this function and return immediately (i.e. not study the pattern,
- leaving studyData to NULL); but before calling pcre16_exec to perform the
- match, another thread performs the studying and sets studyData to something
- else. Although the assignment to studyData is itself atomic, the release of
- the memory pointed by studyData isn't. Therefore, we work on a local copy
- (localStudyData) before using storeRelease on studyData. In doMatch there's
- the corresponding loadAcquire.
+ It gets called by doMatch() every time a match is performed.
+
+ As of now, the optimizations on the pattern are performed after a certain
+ number of usages (i.e. the qt_qregularexpression_optimize_after_use_count
+ constant) unless the DontAutomaticallyOptimizeOption option is set on the
+ QRegularExpression object, or anyhow by calling optimize() (which will pass
+ ImmediateOptimizeOption).
*/
void QRegularExpressionPrivate::optimizePattern(OptimizePatternOption option)
{
Q_ASSERT(compiledPattern);
- QMutexLocker lock(&mutex);
+ static const bool enableJit = isJitEnabled();
- if (studyData.load()) // already optimized
+ if (!enableJit)
return;
+ const QWriteLocker lock(&mutex);
+
if ((option == LazyOptimizeOption) && (++usedCount != qt_qregularexpression_optimize_after_use_count))
return;
- static const bool enableJit = isJitEnabled();
-
- int studyOptions = 0;
- if (enableJit)
- studyOptions |= (PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE);
-
- const char *err;
- pcre16_extra * const localStudyData = pcre16_study(compiledPattern, studyOptions, &err);
-
- if (localStudyData && localStudyData->flags & PCRE_EXTRA_EXECUTABLE_JIT)
- pcre16_assign_jit_stack(localStudyData, qtPcreCallback, 0);
-
- if (!localStudyData && err)
- qWarning("QRegularExpressionPrivate::optimizePattern(): pcre_study failed: %s", err);
-
- studyData.storeRelease(localStudyData);
+ pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
}
/*!
@@ -1197,7 +1180,7 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const
if (!compiledPattern)
return -1;
- int index = pcre16_get_stringnumber(compiledPattern, name.utf16());
+ int index = pcre2_substring_number_from_name_16(compiledPattern, name.utf16());
if (index >= 0)
return index;
@@ -1207,24 +1190,25 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const
/*!
\internal
- This is a simple wrapper for pcre16_exec for handling the case in which the
+ This is a simple wrapper for pcre2_match_16 for handling the case in which the
JIT runs out of memory. In that case, we allocate a thread-local JIT stack
- and re-run pcre16_exec.
+ and re-run pcre2_match_16.
*/
-static int pcre16SafeExec(const pcre16 *code, const pcre16_extra *extra,
- const unsigned short *subject, int length,
- int startOffset, int options,
- int *ovector, int ovecsize)
+static int safe_pcre2_match_16(const pcre2_code_16 *code,
+ const unsigned short *subject, int length,
+ int startOffset, int options,
+ pcre2_match_data_16 *matchData,
+ pcre2_match_context_16 *matchContext)
{
- int result = pcre16_exec(code, extra, subject, length,
- startOffset, options, ovector, ovecsize);
+ int result = pcre2_match_16(code, subject, length,
+ startOffset, options, matchData, matchContext);
- if (result == PCRE_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) {
+ if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) {
QPcreJitStackPointer *p = new QPcreJitStackPointer;
jitStacks()->setLocalData(p);
- result = pcre16_exec(code, extra, subject, length,
- startOffset, options, ovector, ovecsize);
+ result = pcre2_match_16(code, subject, length,
+ startOffset, options, matchData, matchContext);
}
return result;
@@ -1273,29 +1257,24 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
QRegularExpression re(*const_cast<QRegularExpressionPrivate *>(this));
+ QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
+ subjectStart, subjectLength,
+ matchType, matchOptions);
+
if (offset < 0 || offset > subjectLength)
- return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions);
+ return priv;
- if (!compiledPattern) {
+ if (Q_UNLIKELY(!compiledPattern)) {
qWarning("QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object");
- return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions);
+ return priv;
}
// skip optimizing and doing the actual matching if NoMatch type was requested
if (matchType == QRegularExpression::NoMatch) {
- QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
- subjectStart, subjectLength,
- matchType, matchOptions);
priv->isValid = true;
return priv;
}
- // capturingCount doesn't include the implicit "0" capturing group
- QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
- subjectStart, subjectLength,
- matchType, matchOptions,
- capturingCount + 1);
-
if (!(patternOptions & QRegularExpression::DontAutomaticallyOptimizeOption)) {
const OptimizePatternOption optimizePatternOption =
(patternOptions & QRegularExpression::OptimizeOnFirstUsageOption)
@@ -1306,22 +1285,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
const_cast<QRegularExpressionPrivate *>(this)->optimizePattern(optimizePatternOption);
}
- // work with a local copy of the study data, as we are running pcre_exec
- // potentially more than once, and we don't want to run call it
- // with different study data
- const pcre16_extra * const currentStudyData = studyData.loadAcquire();
-
int pcreOptions = convertToPcreOptions(matchOptions);
if (matchType == QRegularExpression::PartialPreferCompleteMatch)
- pcreOptions |= PCRE_PARTIAL_SOFT;
+ pcreOptions |= PCRE2_PARTIAL_SOFT;
else if (matchType == QRegularExpression::PartialPreferFirstMatch)
- pcreOptions |= PCRE_PARTIAL_HARD;
+ pcreOptions |= PCRE2_PARTIAL_HARD;
- if (checkSubjectStringOption == DontCheckSubjectString
- || matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption) {
- pcreOptions |= PCRE_NO_UTF16_CHECK;
- }
+ if (checkSubjectStringOption == DontCheckSubjectString)
+ pcreOptions |= PCRE2_NO_UTF_CHECK;
bool previousMatchWasEmpty = false;
if (previous && previous->hasMatch &&
@@ -1329,25 +1301,28 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
previousMatchWasEmpty = true;
}
- int * const captureOffsets = priv->capturedOffsets.data();
- const int captureOffsetsCount = priv->capturedOffsets.size();
+ 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);
const unsigned short * const subjectUtf16 = subject.utf16() + subjectStart;
int result;
+ QReadLocker lock(&mutex);
+
if (!previousMatchWasEmpty) {
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
+ matchData, matchContext);
} else {
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
+ matchData, matchContext);
- if (result == PCRE_ERROR_NOMATCH) {
+ if (result == PCRE2_ERROR_NOMATCH) {
++offset;
if (usingCrLfNewlines
@@ -1360,13 +1335,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
++offset;
}
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
+ matchData, matchContext);
}
}
+ lock.unlock();
+
#ifdef QREGULAREXPRESSION_DEBUG
qDebug() << "Matching" << pattern << "against" << subject
<< "starting at" << subjectStart << "len" << subjectLength
@@ -1386,10 +1363,10 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
priv->capturedOffsets.resize(result * 2);
} else {
// no match, partial match or error
- priv->hasPartialMatch = (result == PCRE_ERROR_PARTIAL);
- priv->isValid = (result == PCRE_ERROR_NOMATCH || result == PCRE_ERROR_PARTIAL);
+ priv->hasPartialMatch = (result == PCRE2_ERROR_PARTIAL);
+ priv->isValid = (result == PCRE2_ERROR_NOMATCH || result == PCRE2_ERROR_PARTIAL);
- if (result == PCRE_ERROR_PARTIAL) {
+ if (result == PCRE2_ERROR_PARTIAL) {
// partial match:
// leave the start and end capture offsets (i.e. cap(0))
priv->capturedCount = 1;
@@ -1401,6 +1378,35 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
}
}
+ // copy the captured substrings offsets, if any
+ if (priv->capturedCount) {
+ PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
+ int * const capturedOffsets = priv->capturedOffsets.data();
+
+ for (int i = 0; i < priv->capturedCount * 2; ++i)
+ capturedOffsets[i] = static_cast<int>(ovector[i]);
+
+ // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
+ // are involved. PCRE2 reports the real begin of the match and the maximum
+ // used lookbehind as distinct information; PCRE1 instead automatically
+ // adjusted ovector[0] to include the maximum lookbehind.
+ //
+ // For instance, given the pattern "\bstring\b", and the subject "a str":
+ // * PCRE1 reports partial, capturing " str"
+ // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
+ //
+ // To keep behavior, emulate PCRE1 here.
+ // (Eventually, we could expose the lookbehind info in a future patch.)
+ if (result == PCRE2_ERROR_PARTIAL) {
+ unsigned int maximumLookBehind;
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
+ capturedOffsets[0] -= maximumLookBehind;
+ }
+ }
+
+ pcre2_match_data_free_16(matchData);
+ pcre2_match_context_free_16(matchContext);
+
return priv;
}
@@ -1412,19 +1418,13 @@ QRegularExpressionMatchPrivate::QRegularExpressionMatchPrivate(const QRegularExp
int subjectStart,
int subjectLength,
QRegularExpression::MatchType matchType,
- QRegularExpression::MatchOptions matchOptions,
- int capturingCount)
+ QRegularExpression::MatchOptions matchOptions)
: regularExpression(re), subject(subject),
subjectStart(subjectStart), subjectLength(subjectLength),
matchType(matchType), matchOptions(matchOptions),
capturedCount(0),
hasMatch(false), hasPartialMatch(false), isValid(false)
{
- Q_ASSERT(capturingCount >= 0);
- if (capturingCount > 0) {
- const int captureOffsetsCount = capturingCount * 3;
- capturedOffsets.resize(captureOffsetsCount);
- }
}
@@ -1632,13 +1632,13 @@ QStringList QRegularExpression::namedCaptureGroups() const
// contains one ushort followed by the name, NUL terminated.
// The ushort is the numerical index of the name in the pattern.
// The length of each entry is namedCapturingTableEntrySize.
- ushort *namedCapturingTable;
- int namedCapturingTableEntryCount;
- int namedCapturingTableEntrySize;
+ PCRE2_SPTR16 *namedCapturingTable;
+ unsigned int namedCapturingTableEntryCount;
+ unsigned int namedCapturingTableEntrySize;
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMETABLE, &namedCapturingTable);
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
QStringList result;
@@ -1647,9 +1647,9 @@ QStringList QRegularExpression::namedCaptureGroups() const
for (int i = 0; i < d->capturingCount + 1; ++i)
result.append(QString());
- for (int i = 0; i < namedCapturingTableEntryCount; ++i) {
- const ushort * const currentNamedCapturingTableRow = namedCapturingTable +
- namedCapturingTableEntrySize * i;
+ for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
+ const ushort * const currentNamedCapturingTableRow =
+ reinterpret_cast<const ushort *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
const int index = *currentNamedCapturingTableRow;
result[index] = QString::fromUtf16(currentNamedCapturingTableRow + 1);
@@ -1680,8 +1680,19 @@ bool QRegularExpression::isValid() const
QString QRegularExpression::errorString() const
{
d.data()->compilePattern();
- if (d->errorString)
- return QCoreApplication::translate("QRegularExpression", d->errorString);
+ if (d->errorCode) {
+ QString errorString;
+ int errorStringLength;
+ do {
+ errorString.resize(errorString.length() + 64);
+ errorStringLength = pcre2_get_error_message_16(d->errorCode,
+ reinterpret_cast<ushort *>(errorString.data()),
+ errorString.length());
+ } while (errorStringLength < 0);
+ errorString.resize(errorStringLength);
+
+ return QCoreApplication::translate("QRegularExpression", std::move(errorString).toLatin1().constData());
+ }
return QCoreApplication::translate("QRegularExpression", "no error");
}
@@ -2583,7 +2594,8 @@ QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match)
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2015 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -2625,80 +2637,149 @@ static const char *pcreCompileErrorCodes[] =
QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in character class"),
QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "nothing to repeat"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing )"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
- QT_TRANSLATE_NOOP("QRegularExpression", "erroffset passed as NULL"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unknown option bit(s) set"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after comment"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
- QT_TRANSLATE_NOOP("QRegularExpression", "failed to get memory"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unmatched parentheses"),
+ 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", "unrecognized character after (?<"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "letter or underscore expected after (?< or (?'"),
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", "assertion expected after (?("),
+ QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
QT_TRANSLATE_NOOP("QRegularExpression", "(?R or (?[+-]digits must be followed by )"),
QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
- QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
- QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UTF8 support"),
- QT_TRANSLATE_NOOP("QRegularExpression", "character value in \\x{...} sequence is too large"),
+ 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 not allowed in lookbehind assertion"),
+ 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", "number after (?C is > 255"),
- QT_TRANSLATE_NOOP("QRegularExpression", "closing ) for (?C expected"),
- QT_TRANSLATE_NOOP("QRegularExpression", "recursive call could loop indefinitely"),
+ 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", "two named subpatterns have the same name"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-8 string"),
- QT_TRANSLATE_NOOP("QRegularExpression", "support for \\P, \\p, and \\X has not been compiled"),
+ 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", "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 32 characters)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum 10000)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 (not in UTF-8 mode)"),
+ 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", "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", "repeating a DEFINE group is not allowed"),
- QT_TRANSLATE_NOOP("QRegularExpression", "inconsistent NEWLINE options"),
+ 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", "(*VERB) not recognized"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
QT_TRANSLATE_NOOP("QRegularExpression", "number is too big"),
QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+"),
- QT_TRANSLATE_NOOP("QRegularExpression", "] is an invalid data character in JavaScript compatibility mode"),
+ 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"),
- QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UCP support"),
- QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by an ASCII character"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
+ 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", "\\N is not supported in a class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "too many forward references"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "SPARE ERROR"),
QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-16 string"),
+ 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 value in \\u.... sequence is too large"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-32 string"),
- QT_TRANSLATE_NOOP("QRegularExpression", "setting UTF is disabled by the application"),
- QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
- QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "group name must start with a non-digit"),
- QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{}")
+ 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", "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"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
+ 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", "no error"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
+ 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", "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"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
+ 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", "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)")
};
#endif // #if 0
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp
index cb11e72435..8fa378e935 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -132,7 +132,6 @@ char *QRingBuffer::reserve(qint64 bytes)
char *writePtr = buffers.last().data() + tail;
bufferSize += bytes;
- Q_ASSERT(bytes < MaxByteArraySize);
tail += int(bytes);
return writePtr;
}
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index 5738413bfb..0d42c8a212 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -974,13 +974,13 @@ qobject_cast(const QWeakPointer<T> &src)
}
template<typename T>
-QWeakPointer<typename QtPrivate::QEnableIf<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::Type>
+QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qWeakPointerFromVariant(const QVariant &variant)
{
return QWeakPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).data()));
}
template<typename T>
-QSharedPointer<typename QtPrivate::QEnableIf<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::Type>
+QSharedPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qSharedPointerFromVariant(const QVariant &variant)
{
return qSharedPointerObjectCast<T>(QtSharedPointer::sharedPointerFromVariant_internal(variant));
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 247119d178..48f3d64c4a 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -211,7 +211,8 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW
{
/* SIMD:
* Unpacking with SSE has been shown to improve performance on recent CPUs
- * The same method gives no improvement with NEON.
+ * The same method gives no improvement with NEON. On Aarch64, clang will do the vectorization
+ * itself in exactly the same way as one would do it with intrinsics.
*/
#if defined(__SSE2__)
const char *e = str + size;
@@ -491,6 +492,30 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l)
return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
# endif
#endif
+#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+ 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) {
+ uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
+ uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b));
+
+ uint8_t r = ~(uint8_t)vaddvq_u16(vandq_u16(vceqq_u16(da, db), mask));
+ if (r) {
+ // found a different QChar
+ uint idx = qCountTrailingZeroBits(r);
+ return (int)a[idx].unicode() - (int)b[idx].unicode();
+ }
+ a += 8;
+ b += 8;
+ }
+ l &= 7;
+ }
+ const auto &lambda = [=](int i) -> int {
+ return a[i].unicode() - b[i].unicode();
+ };
+ return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
+#endif // __ARM_NEON__
if (!l)
return 0;
@@ -703,6 +728,18 @@ static int findChar(const QChar *str, int len, QChar ch, int from,
[=](int i) { return n - s + i; });
# endif
#endif
+#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+ const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
+ const uint16x8_t ch_vec = vdupq_n_u16(c);
+ for (const ushort *next = n + 8; next <= e; n = next, next += 8) {
+ uint16x8_t data = vld1q_u16(n);
+ uint mask = vaddvq_u16(vandq_u16(vceqq_u16(data, ch_vec), vmask));
+ if (ushort(mask)) {
+ // found a match
+ return n - s + qCountTrailingZeroBits(mask);
+ }
+ }
+#endif // aarch64
--n;
while (++n != e)
if (*n == c)
@@ -742,7 +779,9 @@ inline char qToLower(char ch)
}
+#if QT_DEPRECATED_SINCE(5, 9)
const QString::Null QString::null = { };
+#endif
/*!
\macro QT_RESTRICTED_CAST_FROM_ASCII
@@ -1617,7 +1656,7 @@ QString::QString(QChar ch)
\internal
*/
-/*! \fn QString &QString::operator=(const Null &)
+/*! \fn QString &QString::operator=(const QString::Null &)
\internal
*/
@@ -1767,17 +1806,11 @@ void QString::resize(int size, QChar fillChar)
void QString::reallocData(uint alloc, bool grow)
{
- size_t blockSize;
- if (grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
+ auto allocOptions = d->detachFlags();
+ if (grow)
+ allocOptions |= QArrayData::Grow;
if (d->ref.isShared() || IS_RAW_DATA(d)) {
- Data::AllocationOptions allocOptions(d->capacityReserved ? Data::CapacityReserved : 0);
Data *x = Data::allocate(alloc, allocOptions);
Q_CHECK_PTR(x);
x->size = qMin(int(alloc) - 1, d->size);
@@ -1787,11 +1820,9 @@ void QString::reallocData(uint alloc, bool grow)
Data::deallocate(d);
d = x;
} else {
- Data *p = static_cast<Data *>(::realloc(d, blockSize));
+ Data *p = Data::reallocateUnaligned(d, alloc, allocOptions);
Q_CHECK_PTR(p);
d = p;
- d->alloc = alloc;
- d->offset = sizeof(QStringData);
}
}
@@ -4466,11 +4497,11 @@ bool QString::startsWith(const QStringRef &s, Qt::CaseSensitivity cs) const
\sa startsWith()
*/
-bool QString::endsWith(const QString& s, Qt::CaseSensitivity cs) const
+bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
{
return qt_ends_with(isNull() ? 0 : unicode(), size(),
s.isNull() ? 0 : s.unicode(), s.size(), cs);
- }
+}
/*!
\since 4.8
@@ -4606,6 +4637,8 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
QByteArray QString::toLocal8Bit_helper(const QChar *data, int size)
{
+ if (!data)
+ return QByteArray();
#ifndef QT_NO_TEXTCODEC
QTextCodec *localeCodec = QTextCodec::codecForLocale();
if (localeCodec)
@@ -4887,6 +4920,7 @@ QString QString::fromUcs4(const uint *unicode, int size)
return QUtf32::convertToUnicode((const char *)unicode, size*4, 0);
}
+
/*!
Resizes the string to \a size characters and copies \a unicode
into the string.
@@ -5981,7 +6015,10 @@ static uint parse_flag_characters(const char * &c) Q_DECL_NOTHROW
uint flags = QLocaleData::ZeroPadExponent;
while (true) {
switch (*c) {
- case '#': flags |= QLocaleData::Alternate; break;
+ case '#':
+ flags |= QLocaleData::ShowBase | QLocaleData::AddTrailingZeroes
+ | QLocaleData::ForcePoint;
+ break;
case '0': flags |= QLocaleData::ZeroPadded; break;
case '-': flags |= QLocaleData::LeftAdjusted; break;
case ' ': flags |= QLocaleData::BlankBeforePositive; break;
@@ -6239,7 +6276,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
case 'p': {
void *arg = va_arg(ap, void*);
const quint64 i = reinterpret_cast<quintptr>(arg);
- flags |= QLocaleData::Alternate;
+ flags |= QLocaleData::ShowBase;
subst = QLocaleData::c()->unsLongLongToString(i, precision, 16, width, flags);
++c;
break;
@@ -7814,10 +7851,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
if (d.locale_occurrences > 0) {
QLocale locale;
- if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
+ const QLocale::NumberOptions numberOptions = locale.numberOptions();
+ if (!(numberOptions & QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
- if (!(locale.numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
locale_arg = locale.d->m_data->doubleToString(a, prec, form, fieldWidth, flags);
}
@@ -8025,33 +8065,12 @@ bool QString::isSimpleText() const
/*! \fn bool QString::isRightToLeft() const
Returns \c true if the string is read right to left.
+
+ \sa QStringRef::isRightToLeft()
*/
bool QString::isRightToLeft() const
{
- const ushort *p = d->data();
- const ushort * const end = p + d->size;
- while (p < end) {
- uint ucs4 = *p;
- if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
- ushort low = p[1];
- if (QChar::isLowSurrogate(low)) {
- ucs4 = QChar::surrogateToUcs4(ucs4, low);
- ++p;
- }
- }
- switch (QChar::direction(ucs4))
- {
- case QChar::DirL:
- return false;
- case QChar::DirR:
- case QChar::DirAL:
- return true;
- default:
- break;
- }
- ++p;
- }
- return false;
+ return QStringRef(this).isRightToLeft();
}
/*! \fn QChar *QString::data()
@@ -9007,7 +9026,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in
the string.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9016,7 +9035,16 @@ ownership of it, no memory is freed when instances are destroyed.
Same as begin().
- \sa begin(), cend(), rbegin(), rend()
+ \sa begin(), constBegin(), cend(), constEnd(), rbegin(), rend()
+*/
+
+/*!
+ \fn QStringRef::const_iterator QStringRef::constBegin() const
+ \since 5.9
+
+ Same as begin().
+
+ \sa begin(), cend(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9026,7 +9054,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
character after the last character in the list.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*! \fn QStringRef::const_iterator QStringRef::cend() const
@@ -9034,7 +9062,15 @@ ownership of it, no memory is freed when instances are destroyed.
Same as end().
- \sa end(), cbegin(), rbegin(), rend()
+ \sa end(), constEnd(), cbegin(), constBegin(), rbegin(), rend()
+*/
+
+/*! \fn QStringRef::const_iterator QStringRef::constEnd() const
+ \since 5.9
+
+ Same as end().
+
+ \sa end(), cend(), cbegin(), constBegin(), rbegin(), rend()
*/
/*!
@@ -9585,9 +9621,7 @@ QStringRef QStringRef::left(int n) const
*/
QStringRef QString::leftRef(int n) const
{
- if (uint(n) >= uint(d->size))
- n = d->size;
- return QStringRef(this, 0, n);
+ return QStringRef(this).left(n);
}
/*!
@@ -9624,9 +9658,7 @@ QStringRef QStringRef::right(int n) const
*/
QStringRef QString::rightRef(int n) const
{
- if (uint(n) >= uint(d->size))
- n = d->size;
- return QStringRef(this, d->size - n, n);
+ return QStringRef(this).right(n);
}
/*!
@@ -9685,19 +9717,7 @@ QStringRef QStringRef::mid(int pos, int n) const
*/
QStringRef QString::midRef(int position, int n) const
{
- using namespace QtPrivate;
- switch (QContainerImplHelper::mid(d->size, &position, &n)) {
- case QContainerImplHelper::Null:
- return QStringRef();
- case QContainerImplHelper::Empty:
- return QStringRef(this, 0, 0);
- case QContainerImplHelper::Full:
- return QStringRef(this, 0, d->size);
- case QContainerImplHelper::Subset:
- return QStringRef(this, position, n);
- }
- Q_UNREACHABLE();
- return QStringRef();
+ return QStringRef(this).mid(position, n);
}
/*!
@@ -9944,6 +9964,41 @@ int QStringRef::count(const QStringRef &str, Qt::CaseSensitivity cs) const
}
/*!
+ \since 5.9
+
+ Returns \c true if the string is read right to left.
+
+ \sa QString::isRightToLeft()
+*/
+bool QStringRef::isRightToLeft() const
+{
+ const ushort *p = reinterpret_cast<const ushort*>(unicode());
+ const ushort * const end = p + size();
+ while (p < end) {
+ uint ucs4 = *p;
+ if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
+ ushort low = p[1];
+ if (QChar::isLowSurrogate(low)) {
+ ucs4 = QChar::surrogateToUcs4(ucs4, low);
+ ++p;
+ }
+ }
+ switch (QChar::direction(ucs4))
+ {
+ case QChar::DirL:
+ return false;
+ case QChar::DirR:
+ case QChar::DirAL:
+ return true;
+ default:
+ break;
+ }
+ ++p;
+ }
+ return false;
+}
+
+/*!
\since 4.8
Returns \c true if the string reference starts with \a str; otherwise
@@ -10309,6 +10364,8 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
*/
QByteArray QStringRef::toLatin1() const
{
+ if (isNull())
+ return QByteArray();
return QString::toLatin1_helper(unicode(), length());
}
@@ -10347,9 +10404,11 @@ QByteArray QStringRef::toLatin1() const
QByteArray QStringRef::toLocal8Bit() const
{
#ifndef QT_NO_TEXTCODEC
- QTextCodec *localeCodec = QTextCodec::codecForLocale();
- if (localeCodec)
- return localeCodec->fromUnicode(unicode(), length());
+ if (!isNull()) {
+ QTextCodec *localeCodec = QTextCodec::codecForLocale();
+ if (localeCodec)
+ return localeCodec->fromUnicode(unicode(), length());
+ }
#endif // QT_NO_TEXTCODEC
return toLatin1();
}
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index b50b2ee4e5..1bd436c387 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -144,15 +144,10 @@ typedef QLatin1String QLatin1Literal;
typedef QTypedArrayData<ushort> QStringData;
-#if defined(Q_COMPILER_UNICODE_STRINGS)
-
-#define QT_UNICODE_LITERAL_II(str) u"" str
-typedef char16_t qunicodechar;
-
-#elif defined(Q_OS_WIN) \
- || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) \
- || (!defined(__SIZEOF_WCHAR_T__) && defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536))
-// wchar_t is 2 bytes
+#if defined(Q_OS_WIN) && !defined(Q_COMPILER_UNICODE_STRINGS)
+// fall back to wchar_t if the a Windows compiler does not
+// support Unicode string literals, assuming wchar_t is 2 bytes
+// on that platform (sanity-checked by static_assert further below)
#if defined(Q_CC_MSVC)
# define QT_UNICODE_LITERAL_II(str) L##str
@@ -162,21 +157,22 @@ typedef char16_t qunicodechar;
typedef wchar_t qunicodechar;
#else
+// 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
+// core language feature, so just use u"" here unconditionally:
-#define QT_NO_UNICODE_LITERAL
-typedef ushort qunicodechar;
+#define QT_UNICODE_LITERAL_II(str) u"" str
+typedef char16_t qunicodechar;
#endif
Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
"qunicodechar must typedef an integral type of size 2");
-#ifndef QT_NO_UNICODE_LITERAL
-# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
-# if defined(Q_COMPILER_LAMBDA)
-
-# define QStringLiteral(str) \
- ([]() -> QString { \
+#define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
+#define QStringLiteral(str) \
+ ([]() Q_DECL_NOEXCEPT -> QString { \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QStaticStringData<Size> qstring_literal = { \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
@@ -187,17 +183,6 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
}()) \
/**/
-# endif
-#endif // QT_NO_UNICODE_LITERAL
-
-#ifndef QStringLiteral
-// no lambdas, not GCC, or GCC in C++98 mode with 4-byte wchar_t
-// fallback, return a temporary QString
-// source code is assumed to be encoded in UTF-8
-
-# define QStringLiteral(str) QString::fromUtf8("" str "", sizeof(str) - 1)
-#endif
-
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
/**/
@@ -397,7 +382,7 @@ public:
QString leftJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT;
QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT;
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT")
@@ -522,7 +507,7 @@ public:
const ushort *utf16() const;
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
QByteArray toLatin1() const & Q_REQUIRED_RESULT
{ return toLatin1_helper(*this); }
QByteArray toLatin1() && Q_REQUIRED_RESULT
@@ -532,9 +517,9 @@ public:
QByteArray toUtf8() && Q_REQUIRED_RESULT
{ return toUtf8_helper(*this); }
QByteArray toLocal8Bit() const & Q_REQUIRED_RESULT
- { return toLocal8Bit_helper(constData(), size()); }
+ { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
QByteArray toLocal8Bit() && Q_REQUIRED_RESULT
- { return toLocal8Bit_helper(constData(), size()); }
+ { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
#else
QByteArray toLatin1() const Q_REQUIRED_RESULT;
QByteArray toUtf8() const Q_REQUIRED_RESULT;
@@ -785,10 +770,13 @@ public:
NSString *toNSString() const Q_DECL_NS_RETURNS_AUTORELEASED;
#endif
// compatibility
+#if QT_DEPRECATED_SINCE(5, 9)
struct Null { };
+ QT_DEPRECATED_X("use QString()")
static const Null null;
inline QString(const Null &): d(Data::sharedNull()) {}
inline QString &operator=(const Null &) { *this = QString(); return *this; }
+#endif
inline bool isNull() const { return d == Data::sharedNull(); }
@@ -1149,13 +1137,18 @@ inline bool QString::contains(QLatin1String s, Qt::CaseSensitivity cs) const
inline bool QString::contains(QChar c, Qt::CaseSensitivity cs) const
{ return indexOf(c, 0, cs) != -1; }
-
+#if QT_DEPRECATED_SINCE(5, 9)
inline bool operator==(QString::Null, QString::Null) { return true; }
+QT_DEPRECATED_X("use QString::isNull()")
inline bool operator==(QString::Null, const QString &s) { return s.isNull(); }
+QT_DEPRECATED_X("use QString::isNull()")
inline bool operator==(const QString &s, QString::Null) { return s.isNull(); }
inline bool operator!=(QString::Null, QString::Null) { return false; }
+QT_DEPRECATED_X("use !QString::isNull()")
inline bool operator!=(QString::Null, const QString &s) { return !s.isNull(); }
+QT_DEPRECATED_X("use !QString::isNull()")
inline bool operator!=(const QString &s, QString::Null) { return !s.isNull(); }
+#endif
inline bool operator==(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ return s1.size() == s2.size() && (!s1.size() || !memcmp(s1.latin1(), s2.latin1(), s1.size())); }
@@ -1400,7 +1393,8 @@ public:
QStringRef(QStringRef &&other) Q_DECL_NOTHROW : m_string(other.m_string), m_position(other.m_position), m_size(other.m_size) {}
QStringRef &operator=(QStringRef &&other) Q_DECL_NOTHROW { return *this = other; }
#endif
- QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW {
+ QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW
+ {
m_string = other.m_string; m_position = other.m_position;
m_size = other.m_size; return *this;
}
@@ -1449,6 +1443,8 @@ public:
m_size -= n;
}
+ bool isRightToLeft() const;
+
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
@@ -1461,7 +1457,8 @@ public:
inline QStringRef &operator=(const QString *string);
- inline const QChar *unicode() const {
+ inline const QChar *unicode() const
+ {
if (!m_string)
return reinterpret_cast<const QChar *>(QString::Data::sharedNull()->data());
return m_string->unicode() + m_position;
@@ -1471,8 +1468,10 @@ public:
inline const_iterator begin() const { return unicode(); }
inline const_iterator cbegin() const { return unicode(); }
+ inline const_iterator constBegin() const { return unicode(); }
inline const_iterator end() const { return unicode() + size(); }
inline const_iterator cend() const { return unicode() + size(); }
+ inline const_iterator constEnd() const { return unicode() + size(); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
inline const_reverse_iterator crbegin() const { return rbegin(); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
diff --git a/src/corelib/tools/qstring_compat.cpp b/src/corelib/tools/qstring_compat.cpp
index 300f8467b1..45bb816e4b 100644
--- a/src/corelib/tools/qstring_compat.cpp
+++ b/src/corelib/tools/qstring_compat.cpp
@@ -80,7 +80,7 @@ QByteArray QString::toLatin1() const
QByteArray QString::toLocal8Bit() const
{
- return toLocal8Bit_helper(constData(), size());
+ return toLocal8Bit_helper(isNull() ? nullptr : constData(), size());
}
QByteArray QString::toUtf8() const
diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h
index b2832b5fbe..9a40abcfed 100644
--- a/src/corelib/tools/qstringbuilder.h
+++ b/src/corelib/tools/qstringbuilder.h
@@ -277,9 +277,9 @@ template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
+template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
{
- typedef char type[N];
+ typedef const char type[N];
typedef QByteArray ConvertTo;
enum { ExactSize = false };
static int size(const char[N]) { return N - 1; }
@@ -296,23 +296,9 @@ template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
+template <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
{
- typedef const char type[N];
- typedef QByteArray ConvertTo;
- enum { ExactSize = false };
- static int size(const char[N]) { return N - 1; }
-#ifndef QT_NO_CAST_FROM_ASCII
- static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
- {
- QAbstractConcatenable::convertFromAscii(a, N - 1, out);
- }
-#endif
- static inline void appendTo(const char a[N], char *&out)
- {
- while (*a)
- *out++ = *a++;
- }
+ typedef char type[N];
};
template <> struct QConcatenable<const char *> : private QAbstractConcatenable
diff --git a/src/corelib/tools/qtimezone.h b/src/corelib/tools/qtimezone.h
index 083f87f39f..bd87139f5b 100644
--- a/src/corelib/tools/qtimezone.h
+++ b/src/corelib/tools/qtimezone.h
@@ -47,6 +47,11 @@
QT_REQUIRE_CONFIG(timezone);
+#if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+Q_FORWARD_DECLARE_CF_TYPE(CFTimeZone);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
+#endif
+
QT_BEGIN_NAMESPACE
class QTimeZonePrivate;
@@ -142,6 +147,13 @@ public:
static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Country country);
+#if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+ static QTimeZone fromCFTimeZone(CFTimeZoneRef timeZone);
+ CFTimeZoneRef toCFTimeZone() const Q_DECL_CF_RETURNS_RETAINED;
+ static QTimeZone fromNSTimeZone(const NSTimeZone *timeZone);
+ NSTimeZone *toNSTimeZone() const Q_DECL_NS_RETURNS_AUTORELEASED;
+#endif
+
private:
QTimeZone(QTimeZonePrivate &dd);
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qtimezoneprivate.cpp b/src/corelib/tools/qtimezoneprivate.cpp
index 2ff03eddec..7b780ecf7d 100644
--- a/src/corelib/tools/qtimezoneprivate.cpp
+++ b/src/corelib/tools/qtimezoneprivate.cpp
@@ -49,10 +49,6 @@
QT_BEGIN_NAMESPACE
-enum {
- MSECS_TRAN_WINDOW = 21600000 // 6 hour window for possible recent transitions
-};
-
/*
Static utilities for looking up Windows ID tables
*/
@@ -140,7 +136,7 @@ QTimeZonePrivate::~QTimeZonePrivate()
{
}
-QTimeZonePrivate *QTimeZonePrivate::clone()
+QTimeZonePrivate *QTimeZonePrivate::clone() const
{
return new QTimeZonePrivate(*this);
}
@@ -248,67 +244,206 @@ QTimeZonePrivate::Data QTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
}
// Private only method for use by QDateTime to convert local msecs to epoch msecs
-// TODO Could be platform optimised if needed
-QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs) const
+QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, int hint) const
{
- if (!hasDaylightTime() ||!hasTransitions()) {
- // No DST means same offset for all local msecs
- // Having DST but no transitions means we can't calculate, so use nearest
- return data(forLocalMSecs - (standardTimeOffset(forLocalMSecs) * 1000));
- }
+ if (!hasDaylightTime()) // No DST means same offset for all local msecs
+ return data(forLocalMSecs - standardTimeOffset(forLocalMSecs) * 1000);
- // Get the transition for the local msecs which most of the time should be the right one
- // Only around the transition times might it not be the right one
- Data tran = previousTransition(forLocalMSecs);
- Data nextTran;
-
- // If the local msecs is less than the real local time of the transition
- // then get the previous transition to use instead
- if (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
- while (tran.atMSecsSinceEpoch != invalidMSecs()
- && forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
- nextTran = tran;
- tran = previousTransition(tran.atMSecsSinceEpoch);
- }
- } else {
- // The zone msecs is after the transition, so check it is before the next tran
- // If not try use the next transition instead
- nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ /*
+ We need a UTC time at which to ask for the offset, in order to be able to
+ add that offset to forLocalMSecs, to get the UTC time we
+ need. Fortunately, no time-zone offset is more than 14 hours; and DST
+ transitions happen (much) more than thirty-two hours apart. So sampling
+ offset sixteen hours each side gives us information we can be sure
+ brackets the correct time and at most one DST transition.
+ */
+ const qint64 sixteenHoursInMSecs(16 * 3600 * 1000);
+ /*
+ Offsets are Local - UTC, positive to the east of Greenwich, negative to
+ the west; DST offset always exceeds standard offset, when DST applies.
+ When we have offsets on either side of a transition, the lower one is
+ standard, the higher is DST.
+
+ Non-DST transitions (jurisdictions changing time-zone and time-zones
+ changing their standard offset, typically) are described below as if they
+ were DST transitions (since these are more usual and familiar); the code
+ mostly concerns itself with offsets from UTC, described in terms of the
+ common case for changes in that. If there is no actual change in offset
+ (e.g. a DST transition cancelled by a standard offset change), this code
+ should handle it gracefully; without transitions, it'll see early == late
+ and take the easy path; with transitions, tran and nextTran get the
+ correct UTC time as atMSecsSinceEpoch so comparing to nextStart selects
+ the right one. In all other cases, the transition changes offset and the
+ reasoning that applies to DST applies just the same. Aside from hinting,
+ the only thing that looks at DST-ness at all, other than inferred from
+ offset changes, is the case without transition data handling an invalid
+ time in the gap that a transition passed over.
+
+ The handling of hint (see below) is apt to go wrong in non-DST
+ transitions. There isn't really a great deal we can hope to do about that
+ without adding yet more unreliable complexity to the heuristics in use for
+ already obscure corner-cases.
+ */
+
+ /*
+ The hint (really a QDateTimePrivate::DaylightStatus) is > 0 if caller
+ thinks we're in DST, 0 if in standard. A value of -2 means never-DST, so
+ should have been handled above; if it slips through, it's wrong but we
+ should probably treat it as standard anyway (never-DST means
+ always-standard, after all). If the hint turns out to be wrong, fall back
+ on trying the other possibility: which makes it harmless to treat -1
+ (meaning unknown) as standard (i.e. try standard first, then try DST). In
+ practice, away from a transition, the only difference hint makes is to
+ which candidate we try first: if the hint is wrong (or unknown and
+ standard fails), we'll try the other candidate and it'll work.
+
+ For the obscure (and invalid) case where forLocalMSecs falls in a
+ spring-forward's missing hour, a common case is that we started with a
+ date/time for which the hint was valid and adjusted it naively; for that
+ case, we should correct the adjustment by shunting across the transition
+ into where hint is wrong. So half-way through the gap, arrived at from
+ the DST side, should be read as an hour earlier, in standard time; but, if
+ arrived at from the standard side, should be read as an hour later, in
+ DST. (This shall be wrong in some cases; for example, when a country
+ changes its transition dates and changing a date/time by more than six
+ months lands it on a transition. However, these cases are even more
+ obscure than those where the heuristic is good.)
+ */
+
+ if (hasTransitions()) {
+ /*
+ We have transitions.
+
+ Each transition gives the offsets to use until the next; so we need the
+ most recent transition before the time forLocalMSecs describes. If it
+ describes a time *in* a transition, we'll need both that transition and
+ the one before it. So find one transition that's probably after (and not
+ much before, otherwise) and another that's definitely before, then work
+ out which one to use. When both or neither work on forLocalMSecs, use
+ hint to disambiguate.
+ */
+
+ // Get a transition definitely before the local MSecs; usually all we need.
+ // Only around the transition times might we need another.
+ Data tran = previousTransition(forLocalMSecs - sixteenHoursInMSecs);
+ Q_ASSERT(forLocalMSecs < 0 || // Pre-epoch TZ info may be unavailable
+ forLocalMSecs >= tran.atMSecsSinceEpoch + tran.offsetFromUtc * 1000);
+ Data nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ /*
+ Now walk those forward until they bracket forLocalMSecs with transitions.
+
+ One of the transitions should then be telling us the right offset to use.
+ In a transition, we need the transition before it (to describe the run-up
+ to the transition) and the transition itself; so we need to stop when
+ nextTran is that transition.
+ */
while (nextTran.atMSecsSinceEpoch != invalidMSecs()
- && forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
+ && forLocalMSecs > nextTran.atMSecsSinceEpoch + nextTran.offsetFromUtc * 1000) {
+ Data newTran = nextTransition(nextTran.atMSecsSinceEpoch);
+ if (newTran.atMSecsSinceEpoch == invalidMSecs()
+ || newTran.atMSecsSinceEpoch + newTran.offsetFromUtc * 1000
+ > forLocalMSecs + sixteenHoursInMSecs) {
+ // Definitely not a relevant tansition: too far in the future.
+ break;
+ }
tran = nextTran;
- nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ nextTran = newTran;
}
+
+ // Check we do *really* have transitions for this zone:
+ if (tran.atMSecsSinceEpoch != invalidMSecs()) {
+
+ /*
+ So now tran is definitely before and nextTran is either after or only
+ slightly before. The one with the larger offset is in DST; the other in
+ standard time. Our hint tells us which of those to use (defaulting to
+ standard if no hint): try it first; if that fails, try the other; if both
+ fail life's tricky.
+ */
+ Q_ASSERT(forLocalMSecs < 0
+ || forLocalMSecs > tran.atMSecsSinceEpoch + tran.offsetFromUtc * 1000);
+ const qint64 nextStart = nextTran.atMSecsSinceEpoch;
+ // Work out the UTC values it might make sense to return:
+ nextTran.atMSecsSinceEpoch = forLocalMSecs - nextTran.offsetFromUtc * 1000;
+ tran.atMSecsSinceEpoch = forLocalMSecs - tran.offsetFromUtc * 1000;
+
+ const bool nextIsDst = tran.offsetFromUtc < nextTran.offsetFromUtc;
+ // If that agrees with hint > 0, our first guess is to use nextTran; else tran.
+ const bool nextFirst = nextIsDst == (hint > 0) && nextStart != invalidMSecs();
+ for (int i = 0; i < 2; i++) {
+ /*
+ On the first pass, the case we consider is what hint told us to expect
+ (except when hint was -1 and didn't actually tell us what to expect),
+ so it's likely right. We only get a second pass if the first failed,
+ by which time the second case, that we're trying, is likely right. If
+ an overwhelming majority of calls have hint == -1, the Q_LIKELY here
+ shall be wrong half the time; otherwise, its errors shall be rarer
+ than that.
+ */
+ if (nextFirst ? i == 0 : i) {
+ Q_ASSERT(nextStart != invalidMSecs());
+ if (Q_LIKELY(nextStart <= nextTran.atMSecsSinceEpoch))
+ return nextTran;
+ } else {
+ // If next is invalid, nextFirst is false, to route us here first:
+ if (nextStart == invalidMSecs() || Q_LIKELY(nextStart > tran.atMSecsSinceEpoch))
+ return tran;
+ }
+ }
+
+ /*
+ Neither is valid (e.g. in a spring-forward's gap) and
+ nextTran.atMSecsSinceEpoch < nextStart <= tran.atMSecsSinceEpoch, so
+ 0 < tran.atMSecsSinceEpoch - nextTran.atMSecsSinceEpoch
+ = (nextTran.offsetFromUtc - tran.offsetFromUtc) * 1000
+ */
+ int dstStep = nextTran.offsetFromUtc - tran.offsetFromUtc;
+ Q_ASSERT(dstStep > 0); // How else could we get here ?
+ if (nextFirst) { // hint thought we needed nextTran, so use tran
+ tran.atMSecsSinceEpoch -= dstStep;
+ return tran;
+ }
+ nextTran.atMSecsSinceEpoch += dstStep;
+ return nextTran;
+ }
+ // System has transitions but not for this zone.
+ // Try falling back to offsetFromUtc
}
- if (tran.daylightTimeOffset == 0) {
- // If tran is in StandardTime, then need to check if falls close to either DST transition.
- // If it does, then it may need adjusting for missing hour or for second occurrence
- qint64 diffPrevTran = forLocalMSecs
- - (tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000));
- qint64 diffNextTran = nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)
- - forLocalMSecs;
- if (diffPrevTran >= 0 && diffPrevTran < MSECS_TRAN_WINDOW) {
- // If tran picked is for standard time check if changed from DST in last 6 hours,
- // as the local msecs may be ambiguous and represent two valid utc msecs.
- // If in last 6 hours then get prev tran and if diff falls within the DST offset
- // then use the prev tran as we default to the FirstOccurrence
- // TODO Check if faster to just always get prev tran, or if faster using 6 hour check.
- Data dstTran = previousTransition(tran.atMSecsSinceEpoch);
- if (dstTran.atMSecsSinceEpoch != invalidMSecs()
- && dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
- tran = dstTran;
- } else if (diffNextTran >= 0 && diffNextTran <= (nextTran.daylightTimeOffset * 1000)) {
- // If time falls within last hour of standard time then is actually the missing hour
- // So return the next tran instead and adjust the local time to be valid
- tran = nextTran;
- forLocalMSecs = forLocalMSecs + (nextTran.daylightTimeOffset * 1000);
+ /* Bracket and refine to discover offset. */
+ qint64 utcEpochMSecs;
+
+ int early = offsetFromUtc(forLocalMSecs - sixteenHoursInMSecs);
+ int late = offsetFromUtc(forLocalMSecs + sixteenHoursInMSecs);
+ if (Q_LIKELY(early == late)) { // > 99% of the time
+ utcEpochMSecs = forLocalMSecs - early * 1000;
+ } else {
+ // Close to a DST transition: early > late is near a fall-back,
+ // early < late is near a spring-forward.
+ const int offsetInDst = qMax(early, late);
+ const int offsetInStd = qMin(early, late);
+ // Candidate values for utcEpochMSecs (if forLocalMSecs is valid):
+ const qint64 forDst = forLocalMSecs - offsetInDst * 1000;
+ const qint64 forStd = forLocalMSecs - offsetInStd * 1000;
+ // Best guess at the answer:
+ const qint64 hinted = hint > 0 ? forDst : forStd;
+ if (Q_LIKELY(offsetFromUtc(hinted) == (hint > 0 ? offsetInDst : offsetInStd))) {
+ utcEpochMSecs = hinted;
+ } else if (hint <= 0 && offsetFromUtc(forDst) == offsetInDst) {
+ utcEpochMSecs = forDst;
+ } else if (hint > 0 && offsetFromUtc(forStd) == offsetInStd) {
+ utcEpochMSecs = forStd;
+ } else {
+ // Invalid forLocalMSecs: in spring-forward gap.
+ const int dstStep = daylightTimeOffset(early < late ?
+ forLocalMSecs + sixteenHoursInMSecs :
+ forLocalMSecs - sixteenHoursInMSecs);
+ Q_ASSERT(dstStep); // There can't be a transition without it !
+ utcEpochMSecs = (hint > 0) ? forStd - dstStep : forDst + dstStep;
}
}
- // tran should now hold the right transition offset to use
- tran.atMSecsSinceEpoch = forLocalMSecs - (tran.offsetFromUtc * 1000);
- return tran;
+ return data(utcEpochMSecs);
}
bool QTimeZonePrivate::hasTransitions() const
@@ -649,7 +784,7 @@ QUtcTimeZonePrivate::~QUtcTimeZonePrivate()
{
}
-QTimeZonePrivate *QUtcTimeZonePrivate::clone()
+QUtcTimeZonePrivate *QUtcTimeZonePrivate::clone() const
{
return new QUtcTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qtimezoneprivate_android.cpp b/src/corelib/tools/qtimezoneprivate_android.cpp
index 53bf90f01d..c3f8c3e0d9 100644
--- a/src/corelib/tools/qtimezoneprivate_android.cpp
+++ b/src/corelib/tools/qtimezoneprivate_android.cpp
@@ -88,7 +88,7 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId)
m_id = ianaId;
}
-QTimeZonePrivate *QAndroidTimeZonePrivate::clone()
+QAndroidTimeZonePrivate *QAndroidTimeZonePrivate::clone() const
{
return new QAndroidTimeZonePrivate(*this);
}
@@ -207,58 +207,6 @@ QTimeZonePrivate::Data QAndroidTimeZonePrivate::previousTransition(qint64 before
return invalidData();
}
-// Since Android does not provide an API to access transitions,
-// dataForLocalTime needs to be reimplemented without direct use of transitions
-QTimeZonePrivate::Data QAndroidTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs) const
-{
- if (!androidTimeZone.isValid()) {
- return invalidData();
- } else {
- qint64 UTCepochMSecs;
-
- // compare the UTC time with standard offset against normal DST offset of one hour
- qint64 standardUTCMSecs(forLocalMSecs - (standardTimeOffset(forLocalMSecs) * 1000));
- qint64 daylightUTCMsecs;
-
- // Check if daylight-saving time applies,
- // checking also for DST boundaries
- if (isDaylightTime(standardUTCMSecs)) {
- // If DST does apply, then standardUTCMSecs will be an hour or so ahead of the real epoch time
- // so check that time
- daylightUTCMsecs = standardUTCMSecs - daylightTimeOffset(standardUTCMSecs)*1000;
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST confirmed
- UTCepochMSecs = daylightUTCMsecs;
- } else {
- // DST has just finished
- UTCepochMSecs = standardUTCMSecs;
- }
- } else {
- // Standard time indicated, but check for a false negative.
- // Would a standard one-hour DST offset indicate DST?
- daylightUTCMsecs = standardUTCMSecs - 3600000; // 3600000 MSECS_PER_HOUR
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST may have just started,
- // but double check against timezone's own DST offset
- // (don't necessarily assume a one-hour offset)
- daylightUTCMsecs = standardUTCMSecs - daylightTimeOffset(daylightUTCMsecs)*1000;
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST confirmed
- UTCepochMSecs = daylightUTCMsecs;
- } else {
- // false positive, apply standard time after all
- UTCepochMSecs = standardUTCMSecs;
- }
- } else {
- // confirmed standard time
- UTCepochMSecs = standardUTCMSecs;
- }
- }
-
- return data(UTCepochMSecs);
- }
-}
-
QByteArray QAndroidTimeZonePrivate::systemTimeZoneId() const
{
QJNIObjectPrivate androidSystemTimeZone = QJNIObjectPrivate::callStaticObjectMethod("java.util.TimeZone", "getDefault", "()Ljava/util/TimeZone;");
diff --git a/src/corelib/tools/qtimezoneprivate_icu.cpp b/src/corelib/tools/qtimezoneprivate_icu.cpp
index c088fe7694..a7226f2720 100644
--- a/src/corelib/tools/qtimezoneprivate_icu.cpp
+++ b/src/corelib/tools/qtimezoneprivate_icu.cpp
@@ -98,7 +98,7 @@ static QByteArray ucalDefaultTimeZoneId()
// If successful on first or second go, resize and return
if (U_SUCCESS(status)) {
result.resize(size);
- return result.toUtf8();
+ return std::move(result).toUtf8();
}
return QByteArray();
@@ -305,7 +305,7 @@ QIcuTimeZonePrivate::~QIcuTimeZonePrivate()
ucal_close(m_ucal);
}
-QTimeZonePrivate *QIcuTimeZonePrivate::clone()
+QIcuTimeZonePrivate *QIcuTimeZonePrivate::clone() const
{
return new QIcuTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qtimezoneprivate_mac.mm b/src/corelib/tools/qtimezoneprivate_mac.mm
index 5dfffeaf36..4e9a432fbf 100644
--- a/src/corelib/tools/qtimezoneprivate_mac.mm
+++ b/src/corelib/tools/qtimezoneprivate_mac.mm
@@ -82,7 +82,7 @@ QMacTimeZonePrivate::~QMacTimeZonePrivate()
[m_nstz release];
}
-QTimeZonePrivate *QMacTimeZonePrivate::clone()
+QMacTimeZonePrivate *QMacTimeZonePrivate::clone() const
{
return new QMacTimeZonePrivate(*this);
}
@@ -273,4 +273,9 @@ QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds() const
return list;
}
+NSTimeZone *QMacTimeZonePrivate::nsTimeZone() const
+{
+ return m_nstz;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h
index d06784b0f9..0038908160 100644
--- a/src/corelib/tools/qtimezoneprivate_p.h
+++ b/src/corelib/tools/qtimezoneprivate_p.h
@@ -60,13 +60,9 @@
#include <unicode/ucal.h>
#endif
-#ifdef Q_OS_MAC
-#ifdef __OBJC__
-@class NSTimeZone;
-#else
-class NSTimeZone;
-#endif // __OBJC__
-#endif // Q_OS_MAC
+#ifdef Q_OS_DARWIN
+Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
+#endif // Q_OS_DARWIN
#ifdef Q_OS_WIN
#include <qt_windows.h>
@@ -78,7 +74,7 @@ class NSTimeZone;
QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QTimeZonePrivate : public QSharedData
+class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData
{
public:
//Version of QTimeZone::OffsetData struct using msecs for efficiency
@@ -96,7 +92,7 @@ public:
QTimeZonePrivate(const QTimeZonePrivate &other);
virtual ~QTimeZonePrivate();
- virtual QTimeZonePrivate *clone();
+ virtual QTimeZonePrivate *clone() const;
bool operator==(const QTimeZonePrivate &other) const;
bool operator!=(const QTimeZonePrivate &other) const;
@@ -123,7 +119,7 @@ public:
virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
virtual Data data(qint64 forMSecsSinceEpoch) const;
- virtual Data dataForLocalTime(qint64 forLocalMSecs) const;
+ Data dataForLocalTime(qint64 forLocalMSecs, int hint) const;
virtual bool hasTransitions() const;
virtual Data nextTransition(qint64 afterMSecsSinceEpoch) const;
@@ -191,7 +187,7 @@ public:
QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other);
virtual ~QUtcTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QUtcTimeZonePrivate *clone() const override;
Data data(qint64 forMSecsSinceEpoch) const Q_DECL_OVERRIDE;
@@ -238,7 +234,7 @@ public:
QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other);
~QIcuTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QIcuTimeZonePrivate *clone() const override;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const Q_DECL_OVERRIDE;
@@ -291,15 +287,15 @@ Q_DECL_CONSTEXPR inline bool operator!=(const QTzTransitionRule &lhs, const QTzT
class Q_AUTOTEST_EXPORT QTzTimeZonePrivate Q_DECL_FINAL : public QTimeZonePrivate
{
+ QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default;
public:
// Create default time zone
QTzTimeZonePrivate();
// Create named time zone
QTzTimeZonePrivate(const QByteArray &ianaId);
- QTzTimeZonePrivate(const QTzTimeZonePrivate &other);
~QTzTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QTzTimeZonePrivate *clone() const override;
QLocale::Country country() const Q_DECL_OVERRIDE;
QString comment() const Q_DECL_OVERRIDE;
@@ -355,7 +351,7 @@ public:
QMacTimeZonePrivate(const QMacTimeZonePrivate &other);
~QMacTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QMacTimeZonePrivate *clone() const override;
QString comment() const Q_DECL_OVERRIDE;
@@ -380,6 +376,8 @@ public:
QList<QByteArray> availableTimeZoneIds() const Q_DECL_OVERRIDE;
+ NSTimeZone *nsTimeZone() const;
+
private:
void init(const QByteArray &zoneId);
@@ -406,7 +404,7 @@ public:
QWinTimeZonePrivate(const QWinTimeZonePrivate &other);
~QWinTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QWinTimeZonePrivate *clone() const override;
QString comment() const Q_DECL_OVERRIDE;
@@ -456,7 +454,7 @@ public:
QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &other);
~QAndroidTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QAndroidTimeZonePrivate *clone() const override;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const Q_DECL_OVERRIDE;
@@ -475,8 +473,6 @@ public:
Data nextTransition(qint64 afterMSecsSinceEpoch) const Q_DECL_OVERRIDE;
Data previousTransition(qint64 beforeMSecsSinceEpoch) const Q_DECL_OVERRIDE;
- Data dataForLocalTime(qint64 forLocalMSecs) const Q_DECL_OVERRIDE;
-
QByteArray systemTimeZoneId() const Q_DECL_OVERRIDE;
QList<QByteArray> availableTimeZoneIds() const Q_DECL_OVERRIDE;
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
index 10b61c3a40..1714c9802f 100644
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
@@ -199,7 +199,7 @@ static QVector<QTzTransition> parseTzTransitions(QDataStream &ds, int tzh_timecn
}
} else {
// Parse tzh_timecnt x 4-byte transition times
- int val;
+ qint32 val;
for (int i = 0; i < tzh_timecnt && ds.status() == QDataStream::Ok; ++i) {
ds >> val;
transitions[i].tz_time = val;
@@ -452,13 +452,31 @@ static inline bool asciiIsLetter(char ch)
return ch >= 'a' && ch <= 'z';
}
+namespace {
+
+struct PosixZone
+{
+ enum {
+ InvalidOffset = INT_MIN,
+ };
+
+ QString name;
+ int offset;
+
+ static PosixZone invalid() { return {QString(), InvalidOffset}; }
+ static PosixZone parse(const char *&pos, const char *end);
+
+ bool hasValidOffset() const Q_DECL_NOTHROW { return offset != InvalidOffset; }
+};
+
+} // unnamed namespace
+
// Returns the zone name, the offset (in seconds) and advances \a begin to
// where the parsing ended. Returns a zone of INT_MIN in case an offset
// couldn't be read.
-static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end)
+PosixZone PosixZone::parse(const char *&pos, const char *end)
{
static const char offsetChars[] = "0123456789:";
- QPair<QString, int> result = qMakePair(QString(), INT_MIN);
const char *nameBegin = pos;
const char *nameEnd;
@@ -480,7 +498,7 @@ static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const c
pos = nameEnd;
}
if (nameEnd - nameBegin < 3)
- return result; // name must be at least 3 characters long
+ return invalid(); // name must be at least 3 characters long
// zone offset, form [+-]hh:mm:ss
const char *zoneBegin = pos;
@@ -493,11 +511,10 @@ static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const c
++zoneEnd;
}
- result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
- if (zoneEnd > zoneBegin)
- result.second = parsePosixOffset(zoneBegin, zoneEnd);
+ QString name = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
+ const int offset = zoneEnd > zoneBegin ? parsePosixOffset(zoneBegin, zoneEnd) : InvalidOffset;
pos = zoneEnd;
- return result;
+ return {std::move(name), offset};
}
static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,
@@ -517,19 +534,19 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
QList<QByteArray> parts = posixRule.split(',');
- QPair<QString, int> stdZone, dstZone;
+ PosixZone stdZone, dstZone;
{
const QByteArray &zoneinfo = parts.at(0);
const char *begin = zoneinfo.constBegin();
- stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
- if (stdZone.second == INT_MIN) {
- stdZone.second = 0; // reset to UTC if we failed to parse
+ stdZone = PosixZone::parse(begin, zoneinfo.constEnd());
+ if (!stdZone.hasValidOffset()) {
+ stdZone.offset = 0; // reset to UTC if we failed to parse
} else if (begin < zoneinfo.constEnd()) {
- dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
- if (dstZone.second == INT_MIN) {
+ dstZone = PosixZone::parse(begin, zoneinfo.constEnd());
+ if (!dstZone.hasValidOffset()) {
// if the dst offset isn't provided, it is 1 hour ahead of the standard offset
- dstZone.second = stdZone.second + (60 * 60);
+ dstZone.offset = stdZone.offset + (60 * 60);
}
}
}
@@ -538,10 +555,10 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
if (parts.count() == 1) {
QTimeZonePrivate::Data data;
data.atMSecsSinceEpoch = lastTranMSecs;
- data.offsetFromUtc = stdZone.second;
- data.standardTimeOffset = stdZone.second;
+ data.offsetFromUtc = stdZone.offset;
+ data.standardTimeOffset = stdZone.offset;
data.daylightTimeOffset = 0;
- data.abbreviation = stdZone.first;
+ data.abbreviation = stdZone.name;
result << data;
return result;
}
@@ -568,18 +585,18 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
for (int year = startYear; year <= endYear; ++year) {
QTimeZonePrivate::Data dstData;
QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC);
- dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000);
- dstData.offsetFromUtc = dstZone.second;
- dstData.standardTimeOffset = stdZone.second;
- dstData.daylightTimeOffset = dstZone.second - stdZone.second;
- dstData.abbreviation = dstZone.first;
+ dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.offset * 1000);
+ dstData.offsetFromUtc = dstZone.offset;
+ dstData.standardTimeOffset = stdZone.offset;
+ dstData.daylightTimeOffset = dstZone.offset - stdZone.offset;
+ dstData.abbreviation = dstZone.name;
QTimeZonePrivate::Data stdData;
QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC);
- stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000);
- stdData.offsetFromUtc = stdZone.second;
- stdData.standardTimeOffset = stdZone.second;
+ stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.offset * 1000);
+ stdData.offsetFromUtc = stdZone.offset;
+ stdData.standardTimeOffset = stdZone.offset;
stdData.daylightTimeOffset = 0;
- stdData.abbreviation = stdZone.first;
+ stdData.abbreviation = stdZone.name;
// Part of the high year will overflow
if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) {
if (dstData.atMSecsSinceEpoch > 0) {
@@ -598,37 +615,21 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// Create the system default time zone
QTzTimeZonePrivate::QTzTimeZonePrivate()
-#if QT_CONFIG(icu)
- : m_icu(0)
-#endif
{
init(systemTimeZoneId());
}
// Create a named time zone
QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId)
-#if QT_CONFIG(icu)
- : m_icu(0)
-#endif
{
init(ianaId);
}
-QTzTimeZonePrivate::QTzTimeZonePrivate(const QTzTimeZonePrivate &other)
- : QTimeZonePrivate(other), m_tranTimes(other.m_tranTimes),
- m_tranRules(other.m_tranRules), m_abbreviations(other.m_abbreviations),
-#if QT_CONFIG(icu)
- m_icu(other.m_icu),
-#endif
- m_posixRule(other.m_posixRule)
-{
-}
-
QTzTimeZonePrivate::~QTzTimeZonePrivate()
{
}
-QTimeZonePrivate *QTzTimeZonePrivate::clone()
+QTzTimeZonePrivate *QTzTimeZonePrivate::clone() const
{
return new QTzTimeZonePrivate(*this);
}
@@ -725,19 +726,61 @@ void QTzTimeZonePrivate::init(const QByteArray &ianaId)
}
}
- // Now for each transition time calculate our rule and save them
- m_tranTimes.reserve(tranList.count());
- for (const QTzTransition &tz_tran : qAsConst(tranList)) {
+ // Now for each transition time calculate and store our rule:
+ const int tranCount = tranList.count();;
+ m_tranTimes.reserve(tranCount);
+ // The DST offset when in effect: usually stable, usually an hour:
+ int lastDstOff = 3600;
+ for (int i = 0; i < tranCount; i++) {
+ const QTzTransition &tz_tran = tranList.at(i);
QTzTransitionTime tran;
QTzTransitionRule rule;
const QTzType tz_type = typeList.at(tz_tran.tz_typeind);
// Calculate the associated Rule
- if (!tz_type.tz_isdst)
+ if (!tz_type.tz_isdst) {
utcOffset = tz_type.tz_gmtoff;
+ } else if (Q_UNLIKELY(tz_type.tz_gmtoff != utcOffset + lastDstOff)) {
+ /*
+ This might be a genuine change in DST offset, but could also be
+ DST starting at the same time as the standard offset changed. See
+ if DST's end gives a more plausible utcOffset (i.e. one closer to
+ the last we saw, or a simple whole hour):
+ */
+ // Standard offset inferred from net offset and expected DST offset:
+ const int inferStd = tz_type.tz_gmtoff - lastDstOff; // != utcOffset
+ for (int j = i + 1; j < tranCount; j++) {
+ const QTzType new_type = typeList.at(tranList.at(j).tz_typeind);
+ if (!new_type.tz_isdst) {
+ const int newUtc = new_type.tz_gmtoff;
+ if (newUtc == utcOffset) {
+ // DST-end can't help us, avoid lots of messy checks.
+ // else: See if the end matches the familiar DST offset:
+ } else if (newUtc == inferStd) {
+ utcOffset = newUtc;
+ // else: let either end shift us to one hour as DST offset:
+ } else if (tz_type.tz_gmtoff - 3600 == utcOffset) {
+ // Start does it
+ } else if (tz_type.tz_gmtoff - 3600 == newUtc) {
+ utcOffset = newUtc; // End does it
+ // else: prefer whichever end gives DST offset closer to
+ // last, but consider any offset > 0 "closer" than any <= 0:
+ } else if (newUtc < tz_type.tz_gmtoff
+ ? (utcOffset >= tz_type.tz_gmtoff
+ || qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))
+ : (utcOffset >= tz_type.tz_gmtoff
+ && qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))) {
+ utcOffset = newUtc;
+ }
+ break;
+ }
+ }
+ lastDstOff = tz_type.tz_gmtoff - utcOffset;
+ }
rule.stdOffset = utcOffset;
rule.dstOffset = tz_type.tz_gmtoff - utcOffset;
rule.abbreviationIndex = tz_type.tz_abbrind;
+
// If the rule already exist then use that, otherwise add it
int ruleIndex = m_tranRules.indexOf(rule);
if (ruleIndex == -1) {
diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp
index 4febeda537..f963e10333 100644
--- a/src/corelib/tools/qtimezoneprivate_win.cpp
+++ b/src/corelib/tools/qtimezoneprivate_win.cpp
@@ -299,7 +299,7 @@ static QByteArray windowsSystemZoneId()
id = readRegistryString(key, L"TimeZoneKeyName");
RegCloseKey(key);
if (!id.isEmpty())
- return id.toUtf8();
+ return std::move(id).toUtf8();
}
// On XP we have to iterate over the zones until we find a match on
@@ -415,7 +415,7 @@ QWinTimeZonePrivate::~QWinTimeZonePrivate()
{
}
-QTimeZonePrivate *QWinTimeZonePrivate::clone()
+QWinTimeZonePrivate *QWinTimeZonePrivate::clone() const
{
return new QWinTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 8b9df7c12b..d99eebd4b9 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -165,6 +165,16 @@ public:
}
}
+ void append(T &&t) {
+ if (s == a)
+ realloc(s, s << 1);
+ const int idx = s++;
+ if (QTypeInfo<T>::isComplex)
+ new (ptr + idx) T(std::move(t));
+ else
+ ptr[idx] = std::move(t);
+ }
+
void append(const T *buf, int size);
inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
{ append(t); return *this; }
@@ -218,6 +228,7 @@ public:
// STL compatibility:
inline bool empty() const { return isEmpty(); }
inline void push_back(const T &t) { append(t); }
+ void push_back(T &&t) { append(std::move(t)); }
inline void pop_back() { removeLast(); }
inline T &front() { return first(); }
inline const T &front() const { return first(); }
@@ -363,7 +374,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
a = Prealloc;
}
s = 0;
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
QT_TRY {
// copy all the old elements
while (s < copySize) {
@@ -456,7 +467,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
if (n != 0) {
resize(s + n);
const T copy(t);
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
T *b = ptr + offset;
T *j = ptr + s;
T *i = j - n;
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 5e53a969e8..127afcd069 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -303,6 +303,34 @@
*/
/*!
+ \fn void QVarLengthArray::append(T &&t)
+ \overload append
+ \since 5.9
+
+ \note Unlike the lvalue overload of append(), passing a reference to
+ an object that is already an element of \c *this leads to undefined
+ behavior:
+
+ \code
+ vla.append(std::move(vla[0])); // BUG: passing an object that is already in the container
+ \endcode
+*/
+
+/*!
+ \fn void QVarLengthArray::push_back(T &&t)
+ \overload push_back
+ \since 5.9
+
+ \note Unlike the lvalue overload of push_back(), passing a reference to
+ an object that is already an element of \c *this leads to undefined
+ behavior:
+
+ \code
+ vla.push_back(std::move(vla[0])); // BUG: passing an object that is already in the container
+ \endcode
+*/
+
+/*!
\fn inline void QVarLengthArray::removeLast()
\since 4.5
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index e345163c2f..57e80ae125 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -554,7 +554,7 @@ void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::Allo
T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
T *dst = x->begin();
- if (QTypeInfo<T>::isStatic || (isShared && QTypeInfo<T>::isComplex)) {
+ if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
// we can not move the data, we need to copy construct it
while (srcBegin != srcEnd) {
new (dst++) T(*srcBegin++);
@@ -599,7 +599,7 @@ void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::Allo
}
if (d != x) {
if (!d->ref.deref()) {
- if (QTypeInfo<T>::isStatic || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
+ if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
// data was copy constructed, we need to call destructors
// or if !alloc we did nothing to the old 'd'.
freeData(d);
@@ -698,7 +698,7 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
const T copy(t);
if (!isDetached() || d->size + n > int(d->alloc))
reallocData(d->size, d->size + n, QArrayData::Grow);
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
T *b = d->end();
T *i = d->end() + n;
while (i != b)
@@ -747,7 +747,7 @@ typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
detach();
abegin = d->begin() + itemsUntouched;
aend = abegin + itemsToErase;
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
iterator moveBegin = abegin + itemsToErase;
iterator moveEnd = d->end();
while (moveBegin != moveEnd) {
diff --git a/src/corelib/tools/qvsnprintf.cpp b/src/corelib/tools/qvsnprintf.cpp
index 472b1f282c..43a21771a1 100644
--- a/src/corelib/tools/qvsnprintf.cpp
+++ b/src/corelib/tools/qvsnprintf.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_VSNPRINTF
+#if !defined(QT_VSNPRINTF) || defined(Q_CLANG_QDOC)
/*!
\relates QByteArray
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 1c9b34dacd..b93ec824ed 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -125,7 +125,6 @@ else:unix {
}
else:win32 {
SOURCES += tools/qlocale_win.cpp
- winphone: LIBS_PRIVATE += -lWindowsPhoneGlobalizationUtil
winrt-*-msvc2013: LIBS += advapi32.lib
} else:integrity {
SOURCES += tools/qlocale_unix.cpp
@@ -172,7 +171,7 @@ qtConfig(timezone) {
}
qtConfig(regularexpression) {
- QMAKE_USE_PRIVATE += pcre
+ QMAKE_USE_PRIVATE += pcre2
HEADERS += tools/qregularexpression.h
SOURCES += tools/qregularexpression.cpp