summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qarraydata.h2
-rw-r--r--src/corelib/tools/qbytearray.cpp276
-rw-r--r--src/corelib/tools/qbytearray.h17
-rw-r--r--src/corelib/tools/qcontiguouscache.h2
-rw-r--r--src/corelib/tools/qcryptographichash.cpp40
-rw-r--r--src/corelib/tools/qcryptographichash.h1
-rw-r--r--src/corelib/tools/qhash.h2
-rw-r--r--src/corelib/tools/qlinkedlist.h2
-rw-r--r--src/corelib/tools/qlist.h2
-rw-r--r--src/corelib/tools/qlocale.cpp31
-rw-r--r--src/corelib/tools/qmap.h2
-rw-r--r--src/corelib/tools/qregexp.cpp56
-rw-r--r--src/corelib/tools/qregularexpression.cpp220
-rw-r--r--src/corelib/tools/qregularexpression.h5
-rw-r--r--src/corelib/tools/qregularexpression_p.h70
-rw-r--r--src/corelib/tools/qringbuffer.cpp8
-rw-r--r--src/corelib/tools/qset.h2
-rw-r--r--src/corelib/tools/qshareddata.h24
-rw-r--r--src/corelib/tools/qsimd.cpp254
-rw-r--r--src/corelib/tools/qsimd_p.h165
-rw-r--r--src/corelib/tools/qsimd_x86.cpp116
-rw-r--r--src/corelib/tools/qsimd_x86_p.h224
-rw-r--r--src/corelib/tools/qstring.cpp453
-rw-r--r--src/corelib/tools/qstring.h4
-rw-r--r--src/corelib/tools/qtimezone.cpp14
-rw-r--r--src/corelib/tools/qtimezoneprivate.cpp18
-rw-r--r--src/corelib/tools/qtimezoneprivate_p.h3
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp5
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp1
-rw-r--r--src/corelib/tools/tools.pri18
30 files changed, 1415 insertions, 622 deletions
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index f0cc56e899..a642fb9b39 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -159,6 +159,7 @@ struct QTypedArrayData
inline iterator &operator-=(int j) { i-=j; return *this; }
inline iterator operator+(int j) const { return iterator(i+j); }
inline iterator operator-(int j) const { return iterator(i-j); }
+ friend inline iterator operator+(int j, iterator k) { return k + j; }
inline int operator-(iterator j) const { return i - j.i; }
inline operator T*() const { return i; }
};
@@ -194,6 +195,7 @@ struct QTypedArrayData
inline const_iterator &operator-=(int j) { i-=j; return *this; }
inline const_iterator operator+(int j) const { return const_iterator(i+j); }
inline const_iterator operator-(int j) const { return const_iterator(i-j); }
+ friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
inline int operator-(const_iterator j) const { return i - j.i; }
inline operator const T*() const { return i; }
};
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 424420204a..d8d8be7a26 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -47,6 +47,7 @@
#include "qlocale_p.h"
#include "qlocale_tools_p.h"
#include "private/qnumeric_p.h"
+#include "private/qsimd_p.h"
#include "qstringalgorithms_p.h"
#include "qscopedpointer.h"
#include "qbytearray_p.h"
@@ -356,7 +357,8 @@ char *qstrncpy(char *dst, const char *src, uint len)
Special case 2: Returns an arbitrary non-zero value if \a str1 is
nullptr or \a str2 is nullptr (but not both).
- \sa qstrncmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons}
+ \sa qstrncmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons},
+ QByteArray::compare()
*/
int qstrcmp(const char *str1, const char *str2)
{
@@ -381,7 +383,8 @@ int qstrcmp(const char *str1, const char *str2)
Special case 2: Returns a random non-zero value if \a str1 is nullptr
or \a str2 is nullptr (but not both).
- \sa qstrcmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons}
+ \sa qstrcmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons},
+ QByteArray::compare()
*/
/*! \relates QByteArray
@@ -400,21 +403,80 @@ int qstrcmp(const char *str1, const char *str2)
Special case 2: Returns a random non-zero value if \a str1 is nullptr
or \a str2 is nullptr (but not both).
- \sa qstrcmp(), qstrncmp(), qstrnicmp(), {8-bit Character Comparisons}
+ \sa qstrcmp(), qstrncmp(), qstrnicmp(), {8-bit Character Comparisons},
+ QByteArray::compare()
*/
int qstricmp(const char *str1, const char *str2)
{
const uchar *s1 = reinterpret_cast<const uchar *>(str1);
const uchar *s2 = reinterpret_cast<const uchar *>(str2);
- int res;
- uchar c;
- if (!s1 || !s2)
- return s1 ? 1 : (s2 ? -1 : 0);
- for (; !(res = (c = latin1_lowercased[*s1]) - latin1_lowercased[*s2]); s1++, s2++)
- if (!c) // strings are equal
- break;
- return res;
+ if (!s1)
+ return s2 ? -1 : 0;
+ if (!s2)
+ return 1;
+
+ enum { Incomplete = 256 };
+ qptrdiff offset = 0;
+ auto innerCompare = [=, &offset](qptrdiff max, bool unlimited) {
+ max += offset;
+ do {
+ uchar c = latin1_lowercased[s1[offset]];
+ int res = c - latin1_lowercased[s2[offset]];
+ if (Q_UNLIKELY(res))
+ return res;
+ if (Q_UNLIKELY(!c))
+ return 0;
+ ++offset;
+ } while (unlimited || offset < max);
+ return int(Incomplete);
+ };
+
+#ifdef __SSE4_1__
+ enum { PageSize = 4096, PageMask = PageSize - 1 };
+ const __m128i zero = _mm_setzero_si128();
+ forever {
+ // Calculate how many bytes we can load until we cross a page boundary
+ // for either source. This isn't an exact calculation, just something
+ // very quick.
+ quintptr u1 = quintptr(s1 + offset);
+ quintptr u2 = quintptr(s2 + offset);
+ uint n = PageSize - ((u1 | u2) & PageMask);
+
+ qptrdiff maxoffset = offset + n;
+ for ( ; offset + 16 <= maxoffset; offset += sizeof(__m128i)) {
+ // load 16 bytes from either source
+ __m128i a = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s1 + offset));
+ __m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s2 + offset));
+
+ // compare the two against each oher
+ __m128i cmp = _mm_cmpeq_epi8(a, b);
+
+ // find NUL terminators too
+ cmp = _mm_min_epu8(cmp, a);
+ cmp = _mm_cmpeq_epi8(cmp, zero);
+
+ // was there any difference or a NUL?
+ uint mask = _mm_movemask_epi8(cmp);
+ if (mask) {
+ // yes, find out where
+ uint start = qCountTrailingZeroBits(mask);
+ uint end = sizeof(mask) * 8 - qCountLeadingZeroBits(mask);
+ Q_ASSUME(end >= start);
+ offset += start;
+ n = end - start;
+ break;
+ }
+ }
+
+ // using SIMD could cause a page fault, so iterate byte by byte
+ int res = innerCompare(n, false);
+ if (res != Incomplete)
+ return res;
+ }
+#endif
+
+ return innerCompare(-1, true);
}
/*! \relates QByteArray
@@ -434,7 +496,8 @@ int qstricmp(const char *str1, const char *str2)
Special case 2: Returns a random non-zero value if \a str1 is nullptr
or \a str2 is nullptr (but not both).
- \sa qstrcmp(), qstrncmp(), qstricmp(), {8-bit Character Comparisons}
+ \sa qstrcmp(), qstrncmp(), qstricmp(), {8-bit Character Comparisons},
+ QByteArray::compare()
*/
int qstrnicmp(const char *str1, const char *str2, uint len)
@@ -456,6 +519,55 @@ int qstrnicmp(const char *str1, const char *str2, uint len)
/*!
\internal
+ \since 5.12
+
+ A helper for QByteArray::compare. Compares \a len1 bytes from \a str1 to \a
+ len2 bytes from \a str2. If \a len2 is -1, then \a str2 is expected to be
+ null-terminated.
+ */
+int qstrnicmp(const char *str1, qsizetype len1, const char *str2, qsizetype len2)
+{
+ Q_ASSERT(str1);
+ Q_ASSERT(len1 >= 0);
+ Q_ASSERT(len2 >= -1);
+ const uchar *s1 = reinterpret_cast<const uchar *>(str1);
+ const uchar *s2 = reinterpret_cast<const uchar *>(str2);
+ if (!s2)
+ return len1 == 0 ? 0 : 1;
+
+ int res;
+ uchar c;
+ if (len2 == -1) {
+ // null-terminated str2
+ qsizetype i;
+ for (i = 0; i < len1; ++i) {
+ c = latin1_lowercased[s2[i]];
+ if (!c)
+ return 1;
+
+ res = latin1_lowercased[s1[i]] - c;
+ if (res)
+ return res;
+ }
+ c = latin1_lowercased[s2[i]];
+ return c ? -1 : 0;
+ } else {
+ // not null-terminated
+ for (qsizetype i = 0; i < qMin(len1, len2); ++i) {
+ c = latin1_lowercased[s2[i]];
+ res = latin1_lowercased[s1[i]] - c;
+ if (res)
+ return res;
+ }
+ if (len1 == len2)
+ return 0;
+ return len1 < len2 ? -1 : 1;
+ }
+}
+
+/*!
+ \internal
+ ### Qt6: replace the QByteArray parameter with [pointer,len] pair
*/
int qstrcmp(const QByteArray &str1, const char *str2)
{
@@ -483,6 +595,7 @@ int qstrcmp(const QByteArray &str1, const char *str2)
/*!
\internal
+ ### Qt6: replace the QByteArray parameter with [pointer,len] pair
*/
int qstrcmp(const QByteArray &str1, const QByteArray &str2)
{
@@ -950,7 +1063,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
$LC_CTYPE is set, most Unix systems do "the right thing".)
Functions that this affects include contains(), indexOf(),
lastIndexOf(), operator<(), operator<=(), operator>(),
- operator>=(), toLower() and toUpper().
+ operator>=(), isLower(), isUpper(), toLower() and toUpper().
This issue does not apply to \l{QString}s since they represent
characters using Unicode.
@@ -2864,6 +2977,31 @@ int QByteArray::count(char ch) const
*/
/*!
+ \fn int QByteArray::compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ \since 5.12
+
+ Returns an integer less than, equal to, or greater than zero depending on
+ whether this QByteArray sorts before, at the same position, or after the
+ string pointed to by \a c. The comparison is performed according to case
+ sensitivity \a cs.
+
+ \sa operator==
+*/
+
+/*!
+ \fn int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ \overload
+ \since 5.12
+
+ Returns an integer less than, equal to, or greater than zero depending on
+ whether this QByteArray sorts before, at the same position, or after the
+ QByteArray \a a. The comparison is performed according to case sensitivity
+ \a cs.
+
+ \sa operator==
+*/
+
+/*!
Returns \c true if this byte array starts with byte array \a ba;
otherwise returns \c false.
@@ -2941,6 +3079,78 @@ bool QByteArray::endsWith(const char *str) const
return qstrncmp(d->data() + d->size - len, str, len) == 0;
}
+/*!
+ Returns true if \a c is an uppercase Latin1 letter.
+ \note The multiplication sign 0xD7 and the sz ligature 0xDF are not
+ treated as uppercase Latin1.
+ */
+static inline bool isUpperCaseLatin1(char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return true;
+
+ return (uchar(c) >= 0xC0 && uchar(c) <= 0xDE && uchar(c) != 0xD7);
+}
+
+/*!
+ Returns \c true if this byte array contains only uppercase letters,
+ otherwise returns \c false. The byte array is interpreted as a Latin-1
+ encoded string.
+ \since 5.12
+
+ \sa isLower(), toUpper()
+*/
+bool QByteArray::isUpper() const
+{
+ if (isEmpty())
+ return false;
+
+ const char *d = data();
+
+ for (int i = 0, max = size(); i < max; ++i) {
+ if (!isUpperCaseLatin1(d[i]))
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ Returns true if \a c is an lowercase Latin1 letter.
+ \note The division sign 0xF7 is not treated as lowercase Latin1,
+ but the small y dieresis 0xFF is.
+ */
+static inline bool isLowerCaseLatin1(char c)
+{
+ if (c >= 'a' && c <= 'z')
+ return true;
+
+ return (uchar(c) >= 0xD0 && uchar(c) != 0xF7);
+}
+
+/*!
+ Returns \c true if this byte array contains only lowercase letters,
+ otherwise returns \c false. The byte array is interpreted as a Latin-1
+ encoded string.
+ \since 5.12
+
+ \sa isUpper(), toLower()
+ */
+bool QByteArray::isLower() const
+{
+ if (isEmpty())
+ return false;
+
+ const char *d = data();
+
+ for (int i = 0, max = size(); i < max; ++i) {
+ if (!isLowerCaseLatin1(d[i]))
+ return false;
+ }
+
+ return true;
+}
+
/*! \overload
Returns \c true if this byte array ends with character \a ch;
@@ -3052,7 +3262,7 @@ QByteArray QByteArray::mid(int pos, int len) const
Example:
\snippet code/src_corelib_tools_qbytearray.cpp 30
- \sa toUpper(), {8-bit Character Comparisons}
+ \sa isLower(), toUpper(), {8-bit Character Comparisons}
*/
// prevent the compiler from inlining the function in each of
@@ -3106,7 +3316,7 @@ QByteArray QByteArray::toLower_helper(QByteArray &a)
Example:
\snippet code/src_corelib_tools_qbytearray.cpp 31
- \sa toLower(), {8-bit Character Comparisons}
+ \sa isUpper(), toLower(), {8-bit Character Comparisons}
*/
QByteArray QByteArray::toUpper_helper(const QByteArray &a)
@@ -3295,6 +3505,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is equal to byte array \a a2;
otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator==(const QByteArray &a1, const char *a2)
@@ -3304,6 +3516,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is equal to string \a a2;
otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator==(const char *a1, const QByteArray &a2)
@@ -3313,6 +3527,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if string \a a1 is equal to byte array \a a2;
otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator!=(const QByteArray &a1, const QByteArray &a2)
@@ -3322,6 +3538,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is not equal to byte array \a a2;
otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator!=(const QByteArray &a1, const char *a2)
@@ -3331,6 +3549,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is not equal to string \a a2;
otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator!=(const char *a1, const QByteArray &a2)
@@ -3340,6 +3560,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if string \a a1 is not equal to byte array \a a2;
otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator<(const QByteArray &a1, const QByteArray &a2)
@@ -3349,6 +3571,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically less than byte array
\a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn inline bool operator<(const QByteArray &a1, const char *a2)
@@ -3358,6 +3582,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically less than string
\a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator<(const char *a1, const QByteArray &a2)
@@ -3367,6 +3593,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if string \a a1 is lexically less than byte array
\a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator<=(const QByteArray &a1, const QByteArray &a2)
@@ -3376,6 +3604,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically less than or equal
to byte array \a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator<=(const QByteArray &a1, const char *a2)
@@ -3385,6 +3615,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically less than or equal
to string \a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator<=(const char *a1, const QByteArray &a2)
@@ -3394,6 +3626,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if string \a a1 is lexically less than or equal
to byte array \a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator>(const QByteArray &a1, const QByteArray &a2)
@@ -3403,6 +3637,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically greater than byte
array \a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator>(const QByteArray &a1, const char *a2)
@@ -3412,6 +3648,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically greater than string
\a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator>(const char *a1, const QByteArray &a2)
@@ -3421,6 +3659,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if string \a a1 is lexically greater than byte array
\a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator>=(const QByteArray &a1, const QByteArray &a2)
@@ -3430,6 +3670,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically greater than or
equal to byte array \a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator>=(const QByteArray &a1, const char *a2)
@@ -3439,6 +3681,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if byte array \a a1 is lexically greater than or
equal to string \a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn bool operator>=(const char *a1, const QByteArray &a2)
@@ -3448,6 +3692,8 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
Returns \c true if string \a a1 is lexically greater than or
equal to byte array \a a2; otherwise returns \c false.
+
+ \sa QByteArray::compare()
*/
/*! \fn const QByteArray operator+(const QByteArray &a1, const QByteArray &a2)
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 300f795469..8ee3a29ecc 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -99,6 +99,7 @@ inline int qstrncmp(const char *str1, const char *str2, uint len)
}
Q_CORE_EXPORT int qstricmp(const char *, const char *);
Q_CORE_EXPORT int qstrnicmp(const char *, const char *, uint len);
+Q_CORE_EXPORT int qstrnicmp(const char *, qsizetype, const char *, qsizetype = -1);
// implemented in qvsnprintf.cpp
Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap);
@@ -231,6 +232,9 @@ public:
int count(const char *a) const;
int count(const QByteArray &a) const;
+ inline int compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ inline int compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+
Q_REQUIRED_RESULT QByteArray left(int len) const;
Q_REQUIRED_RESULT QByteArray right(int len) const;
Q_REQUIRED_RESULT QByteArray mid(int index, int len = -1) const;
@@ -245,6 +249,9 @@ public:
bool endsWith(char c) const;
bool endsWith(const char *c) const;
+ bool isUpper() const;
+ bool isLower() const;
+
void truncate(int pos);
void chop(int n);
@@ -600,6 +607,16 @@ inline bool QByteArray::contains(const QByteArray &a) const
{ return indexOf(a) != -1; }
inline bool QByteArray::contains(char c) const
{ return indexOf(c) != -1; }
+inline int QByteArray::compare(const char *c, Qt::CaseSensitivity cs) const
+{
+ return cs == Qt::CaseSensitive ? qstrcmp(*this, c) :
+ qstrnicmp(data(), size(), c, -1);
+}
+inline int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs) const
+{
+ return cs == Qt::CaseSensitive ? qstrcmp(*this, a) :
+ qstrnicmp(data(), size(), a.data(), a.size());
+}
inline bool operator==(const QByteArray &a1, const QByteArray &a2) Q_DECL_NOTHROW
{ return (a1.size() == a2.size()) && (memcmp(a1.constData(), a2.constData(), a1.size())==0); }
inline bool operator==(const QByteArray &a1, const char *a2) Q_DECL_NOTHROW
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
index 18facf7e42..faa7263d6b 100644
--- a/src/corelib/tools/qcontiguouscache.h
+++ b/src/corelib/tools/qcontiguouscache.h
@@ -211,6 +211,7 @@ void QContiguousCache<T>::detach_helper()
template <typename T>
void QContiguousCache<T>::setCapacity(int asize)
{
+ Q_ASSERT(asize >= 0);
if (asize == d->alloc)
return;
detach();
@@ -285,6 +286,7 @@ inline QContiguousCacheData *QContiguousCache<T>::allocateData(int aalloc)
template <typename T>
QContiguousCache<T>::QContiguousCache(int cap)
{
+ Q_ASSERT(cap >= 0);
d = allocateData(cap);
d->ref.store(1);
d->alloc = cap;
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index a1b121f1ee..3c79bb797d 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -544,6 +544,46 @@ QByteArray QCryptographicHash::hash(const QByteArray &data, Algorithm method)
return hash.result();
}
+/*!
+ Returns the size of the output of the selected hash \a method in bytes.
+
+ \since 5.12
+*/
+int QCryptographicHash::hashLength(QCryptographicHash::Algorithm method)
+{
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ return 20;
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ case QCryptographicHash::Md4:
+ return 16;
+ case QCryptographicHash::Md5:
+ return 16;
+ case QCryptographicHash::Sha224:
+ return SHA224HashSize;
+ case QCryptographicHash::Sha256:
+ return SHA256HashSize;
+ case QCryptographicHash::Sha384:
+ return SHA384HashSize;
+ case QCryptographicHash::Sha512:
+ return SHA512HashSize;
+ case QCryptographicHash::RealSha3_224:
+ case QCryptographicHash::Keccak_224:
+ return 224 / 8;
+ case QCryptographicHash::RealSha3_256:
+ case QCryptographicHash::Keccak_256:
+ return 256 / 8;
+ case QCryptographicHash::RealSha3_384:
+ case QCryptographicHash::Keccak_384:
+ return 384 / 8;
+ case QCryptographicHash::RealSha3_512:
+ case QCryptographicHash::Keccak_512:
+ return 512 / 8;
+#endif
+ }
+ return 0;
+}
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h
index 2f74d42405..ad1de7c756 100644
--- a/src/corelib/tools/qcryptographichash.h
+++ b/src/corelib/tools/qcryptographichash.h
@@ -101,6 +101,7 @@ public:
QByteArray result() const;
static QByteArray hash(const QByteArray &data, Algorithm method);
+ static int hashLength(Algorithm method);
private:
Q_DISABLE_COPY(QCryptographicHash)
QCryptographicHashPrivate *d;
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index ce663ce2ca..a586ca5671 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -348,6 +348,7 @@ public:
inline iterator operator-(int j) const { return operator+(-j); }
inline iterator &operator+=(int j) { return *this = *this + j; }
inline iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline iterator operator+(int j, iterator k) { return k + j; }
#ifndef QT_STRICT_ITERATORS
public:
@@ -413,6 +414,7 @@ public:
inline const_iterator operator-(int j) const { return operator+(-j); }
inline const_iterator &operator+=(int j) { return *this = *this + j; }
inline const_iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
// ### Qt 5: not sure this is necessary anymore
#ifdef QT_STRICT_ITERATORS
diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h
index c8f3f4c8c3..1e6d4df474 100644
--- a/src/corelib/tools/qlinkedlist.h
+++ b/src/corelib/tools/qlinkedlist.h
@@ -159,6 +159,7 @@ public:
inline iterator operator-(int j) const { return operator+(-j); }
inline iterator &operator+=(int j) { return *this = *this + j; }
inline iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline iterator operator+(int j, iterator k) { return k + j; }
};
friend class iterator;
@@ -193,6 +194,7 @@ public:
inline const_iterator operator-(int j) const { return operator+(-j); }
inline const_iterator &operator+=(int j) { return *this = *this + j; }
inline const_iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
};
friend class const_iterator;
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index af7659e995..c00220ad3a 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -269,6 +269,7 @@ public:
inline iterator &operator-=(difference_type j) { i-=j; return *this; }
inline iterator operator+(difference_type j) const { return iterator(i+j); }
inline iterator operator-(difference_type j) const { return iterator(i-j); }
+ friend inline iterator operator+(difference_type j, iterator k) { return k + j; }
inline int operator-(iterator j) const { return int(i - j.i); }
};
friend class iterator;
@@ -312,6 +313,7 @@ public:
inline const_iterator &operator-=(difference_type j) { i-=j; return *this; }
inline const_iterator operator+(difference_type j) const { return const_iterator(i+j); }
inline const_iterator operator-(difference_type j) const { return const_iterator(i-j); }
+ friend inline const_iterator operator+(difference_type j, const_iterator k) { return k + j; }
inline int operator-(const_iterator j) const { return int(i - j.i); }
};
friend class const_iterator;
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 00a2c05c35..e70630eb12 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -233,14 +233,6 @@ QLocaleId QLocaleId::withLikelySubtagsAdded() const
if (addLikelySubtags(id))
return id;
}
- // language_script
- if (country_id) {
- QLocaleId id = QLocaleId::fromIds(language_id, script_id, 0);
- if (addLikelySubtags(id)) {
- id.country_id = country_id;
- return id;
- }
- }
// language_region
if (script_id) {
QLocaleId id = QLocaleId::fromIds(language_id, 0, country_id);
@@ -249,6 +241,14 @@ QLocaleId QLocaleId::withLikelySubtagsAdded() const
return id;
}
}
+ // language_script
+ if (country_id) {
+ QLocaleId id = QLocaleId::fromIds(language_id, script_id, 0);
+ if (addLikelySubtags(id)) {
+ id.country_id = country_id;
+ return id;
+ }
+ }
// language
if (script_id && country_id) {
QLocaleId id = QLocaleId::fromIds(language_id, 0, 0);
@@ -258,6 +258,14 @@ QLocaleId QLocaleId::withLikelySubtagsAdded() const
return id;
}
}
+ // und_script
+ if (language_id) {
+ QLocaleId id = QLocaleId::fromIds(0, script_id, 0);
+ if (addLikelySubtags(id)) {
+ id.language_id = language_id;
+ return id;
+ }
+ }
return *this;
}
@@ -382,6 +390,13 @@ const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLoca
QList<QLocaleId> tried;
tried.push_back(likelyId);
+ // No match; try again with raw data:
+ if (!tried.contains(localeId)) {
+ if (const QLocaleData *const data = findLocaleDataById(localeId))
+ return data;
+ tried.push_back(localeId);
+ }
+
// No match; try again with likely country
if (country != QLocale::AnyCountry
&& (language != QLocale::AnyLanguage || script != QLocale::AnyScript)) {
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index a5b9096835..1cf9299e26 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -449,6 +449,7 @@ public:
inline iterator operator-(int j) const { return operator+(-j); }
inline iterator &operator+=(int j) { return *this = *this + j; }
inline iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline iterator operator+(int j, iterator k) { return k + j; }
#ifndef QT_STRICT_ITERATORS
public:
@@ -512,6 +513,7 @@ public:
inline const_iterator operator-(int j) const { return operator+(-j); }
inline const_iterator &operator+=(int j) { return *this = *this + j; }
inline const_iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
#ifdef QT_STRICT_ITERATORS
private:
diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp
index 96ddca56af..87b30c952e 100644
--- a/src/corelib/tools/qregexp.cpp
+++ b/src/corelib/tools/qregexp.cpp
@@ -3813,50 +3813,57 @@ struct QRegExpPrivate
};
#if !defined(QT_NO_REGEXP_OPTIM)
-typedef QCache<QRegExpEngineKey, QRegExpEngine> EngineCache;
-Q_GLOBAL_STATIC(EngineCache, globalEngineCache)
-static QBasicMutex globalEngineCacheMutex;
+struct QRECache
+{
+ typedef QHash<QRegExpEngineKey, QRegExpEngine *> EngineCache;
+ typedef QCache<QRegExpEngineKey, QRegExpEngine> UnusedEngineCache;
+ EngineCache usedEngines;
+ UnusedEngineCache unusedEngines;
+};
+Q_GLOBAL_STATIC(QRECache, engineCache)
+static QBasicMutex engineCacheMutex;
#endif // QT_NO_REGEXP_OPTIM
static void derefEngine(QRegExpEngine *eng, const QRegExpEngineKey &key)
{
- if (!eng->ref.deref()) {
#if !defined(QT_NO_REGEXP_OPTIM)
- if (globalEngineCache()) {
- QMutexLocker locker(&globalEngineCacheMutex);
- QT_TRY {
- globalEngineCache()->insert(key, eng, 4 + key.pattern.length() / 4);
- } QT_CATCH(const std::bad_alloc &) {
- // in case of an exception (e.g. oom), just delete the engine
- delete eng;
- }
+ QMutexLocker locker(&engineCacheMutex);
+ if (!eng->ref.deref()) {
+ if (QRECache *c = engineCache()) {
+ c->unusedEngines.insert(key, eng, 4 + key.pattern.length() / 4);
+ c->usedEngines.remove(key);
} else {
delete eng;
}
+ }
#else
- Q_UNUSED(key);
+ Q_UNUSED(key);
+ if (!eng->ref.deref())
delete eng;
#endif
- }
}
static void prepareEngine_helper(QRegExpPrivate *priv)
{
- bool initMatchState = !priv->eng;
+ Q_ASSERT(!priv->eng);
+
#if !defined(QT_NO_REGEXP_OPTIM)
- if (!priv->eng && globalEngineCache()) {
- QMutexLocker locker(&globalEngineCacheMutex);
- priv->eng = globalEngineCache()->take(priv->engineKey);
- if (priv->eng != 0)
+ QMutexLocker locker(&engineCacheMutex);
+ if (QRECache *c = engineCache()) {
+ priv->eng = c->unusedEngines.take(priv->engineKey);
+ if (!priv->eng)
+ priv->eng = c->usedEngines.value(priv->engineKey);
+ if (!priv->eng)
+ priv->eng = new QRegExpEngine(priv->engineKey);
+ else
priv->eng->ref.ref();
+
+ c->usedEngines.insert(priv->engineKey, priv->eng);
+ return;
}
#endif // QT_NO_REGEXP_OPTIM
- if (!priv->eng)
- priv->eng = new QRegExpEngine(priv->engineKey);
-
- if (initMatchState)
- priv->matchState.prepareForMatch(priv->eng);
+ priv->eng = new QRegExpEngine(priv->engineKey);
}
inline static void prepareEngine(QRegExpPrivate *priv)
@@ -3864,6 +3871,7 @@ inline static void prepareEngine(QRegExpPrivate *priv)
if (priv->eng)
return;
prepareEngine_helper(priv);
+ priv->matchState.prepareForMatch(priv->eng);
}
static void prepareEngineForMatch(QRegExpPrivate *priv, const QString &str)
diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp
index 13eff07c04..af2e46dd00 100644
--- a/src/corelib/tools/qregularexpression.cpp
+++ b/src/corelib/tools/qregularexpression.cpp
@@ -43,7 +43,7 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qhashfunctions.h>
-#include <QtCore/qreadwritelock.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qvector.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qdebug.h>
@@ -720,21 +720,14 @@ QT_BEGIN_NAMESPACE
to the \c{/u} modifier in Perl regular expressions.
\value OptimizeOnFirstUsageOption
- The regular expression will be optimized (and possibly
- JIT-compiled) on its first usage, instead of after a certain (undefined)
- number of usages. See also \l{QRegularExpression::}{optimize()}.
- This enum value has been introduced in Qt 5.4.
+ This option is ignored. A regular expression is automatically optimized
+ (including JIT compiling) the first time it is used. This enum value
+ was introduced in Qt 5.4.
\value DontAutomaticallyOptimizeOption
- Regular expressions are automatically optimized after a
- certain number of usages; setting this option prevents such
- optimizations, therefore avoiding possible unpredictable spikes in
- CPU and memory usage. If both this option and the
- \c{OptimizeOnFirstUsageOption} option are set, then this option takes
- precedence. Note: this option will still let the regular expression
- to be optimized by manually calling
- \l{QRegularExpression::}{optimize()}. This enum value has been
- introduced in Qt 5.4.
+ This option is ignored. A regular expression is automatically optimized
+ (including JIT compiling) the first time it is used. This enum value
+ was introduced in Qt 5.4.
*/
/*!
@@ -791,12 +784,81 @@ QT_BEGIN_NAMESPACE
Qt 5.4.
*/
-// after how many usages we optimize the regexp
-#ifdef QT_BUILD_INTERNAL
-Q_AUTOTEST_EXPORT unsigned int qt_qregularexpression_optimize_after_use_count = 10;
-#else
-static const unsigned int qt_qregularexpression_optimize_after_use_count = 10;
-#endif // QT_BUILD_INTERNAL
+namespace QtPrivate {
+/*!
+ internal
+*/
+QString wildcardToRegularExpression(const QString &wildcardString)
+{
+ const int wclen = wildcardString.length();
+ QString rx;
+ int i = 0;
+ bool hasNegativeBracket = false;
+ const QChar *wc = wildcardString.unicode();
+
+ while (i < wclen) {
+ const QChar c = wc[i++];
+ switch (c.unicode()) {
+ case '*':
+ rx += QLatin1String(".*");
+ break;
+ case '?':
+ rx += QLatin1Char('.');
+ break;
+ case '$':
+ case '(':
+ case ')':
+ case '+':
+ case '.':
+ case '^':
+ case '{':
+ case '|':
+ case '}':
+ rx += QLatin1Char('\\');
+ rx += c;
+ break;
+ case '[':
+ // Support for the [!abc] or [!a-c] syntax
+ // Implements a negative look-behind for one char.
+ if (wc[i] == QLatin1Char(']')) {
+ rx += c;
+ rx += wc[i++];
+ } else if (wc[i] == QLatin1Char('!')) {
+ rx += QLatin1String(".(?<");
+ rx += wc[i++];
+ rx += c;
+ hasNegativeBracket = true;
+ } else {
+ rx += c;
+ }
+
+ if (i < wclen) {
+ if (rx[i] == QLatin1Char(']'))
+ rx += wc[i++];
+ while (i < wclen && wc[i] != QLatin1Char(']')) {
+ if (wc[i] == QLatin1Char('\\'))
+ rx += QLatin1Char('\\');
+ rx += wc[i++];
+ }
+ }
+ break;
+ case ']':
+ rx += c;
+ // Closes the negative look-behind expression.
+ if (hasNegativeBracket) {
+ rx += QLatin1Char(')');
+ hasNegativeBracket = false;
+ }
+ break;
+ default:
+ rx += c;
+ break;
+ }
+ }
+
+ return rx;
+}
+}
/*!
\internal
@@ -847,13 +909,7 @@ struct QRegularExpressionPrivate : QSharedData
void cleanCompiledPattern();
void compilePattern();
void getPatternInfo();
-
- enum OptimizePatternOption {
- LazyOptimizeOption,
- ImmediateOptimizeOption
- };
-
- void optimizePattern(OptimizePatternOption option);
+ void optimizePattern();
enum CheckSubjectStringOption {
CheckSubjectString,
@@ -878,16 +934,15 @@ struct QRegularExpressionPrivate : QSharedData
// *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).
- mutable QReadWriteLock mutex;
+ mutable QMutex mutex;
// 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
+ // it is set to nullptr
pcre2_code_16 *compiledPattern;
int errorCode;
int errorOffset;
int capturingCount;
- unsigned int usedCount;
bool usingCrLfNewlines;
bool isDirty;
};
@@ -952,11 +1007,10 @@ QRegularExpressionPrivate::QRegularExpressionPrivate()
patternOptions(0),
pattern(),
mutex(),
- compiledPattern(0),
+ compiledPattern(nullptr),
errorCode(0),
errorOffset(-1),
capturingCount(0),
- usedCount(0),
usingCrLfNewlines(false),
isDirty(true)
{
@@ -974,8 +1028,8 @@ QRegularExpressionPrivate::~QRegularExpressionPrivate()
\internal
Copies the private, which means copying only the pattern and the pattern
- options. The compiledPattern and the studyData pointers are NOT copied (we
- do not own them any more), and in general all the members set when
+ options. The compiledPattern pointer is NOT copied (we
+ do not own it any more), and in general all the members set when
compiling a pattern are set to default values. isDirty is set back to true
so that the pattern has to be recompiled again.
*/
@@ -984,11 +1038,10 @@ QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPri
patternOptions(other.patternOptions),
pattern(other.pattern),
mutex(),
- compiledPattern(0),
+ compiledPattern(nullptr),
errorCode(0),
errorOffset(-1),
capturingCount(0),
- usedCount(0),
usingCrLfNewlines(false),
isDirty(true)
{
@@ -1000,11 +1053,10 @@ QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPri
void QRegularExpressionPrivate::cleanCompiledPattern()
{
pcre2_code_free_16(compiledPattern);
- compiledPattern = 0;
+ compiledPattern = nullptr;
errorCode = 0;
errorOffset = -1;
capturingCount = 0;
- usedCount = 0;
usingCrLfNewlines = false;
}
@@ -1013,7 +1065,7 @@ void QRegularExpressionPrivate::cleanCompiledPattern()
*/
void QRegularExpressionPrivate::compilePattern()
{
- const QWriteLocker lock(&mutex);
+ const QMutexLocker lock(&mutex);
if (!isDirty)
return;
@@ -1040,6 +1092,7 @@ void QRegularExpressionPrivate::compilePattern()
errorCode = 0;
}
+ optimizePattern();
getPatternInfo();
}
@@ -1140,15 +1193,10 @@ static bool isJitEnabled()
The purpose of the function is to call pcre2_jit_compile_16, which
JIT-compiles the pattern.
- 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).
+ It gets called when a pattern is recompiled by us (in compilePattern()),
+ under mutex protection.
*/
-void QRegularExpressionPrivate::optimizePattern(OptimizePatternOption option)
+void QRegularExpressionPrivate::optimizePattern()
{
Q_ASSERT(compiledPattern);
@@ -1157,11 +1205,6 @@ void QRegularExpressionPrivate::optimizePattern(OptimizePatternOption option)
if (!enableJit)
return;
- const QWriteLocker lock(&mutex);
-
- if ((option == LazyOptimizeOption) && (++usedCount != qt_qregularexpression_optimize_after_use_count))
- return;
-
pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
}
@@ -1267,22 +1310,12 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
return priv;
}
- // skip optimizing and doing the actual matching if NoMatch type was requested
+ // skip doing the actual matching if NoMatch type was requested
if (matchType == QRegularExpression::NoMatch) {
priv->isValid = true;
return priv;
}
- if (!(patternOptions & QRegularExpression::DontAutomaticallyOptimizeOption)) {
- const OptimizePatternOption optimizePatternOption =
- (patternOptions & QRegularExpression::OptimizeOnFirstUsageOption)
- ? ImmediateOptimizeOption
- : LazyOptimizeOption;
-
- // this is mutex protected
- const_cast<QRegularExpressionPrivate *>(this)->optimizePattern(optimizePatternOption);
- }
-
int pcreOptions = convertToPcreOptions(matchOptions);
if (matchType == QRegularExpression::PartialPreferCompleteMatch)
@@ -1307,8 +1340,6 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
int result;
- QReadLocker lock(&mutex);
-
if (!previousMatchWasEmpty) {
result = safe_pcre2_match_16(compiledPattern,
subjectUtf16, subjectLength,
@@ -1340,8 +1371,6 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
}
}
- lock.unlock();
-
#ifdef QREGULAREXPRESSION_DEBUG
qDebug() << "Matching" << pattern << "against" << subject
<< "starting at" << subjectStart << "len" << subjectLength
@@ -1554,6 +1583,47 @@ void QRegularExpression::setPattern(const QString &pattern)
}
/*!
+ \since 5.12
+
+ Sets the pattern string of the regular expression to \a wildcard pattern.
+ The pattern options are left unchanged.
+
+ \warning Unlike QRegExp, this implementation follows closely the definition
+ of wildcard for glob patterns:
+ \table
+ \row \li \b{c}
+ \li Any character represents itself apart from those mentioned
+ below. Thus \b{c} matches the character \e c.
+ \row \li \b{?}
+ \li Matches any single character. It is the same as
+ \b{.} in full regexps.
+ \row \li \b{*}
+ \li Matches zero or more of any characters. It is the
+ same as \b{.*} in full regexps.
+ \row \li \b{[abc]}
+ \li Matches one character given in the bracket.
+ \row \li \b{[a-c]}
+ \li Matches one character from the range given in the bracket.
+ \row \li \b{[!abc]}
+ \li Matches one character that is not given in the bracket.
+ \row \li \b{[!a-c]}
+ \li matches one character that is not from the range given in the
+ bracket.
+ \endtable
+
+ \note This function generates a regular expression that will act following
+ the wildcard pattern given. However the content of the regular expression
+ will not be the same as the one set.
+
+ \sa pattern(), setPattern()
+*/
+void QRegularExpression::setWildcardPattern(const QString &pattern)
+{
+ setPattern(QtPrivate::wildcardToRegularExpression(pattern));
+}
+
+
+/*!
Returns the pattern options for the regular expression.
\sa setPatternOptions(), pattern()
@@ -1810,22 +1880,14 @@ QRegularExpressionMatchIterator QRegularExpression::globalMatch(const QStringRef
/*!
\since 5.4
- Forces an immediate optimization of the pattern, including
- JIT-compiling it (if the JIT compiler is enabled).
-
- Patterns are normally optimized only after a certain number of usages.
- If you can predict that this QRegularExpression object is going to be
- used for several matches, it may be convenient to optimize it in
- advance by calling this function.
+ Compiles the pattern immediately, including JIT compiling it (if
+ the JIT is enabled) for optimization.
- \sa QRegularExpression::OptimizeOnFirstUsageOption
+ \sa isValid(), {Debugging Code that Uses QRegularExpression}
*/
void QRegularExpression::optimize() const
{
- if (!isValid()) // will compile the pattern
- return;
-
- d->optimizePattern(QRegularExpressionPrivate::ImmediateOptimizeOption);
+ d.data()->compilePattern();
}
/*!
diff --git a/src/corelib/tools/qregularexpression.h b/src/corelib/tools/qregularexpression.h
index 398fc9ec9c..d0f90b90b3 100644
--- a/src/corelib/tools/qregularexpression.h
+++ b/src/corelib/tools/qregularexpression.h
@@ -73,8 +73,8 @@ public:
InvertedGreedinessOption = 0x0010,
DontCaptureOption = 0x0020,
UseUnicodePropertiesOption = 0x0040,
- OptimizeOnFirstUsageOption = 0x0080,
- DontAutomaticallyOptimizeOption = 0x0100
+ OptimizeOnFirstUsageOption Q_DECL_ENUMERATOR_DEPRECATED_X("This option does not have any effect since Qt 5.12") = 0x0080,
+ DontAutomaticallyOptimizeOption Q_DECL_ENUMERATOR_DEPRECATED_X("This option does not have any effect since Qt 5.12") = 0x0100,
};
Q_DECLARE_FLAGS(PatternOptions, PatternOption)
@@ -96,6 +96,7 @@ public:
QString pattern() const;
void setPattern(const QString &pattern);
+ void setWildcardPattern(const QString &pattern);
bool isValid() const;
int patternErrorOffset() const;
diff --git a/src/corelib/tools/qregularexpression_p.h b/src/corelib/tools/qregularexpression_p.h
new file mode 100644
index 0000000000..f5455de853
--- /dev/null
+++ b/src/corelib/tools/qregularexpression_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Samuel Gaist <samuel.gaist@edeltech.ch>
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREGULAREXPRESSION_P_H
+#define QREGULAREXPRESSION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qglobal_p.h>
+
+#include <qregularexpression.h>
+#include <qstring.h>
+
+QT_REQUIRE_CONFIG(regularexpression);
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+QString wildcardToRegularExpression(const QString &expression);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp
index eb7bdfe95c..59650ed2f7 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -312,12 +312,14 @@ qint64 QRingBuffer::peek(char *data, qint64 maxLength, qint64 pos) const
Q_ASSERT(maxLength >= 0 && pos >= 0);
qint64 readSoFar = 0;
- for (int i = 0; readSoFar < maxLength && i < buffers.size(); ++i) {
- qint64 blockLength = buffers[i].size();
+ for (const QRingChunk &chunk : buffers) {
+ if (readSoFar == maxLength)
+ break;
+ qint64 blockLength = chunk.size();
if (pos < blockLength) {
blockLength = qMin(blockLength - pos, maxLength - readSoFar);
- memcpy(data + readSoFar, buffers[i].data() + pos, blockLength);
+ memcpy(data + readSoFar, chunk.data() + pos, blockLength);
readSoFar += blockLength;
pos = 0;
} else {
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index 7ded120ab7..6640c8486d 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -131,6 +131,7 @@ public:
inline iterator operator--(int) { iterator r = *this; --i; return r; }
inline iterator operator+(int j) const { return i + j; }
inline iterator operator-(int j) const { return i - j; }
+ friend inline iterator operator+(int j, iterator k) { return k + j; }
inline iterator &operator+=(int j) { i += j; return *this; }
inline iterator &operator-=(int j) { i -= j; return *this; }
};
@@ -165,6 +166,7 @@ public:
inline const_iterator operator--(int) { const_iterator r = *this; --i; return r; }
inline const_iterator operator+(int j) const { return i + j; }
inline const_iterator operator-(int j) const { return i - j; }
+ friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
inline const_iterator &operator+=(int j) { i += j; return *this; }
inline const_iterator &operator-=(int j) { i -= j; return *this; }
};
diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h
index 780f2331a8..3ef134a99d 100644
--- a/src/corelib/tools/qshareddata.h
+++ b/src/corelib/tools/qshareddata.h
@@ -136,6 +136,18 @@ private:
T *d;
};
+template <class T> inline bool operator==(std::nullptr_t p1, const QSharedDataPointer<T> &p2)
+{
+ Q_UNUSED(p1);
+ return !p2;
+}
+
+template <class T> inline bool operator==(const QSharedDataPointer<T> &p1, std::nullptr_t p2)
+{
+ Q_UNUSED(p2);
+ return !p1;
+}
+
template <class T> class QExplicitlySharedDataPointer
{
public:
@@ -271,6 +283,18 @@ Q_INLINE_TEMPLATE QExplicitlySharedDataPointer<T>::QExplicitlySharedDataPointer(
: d(adata)
{ if (d) d->ref.ref(); }
+template <class T> inline bool operator==(std::nullptr_t p1, const QExplicitlySharedDataPointer<T> &p2)
+{
+ Q_UNUSED(p1);
+ return !p2;
+}
+
+template <class T> inline bool operator==(const QExplicitlySharedDataPointer<T> &p1, std::nullptr_t p2)
+{
+ Q_UNUSED(p2);
+ return !p1;
+}
+
template <class T>
Q_INLINE_TEMPLATE void qSwap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2)
{ p1.swap(p2); }
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
index 25340f2d02..85efd3cded 100644
--- a/src/corelib/tools/qsimd.cpp
+++ b/src/corelib/tools/qsimd.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -80,6 +80,43 @@
QT_BEGIN_NAMESPACE
+/*
+ * Use kdesdk/scripts/generate_string_table.pl to update the table below. Note
+ * we remove the terminating -1 that the script adds.
+ */
+
+// begin generated
+#if defined(Q_PROCESSOR_ARM)
+/* Data:
+ neon
+ crc32
+ */
+static const char features_string[] =
+ " neon\0"
+ " crc32\0"
+ "\0";
+static const int features_indices[] = { 0, 6 };
+#elif defined(Q_PROCESSOR_MIPS)
+/* Data:
+ dsp
+ dspr2
+*/
+static const char features_string[] =
+ " dsp\0"
+ " dspr2\0"
+ "\0";
+
+static const int features_indices[] = {
+ 0, 5
+};
+#elif defined(Q_PROCESSOR_X86)
+# include "qsimd_x86.cpp" // generated by util/x86simdgen
+#else
+static const char features_string[] = "";
+static const int features_indices[] = { };
+#endif
+// end generated
+
#if defined (Q_OS_NACL)
static inline uint detectProcessorFeatures()
{
@@ -222,29 +259,32 @@ static void cpuidFeatures01(uint &ecx, uint &edx)
inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int));}
#endif
-static void cpuidFeatures07_00(uint &ebx, uint &ecx)
+static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
{
#if defined(Q_CC_GNU)
qregisteruint rbx; // in case it's 64-bit
qregisteruint rcx = 0;
+ qregisteruint rdx = 0;
asm ("xchg " PICreg", %0\n"
"cpuid\n"
"xchg " PICreg", %0\n"
- : "=&r" (rbx), "+&c" (rcx)
- : "a" (7)
- : "%edx");
+ : "=&r" (rbx), "+&c" (rcx), "+&d" (rdx)
+ : "a" (7));
ebx = rbx;
ecx = rcx;
+ edx = rdx;
#elif defined(Q_OS_WIN)
int info[4];
__cpuidex(info, 7, 0);
ebx = info[1];
ecx = info[2];
+ edx = info[3];
#elif defined(Q_CC_GHS)
unsigned int info[4];
__CPUIDEX(7, 0, info);
ebx = info[1];
ecx = info[2];
+ edx = info[3];
#endif
}
@@ -282,13 +322,8 @@ static quint64 detectProcessorFeatures()
AVXState = XMM0_15 | YMM0_15Hi128,
AVX512State = AVXState | OpMask | ZMM0_15Hi256 | ZMM16_31
};
- static const quint64 AllAVX512 = (Q_UINT64_C(1) << CpuFeatureAVX512F) | (Q_UINT64_C(1) << CpuFeatureAVX512CD) |
- (Q_UINT64_C(1) << CpuFeatureAVX512ER) | (Q_UINT64_C(1) << CpuFeatureAVX512PF) |
- (Q_UINT64_C(1) << CpuFeatureAVX512BW) | (Q_UINT64_C(1) << CpuFeatureAVX512DQ) |
- (Q_UINT64_C(1) << CpuFeatureAVX512VL) |
- (Q_UINT64_C(1) << CpuFeatureAVX512IFMA) | (Q_UINT64_C(1) << CpuFeatureAVX512VBMI);
- static const quint64 AllAVX2 = (Q_UINT64_C(1) << CpuFeatureAVX2) | AllAVX512;
- static const quint64 AllAVX = (Q_UINT64_C(1) << CpuFeatureAVX) | AllAVX2;
+ static const quint64 AllAVX2 = CpuFeatureAVX2 | AllAVX512;
+ static const quint64 AllAVX = CpuFeatureAVX | AllAVX2;
quint64 features = 0;
int cpuidLevel = maxBasicCpuidSupported();
@@ -299,52 +334,33 @@ static quint64 detectProcessorFeatures()
Q_ASSERT(cpuidLevel >= 1);
#endif
- uint cpuid01ECX = 0, cpuid01EDX = 0;
- cpuidFeatures01(cpuid01ECX, cpuid01EDX);
-
- // the low 32-bits of features is cpuid01ECX
- // note: we need to check OS support for saving the AVX register state
- features = cpuid01ECX;
-
-#if defined(Q_PROCESSOR_X86_32)
- // x86 might not have SSE2 support
- if (cpuid01EDX & (1u << 26))
- features |= Q_UINT64_C(1) << CpuFeatureSSE2;
- else
- features &= ~(Q_UINT64_C(1) << CpuFeatureSSE2);
- // we should verify that the OS enabled saving of the SSE state...
-#else
- // x86-64 or x32
- features |= Q_UINT64_C(1) << CpuFeatureSSE2;
-#endif
+ uint results[X86CpuidMaxLeaf] = {};
+ cpuidFeatures01(results[Leaf1ECX], results[Leaf1EDX]);
+ if (cpuidLevel >= 7)
+ cpuidFeatures07_00(results[Leaf7_0EBX], results[Leaf7_0ECX], results[Leaf7_0EDX]);
+
+ // populate our feature list
+ for (uint i = 0; i < sizeof(x86_locators) / sizeof(x86_locators[0]); ++i) {
+ uint word = x86_locators[i] / 32;
+ uint bit = 1U << (x86_locators[i] % 32);
+ quint64 feature = Q_UINT64_C(1) << (i + 1);
+ if (results[word] & bit)
+ features |= feature;
+ }
+ // now check the AVX state
uint xgetbvA = 0, xgetbvD = 0;
- if (cpuid01ECX & (1u << 27)) {
+ if (results[Leaf1ECX] & (1u << 27)) {
// XGETBV enabled
xgetbv(0, xgetbvA, xgetbvD);
}
- uint cpuid0700EBX = 0;
- uint cpuid0700ECX = 0;
- if (cpuidLevel >= 7) {
- cpuidFeatures07_00(cpuid0700EBX, cpuid0700ECX);
-
- // the high 32-bits of features is cpuid0700EBX
- features |= quint64(cpuid0700EBX) << 32;
- }
-
if ((xgetbvA & AVXState) != AVXState) {
// support for YMM registers is disabled, disable all AVX
features &= ~AllAVX;
} else if ((xgetbvA & AVX512State) != AVX512State) {
// support for ZMM registers or mask registers is disabled, disable all AVX512
features &= ~AllAVX512;
- } else {
- // this feature is out of order
- if (cpuid0700ECX & (1u << 1))
- features |= Q_UINT64_C(1) << CpuFeatureAVX512VBMI;
- else
- features &= ~(Q_UINT64_C(1) << CpuFeatureAVX512VBMI);
}
return features;
@@ -493,152 +509,6 @@ static inline uint detectProcessorFeatures()
}
#endif
-/*
- * Use kdesdk/scripts/generate_string_table.pl to update the table below. Note
- * that the x86 version has a lot of blanks that must be kept and that the
- * offset table's type is changed to make the table smaller. We also remove the
- * terminating -1 that the script adds.
- */
-
-// begin generated
-#if defined(Q_PROCESSOR_ARM)
-/* Data:
- neon
- crc32
- */
-static const char features_string[] =
- " neon\0"
- " crc32\0"
- "\0";
-static const int features_indices[] = { 0, 6 };
-#elif defined(Q_PROCESSOR_MIPS)
-/* Data:
- dsp
- dspr2
-*/
-static const char features_string[] =
- " dsp\0"
- " dspr2\0"
- "\0";
-
-static const int features_indices[] = {
- 0, 5
-};
-#elif defined(Q_PROCESSOR_X86)
-/* Data:
- sse3
- sse2
- avx512vbmi
-
-
-
-
-
-
- ssse3
-
-
- fma
- cmpxchg16b
-
-
-
-
-
- sse4.1
- sse4.2
-
- movbe
- popcnt
-
- aes
-
-
- avx
- f16c
- rdrand
-
-
-
-
- bmi
- hle
- avx2
-
-
- bmi2
-
-
- rtm
-
-
-
-
- avx512f
- avx512dq
- rdseed
-
-
- avx512ifma
-
-
-
-
- avx512pf
- avx512er
- avx512cd
- sha
- avx512bw
- avx512vl
- */
-static const char features_string[] =
- " sse3\0"
- " sse2\0"
- " avx512vbmi\0"
- " ssse3\0"
- " fma\0"
- " cmpxchg16b\0"
- " sse4.1\0"
- " sse4.2\0"
- " movbe\0"
- " popcnt\0"
- " aes\0"
- " avx\0"
- " f16c\0"
- " rdrand\0"
- " bmi\0"
- " hle\0"
- " avx2\0"
- " bmi2\0"
- " rtm\0"
- " avx512f\0"
- " avx512dq\0"
- " rdseed\0"
- " avx512ifma\0"
- " avx512pf\0"
- " avx512er\0"
- " avx512cd\0"
- " sha\0"
- " avx512bw\0"
- " avx512vl\0"
- "\0";
-
-static const quint8 features_indices[] = {
- 0, 6, 12, 5, 5, 5, 5, 5,
- 5, 24, 5, 5, 31, 36, 5, 5,
- 5, 5, 5, 48, 56, 5, 64, 71,
- 5, 79, 5, 5, 84, 89, 95, 5,
- 5, 5, 5, 103, 108, 113, 5, 5,
- 119, 5, 5, 125, 5, 5, 5, 5,
- 130, 139, 149, 5, 5, 157, 5, 5,
- 5, 5, 169, 179, 189, 199, 204, 214
-};
-#else
-static const char features_string[] = "";
-static const int features_indices[] = { };
-#endif
-// end generated
-
static const int features_count = (sizeof features_indices) / (sizeof features_indices[0]);
// record what CPU features were enabled by default in this Qt build
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
index 18684caefb..af262ec88f 100644
--- a/src/corelib/tools/qsimd_p.h
+++ b/src/corelib/tools/qsimd_p.h
@@ -232,32 +232,7 @@
# define __RDRND__ 1
# endif
-#define QT_FUNCTION_TARGET_STRING_SSE2 "sse2"
-#define QT_FUNCTION_TARGET_STRING_SSE3 "sse3"
-#define QT_FUNCTION_TARGET_STRING_SSSE3 "ssse3"
-#define QT_FUNCTION_TARGET_STRING_SSE4_1 "sse4.1"
-#define QT_FUNCTION_TARGET_STRING_SSE4_2 "sse4.2"
-#define QT_FUNCTION_TARGET_STRING_AVX "avx"
-#define QT_FUNCTION_TARGET_STRING_AVX2 "avx2"
-#define QT_FUNCTION_TARGET_STRING_AVX512F "avx512f"
-#define QT_FUNCTION_TARGET_STRING_AVX512CD "avx512cd"
-#define QT_FUNCTION_TARGET_STRING_AVX512ER "avx512er"
-#define QT_FUNCTION_TARGET_STRING_AVX512PF "avx512pf"
-#define QT_FUNCTION_TARGET_STRING_AVX512BW "avx512bw"
-#define QT_FUNCTION_TARGET_STRING_AVX512DQ "avx512dq"
-#define QT_FUNCTION_TARGET_STRING_AVX512VL "avx512vl"
-#define QT_FUNCTION_TARGET_STRING_AVX512IFMA "avx512ifma"
-#define QT_FUNCTION_TARGET_STRING_AVX512VBMI "avx512vbmi"
-
-#define QT_FUNCTION_TARGET_STRING_AES "aes,sse4.2"
-#define QT_FUNCTION_TARGET_STRING_PCLMUL "pclmul,sse4.2"
-#define QT_FUNCTION_TARGET_STRING_POPCNT "popcnt"
-#define QT_FUNCTION_TARGET_STRING_F16C "f16c,avx"
-#define QT_FUNCTION_TARGET_STRING_RDRND "rdrnd"
-#define QT_FUNCTION_TARGET_STRING_BMI "bmi"
-#define QT_FUNCTION_TARGET_STRING_BMI2 "bmi2"
-#define QT_FUNCTION_TARGET_STRING_RDSEED "rdseed"
-#define QT_FUNCTION_TARGET_STRING_SHA "sha"
+# include "qsimd_x86_p.h"
#endif /* Q_PROCESSOR_X86 */
@@ -292,148 +267,36 @@
QT_BEGIN_NAMESPACE
+#ifndef Q_PROCESSOR_X86
enum CPUFeatures {
#if defined(Q_PROCESSOR_ARM)
- CpuFeatureNEON = 0,
+ CpuFeatureNEON = 2,
CpuFeatureARM_NEON = CpuFeatureNEON,
- CpuFeatureCRC32 = 1,
+ CpuFeatureCRC32 = 4,
#elif defined(Q_PROCESSOR_MIPS)
- CpuFeatureDSP = 0,
- CpuFeatureDSPR2 = 1,
-#elif defined(Q_PROCESSOR_X86)
- // The order of the flags is jumbled so it matches most closely the bits in CPUID
- // Out of order:
- CpuFeatureSSE2 = 1, // uses the bit for PCLMULQDQ
- // in level 1, ECX
- CpuFeatureSSE3 = (0 + 0),
- CpuFeatureSSSE3 = (0 + 9),
- CpuFeatureSSE4_1 = (0 + 19),
- CpuFeatureSSE4_2 = (0 + 20),
- CpuFeatureMOVBE = (0 + 22),
- CpuFeaturePOPCNT = (0 + 23),
- CpuFeatureAES = (0 + 25),
- CpuFeatureAVX = (0 + 28),
- CpuFeatureF16C = (0 + 29),
- CpuFeatureRDRND = (0 + 30),
- // 31 is always zero and we've used it for the QSimdInitialized
-
- // in level 7, leaf 0, EBX
- CpuFeatureBMI = (32 + 3),
- CpuFeatureHLE = (32 + 4),
- CpuFeatureAVX2 = (32 + 5),
- CpuFeatureBMI2 = (32 + 8),
- CpuFeatureRTM = (32 + 11),
- CpuFeatureAVX512F = (32 + 16),
- CpuFeatureAVX512DQ = (32 + 17),
- CpuFeatureRDSEED = (32 + 18),
- CpuFeatureAVX512IFMA = (32 + 21),
- CpuFeatureAVX512PF = (32 + 26),
- CpuFeatureAVX512ER = (32 + 27),
- CpuFeatureAVX512CD = (32 + 28),
- CpuFeatureSHA = (32 + 29),
- CpuFeatureAVX512BW = (32 + 30),
- CpuFeatureAVX512VL = (32 + 31),
-
- // in level 7, leaf 0, ECX (out of order, for now)
- CpuFeatureAVX512VBMI = 2, // uses the bit for DTES64
+ CpuFeatureDSP = 2,
+ CpuFeatureDSPR2 = 4,
#endif
// used only to indicate that the CPU detection was initialised
- QSimdInitialized = 0x80000000
+ QSimdInitialized = 1
};
static const quint64 qCompilerCpuFeatures = 0
-#if defined __SHA__
- | (Q_UINT64_C(1) << CpuFeatureSHA)
-#endif
-#if defined __AES__
- | (Q_UINT64_C(1) << CpuFeatureAES)
-#endif
-#if defined __RTM__
- | (Q_UINT64_C(1) << CpuFeatureRTM)
-#endif
-#ifdef __RDRND__
- | (Q_UINT64_C(1) << CpuFeatureRDRND)
-#endif
-#ifdef __RDSEED__
- | (Q_UINT64_C(1) << CpuFeatureRDSEED)
-#endif
-#if defined __BMI__
- | (Q_UINT64_C(1) << CpuFeatureBMI)
-#endif
-#if defined __BMI2__
- | (Q_UINT64_C(1) << CpuFeatureBMI2)
-#endif
-#if defined __F16C__
- | (Q_UINT64_C(1) << CpuFeatureF16C)
-#endif
-#if defined __POPCNT__
- | (Q_UINT64_C(1) << CpuFeaturePOPCNT)
-#endif
-#if defined __MOVBE__ // GCC and Clang don't seem to define this
- | (Q_UINT64_C(1) << CpuFeatureMOVBE)
-#endif
-#if defined __AVX512F__
- | (Q_UINT64_C(1) << CpuFeatureAVX512F)
-#endif
-#if defined __AVX512CD__
- | (Q_UINT64_C(1) << CpuFeatureAVX512CD)
-#endif
-#if defined __AVX512ER__
- | (Q_UINT64_C(1) << CpuFeatureAVX512ER)
-#endif
-#if defined __AVX512PF__
- | (Q_UINT64_C(1) << CpuFeatureAVX512PF)
-#endif
-#if defined __AVX512BW__
- | (Q_UINT64_C(1) << CpuFeatureAVX512BW)
-#endif
-#if defined __AVX512DQ__
- | (Q_UINT64_C(1) << CpuFeatureAVX512DQ)
-#endif
-#if defined __AVX512VL__
- | (Q_UINT64_C(1) << CpuFeatureAVX512VL)
-#endif
-#if defined __AVX512IFMA__
- | (Q_UINT64_C(1) << CpuFeatureAVX512IFMA)
-#endif
-#if defined __AVX512VBMI__
- | (Q_UINT64_C(1) << CpuFeatureAVX512VBMI)
-#endif
-#if defined __AVX2__
- | (Q_UINT64_C(1) << CpuFeatureAVX2)
-#endif
-#if defined __AVX__
- | (Q_UINT64_C(1) << CpuFeatureAVX)
-#endif
-#if defined __SSE4_2__
- | (Q_UINT64_C(1) << CpuFeatureSSE4_2)
-#endif
-#if defined __SSE4_1__
- | (Q_UINT64_C(1) << CpuFeatureSSE4_1)
-#endif
-#if defined __SSSE3__
- | (Q_UINT64_C(1) << CpuFeatureSSSE3)
-#endif
-#if defined __SSE3__
- | (Q_UINT64_C(1) << CpuFeatureSSE3)
-#endif
-#if defined __SSE2__
- | (Q_UINT64_C(1) << CpuFeatureSSE2)
-#endif
#if defined __ARM_NEON__
- | (Q_UINT64_C(1) << CpuFeatureNEON)
+ | CpuFeatureNEON
#endif
#if defined __ARM_FEATURE_CRC32
- | (Q_UINT64_C(1) << CpuFeatureCRC32)
+ | CpuFeatureCRC32
#endif
#if defined __mips_dsp
- | (Q_UINT64_C(1) << CpuFeatureDSP)
+ | CpuFeatureDSP
#endif
#if defined __mips_dspr2
- | (Q_UINT64_C(1) << CpuFeatureDSPR2)
+ | CpuFeatureDSPR2
#endif
;
+#endif
#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
extern Q_CORE_EXPORT QBasicAtomicInteger<quint64> qt_cpu_features[1];
@@ -459,8 +322,8 @@ static inline quint64 qCpuFeatures()
return features;
}
-#define qCpuHasFeature(feature) ((qCompilerCpuFeatures & (Q_UINT64_C(1) << CpuFeature ## feature)) \
- || (qCpuFeatures() & (Q_UINT64_C(1) << CpuFeature ## feature)))
+#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
+ || ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
#define ALIGNMENT_PROLOGUE_16BYTES(ptr, i, length) \
for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i)
diff --git a/src/corelib/tools/qsimd_x86.cpp b/src/corelib/tools/qsimd_x86.cpp
new file mode 100644
index 0000000000..509af464b2
--- /dev/null
+++ b/src/corelib/tools/qsimd_x86.cpp
@@ -0,0 +1,116 @@
+// This is a generated file. DO NOT EDIT.
+// Please see util/x86simdgen/generate.pl
+#include "qsimd_p.h"
+
+static const char features_string[] =
+ " sse2\0"
+ " sse3\0"
+ " ssse3\0"
+ " fma\0"
+ " sse4.1\0"
+ " sse4.2\0"
+ " movbe\0"
+ " popcnt\0"
+ " aes\0"
+ " avx\0"
+ " f16c\0"
+ " rdrnd\0"
+ " bmi\0"
+ " hle\0"
+ " avx2\0"
+ " bmi2\0"
+ " rtm\0"
+ " avx512f\0"
+ " avx512dq\0"
+ " rdseed\0"
+ " avx512ifma\0"
+ " avx512pf\0"
+ " avx512er\0"
+ " avx512cd\0"
+ " sha\0"
+ " avx512bw\0"
+ " avx512vl\0"
+ " avx512vbmi\0"
+ " avx512vbmi2\0"
+ " gfni\0"
+ " vaes\0"
+ " avx512vnni\0"
+ " avx512bitalg\0"
+ " avx512vpopcntdq\0"
+ " avx5124nniw\0"
+ " avx5124fmaps\0"
+ "\0";
+
+static const quint16 features_indices[] = {
+ 306, 0, 6, 12, 19, 24, 32, 40,
+ 47, 55, 60, 65, 71, 78, 83, 88,
+ 94, 100, 105, 114, 124, 132, 144, 154,
+ 164, 174, 179, 189, 199, 211, 224, 230,
+ 236, 248, 262, 279, 292
+};
+
+enum X86CpuidLeaves {
+ Leaf1ECX,
+ Leaf1EDX,
+ Leaf7_0EBX,
+ Leaf7_0ECX,
+ Leaf7_0EDX,
+ X86CpuidMaxLeaf
+};
+
+static const quint8 x86_locators[] = {
+ Leaf1EDX*32 + 26, // sse2
+ Leaf1ECX*32 + 0, // sse3
+ Leaf1ECX*32 + 9, // ssse3
+ Leaf1ECX*32 + 12, // fma
+ Leaf1ECX*32 + 19, // sse4.1
+ Leaf1ECX*32 + 20, // sse4.2
+ Leaf1ECX*32 + 22, // movbe
+ Leaf1ECX*32 + 23, // popcnt
+ Leaf1ECX*32 + 25, // aes
+ Leaf1ECX*32 + 28, // avx
+ Leaf1ECX*32 + 29, // f16c
+ Leaf1ECX*32 + 30, // rdrnd
+ Leaf7_0EBX*32 + 3, // bmi
+ Leaf7_0EBX*32 + 4, // hle
+ Leaf7_0EBX*32 + 5, // avx2
+ Leaf7_0EBX*32 + 8, // bmi2
+ Leaf7_0EBX*32 + 11, // rtm
+ Leaf7_0EBX*32 + 16, // avx512f
+ Leaf7_0EBX*32 + 17, // avx512dq
+ Leaf7_0EBX*32 + 18, // rdseed
+ Leaf7_0EBX*32 + 21, // avx512ifma
+ Leaf7_0EBX*32 + 26, // avx512pf
+ Leaf7_0EBX*32 + 27, // avx512er
+ Leaf7_0EBX*32 + 28, // avx512cd
+ Leaf7_0EBX*32 + 29, // sha
+ Leaf7_0EBX*32 + 30, // avx512bw
+ Leaf7_0EBX*32 + 31, // avx512vl
+ Leaf7_0ECX*32 + 1, // avx512vbmi
+ Leaf7_0ECX*32 + 6, // avx512vbmi2
+ Leaf7_0ECX*32 + 8, // gfni
+ Leaf7_0ECX*32 + 9, // vaes
+ Leaf7_0ECX*32 + 11, // avx512vnni
+ Leaf7_0ECX*32 + 12, // avx512bitalg
+ Leaf7_0ECX*32 + 14, // avx512vpopcntdq
+ Leaf7_0EDX*32 + 2, // avx5124nniw
+ Leaf7_0EDX*32 + 3 // avx5124fmaps
+};
+
+// List of AVX512 features (see detectProcessorFeatures())
+static const quint64 AllAVX512 = 0
+ | CpuFeatureAVX512F
+ | CpuFeatureAVX512DQ
+ | CpuFeatureAVX512IFMA
+ | CpuFeatureAVX512PF
+ | CpuFeatureAVX512ER
+ | CpuFeatureAVX512CD
+ | CpuFeatureAVX512BW
+ | CpuFeatureAVX512VL
+ | CpuFeatureAVX512VBMI
+ | CpuFeatureAVX512VBMI2
+ | CpuFeatureAVX512VNNI
+ | CpuFeatureAVX512BITALG
+ | CpuFeatureAVX512VPOPCNTDQ
+ | CpuFeatureAVX5124NNIW
+ | CpuFeatureAVX5124FMAPS;
diff --git a/src/corelib/tools/qsimd_x86_p.h b/src/corelib/tools/qsimd_x86_p.h
new file mode 100644
index 0000000000..c165ee0b56
--- /dev/null
+++ b/src/corelib/tools/qsimd_x86_p.h
@@ -0,0 +1,224 @@
+// This is a generated file. DO NOT EDIT.
+// Please see util/x86simdgen/generate.pl
+#ifndef QSIMD_P_H
+# error "Please include <private/qsimd_p.h> instead"
+#endif
+#ifndef QSIMD_X86_P_H
+#define QSIMD_X86_P_H
+
+#include "qsimd_p.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+// Macros for QT_FUNCTION_TARGET (for Clang and GCC)
+#define QT_FUNCTION_TARGET_STRING_SSE2 "sse2"
+#define QT_FUNCTION_TARGET_STRING_SSE3 "sse3"
+#define QT_FUNCTION_TARGET_STRING_SSSE3 "ssse3"
+#define QT_FUNCTION_TARGET_STRING_FMA "fma"
+#define QT_FUNCTION_TARGET_STRING_SSE4_1 "sse4.1"
+#define QT_FUNCTION_TARGET_STRING_SSE4_2 "sse4.2"
+#define QT_FUNCTION_TARGET_STRING_MOVBE "movbe"
+#define QT_FUNCTION_TARGET_STRING_POPCNT "popcnt"
+#define QT_FUNCTION_TARGET_STRING_AES "aes,sse4.2"
+#define QT_FUNCTION_TARGET_STRING_AVX "avx"
+#define QT_FUNCTION_TARGET_STRING_F16C "f16c"
+#define QT_FUNCTION_TARGET_STRING_RDRND "rdrnd"
+#define QT_FUNCTION_TARGET_STRING_BMI "bmi"
+#define QT_FUNCTION_TARGET_STRING_HLE "hle"
+#define QT_FUNCTION_TARGET_STRING_AVX2 "avx2"
+#define QT_FUNCTION_TARGET_STRING_BMI2 "bmi2"
+#define QT_FUNCTION_TARGET_STRING_RTM "rtm"
+#define QT_FUNCTION_TARGET_STRING_AVX512F "avx512f"
+#define QT_FUNCTION_TARGET_STRING_AVX512DQ "avx512dq"
+#define QT_FUNCTION_TARGET_STRING_RDSEED "rdseed"
+#define QT_FUNCTION_TARGET_STRING_AVX512IFMA "avx512ifma"
+#define QT_FUNCTION_TARGET_STRING_AVX512PF "avx512pf"
+#define QT_FUNCTION_TARGET_STRING_AVX512ER "avx512er"
+#define QT_FUNCTION_TARGET_STRING_AVX512CD "avx512cd"
+#define QT_FUNCTION_TARGET_STRING_SHA "sha"
+#define QT_FUNCTION_TARGET_STRING_AVX512BW "avx512bw"
+#define QT_FUNCTION_TARGET_STRING_AVX512VL "avx512vl"
+#define QT_FUNCTION_TARGET_STRING_AVX512VBMI "avx512vbmi"
+#define QT_FUNCTION_TARGET_STRING_AVX512VBMI2 "avx512vbmi2"
+#define QT_FUNCTION_TARGET_STRING_GFNI "gfni"
+#define QT_FUNCTION_TARGET_STRING_VAES "vaes"
+#define QT_FUNCTION_TARGET_STRING_AVX512VNNI "avx512vnni"
+#define QT_FUNCTION_TARGET_STRING_AVX512BITALG "avx512bitalg"
+#define QT_FUNCTION_TARGET_STRING_AVX512VPOPCNTDQ "avx512vpopcntdq"
+#define QT_FUNCTION_TARGET_STRING_AVX5124NNIW "avx5124nniw"
+#define QT_FUNCTION_TARGET_STRING_AVX5124FMAPS "avx5124fmaps"
+
+// used only to indicate that the CPU detection was initialized
+static const quint64 QSimdInitialized = Q_UINT64_C(1) << 0;
+
+// in CPUID Leaf 1, EDX:
+static const quint64 CpuFeatureSSE2 = Q_UINT64_C(1) << 1;
+
+// in CPUID Leaf 1, ECX:
+static const quint64 CpuFeatureSSE3 = Q_UINT64_C(1) << 2;
+static const quint64 CpuFeatureSSSE3 = Q_UINT64_C(1) << 3;
+static const quint64 CpuFeatureFMA = Q_UINT64_C(1) << 4;
+static const quint64 CpuFeatureSSE4_1 = Q_UINT64_C(1) << 5;
+static const quint64 CpuFeatureSSE4_2 = Q_UINT64_C(1) << 6;
+static const quint64 CpuFeatureMOVBE = Q_UINT64_C(1) << 7;
+static const quint64 CpuFeaturePOPCNT = Q_UINT64_C(1) << 8;
+static const quint64 CpuFeatureAES = Q_UINT64_C(1) << 9;
+static const quint64 CpuFeatureAVX = Q_UINT64_C(1) << 10;
+static const quint64 CpuFeatureF16C = Q_UINT64_C(1) << 11;
+static const quint64 CpuFeatureRDRND = Q_UINT64_C(1) << 12;
+
+// in CPUID Leaf 7, Sub-leaf 0, EBX:
+static const quint64 CpuFeatureBMI = Q_UINT64_C(1) << 13;
+static const quint64 CpuFeatureHLE = Q_UINT64_C(1) << 14;
+static const quint64 CpuFeatureAVX2 = Q_UINT64_C(1) << 15;
+static const quint64 CpuFeatureBMI2 = Q_UINT64_C(1) << 16;
+static const quint64 CpuFeatureRTM = Q_UINT64_C(1) << 17;
+static const quint64 CpuFeatureAVX512F = Q_UINT64_C(1) << 18;
+static const quint64 CpuFeatureAVX512DQ = Q_UINT64_C(1) << 19;
+static const quint64 CpuFeatureRDSEED = Q_UINT64_C(1) << 20;
+static const quint64 CpuFeatureAVX512IFMA = Q_UINT64_C(1) << 21;
+static const quint64 CpuFeatureAVX512PF = Q_UINT64_C(1) << 22;
+static const quint64 CpuFeatureAVX512ER = Q_UINT64_C(1) << 23;
+static const quint64 CpuFeatureAVX512CD = Q_UINT64_C(1) << 24;
+static const quint64 CpuFeatureSHA = Q_UINT64_C(1) << 25;
+static const quint64 CpuFeatureAVX512BW = Q_UINT64_C(1) << 26;
+static const quint64 CpuFeatureAVX512VL = Q_UINT64_C(1) << 27;
+
+// in CPUID Leaf 7, Sub-leaf 0, ECX:
+static const quint64 CpuFeatureAVX512VBMI = Q_UINT64_C(1) << 28;
+static const quint64 CpuFeatureAVX512VBMI2 = Q_UINT64_C(1) << 29;
+static const quint64 CpuFeatureGFNI = Q_UINT64_C(1) << 30;
+static const quint64 CpuFeatureVAES = Q_UINT64_C(1) << 31;
+static const quint64 CpuFeatureAVX512VNNI = Q_UINT64_C(1) << 32;
+static const quint64 CpuFeatureAVX512BITALG = Q_UINT64_C(1) << 33;
+static const quint64 CpuFeatureAVX512VPOPCNTDQ = Q_UINT64_C(1) << 34;
+
+// in CPUID Leaf 7, Sub-leaf 0, EDX:
+static const quint64 CpuFeatureAVX5124NNIW = Q_UINT64_C(1) << 35;
+static const quint64 CpuFeatureAVX5124FMAPS = Q_UINT64_C(1) << 36;
+
+static const quint64 qCompilerCpuFeatures = 0
+#ifdef __SSE2__
+ | (Q_UINT64_C(1) << 1) // CpuFeatureSSE2
+#endif
+#ifdef __SSE3__
+ | (Q_UINT64_C(1) << 2) // CpuFeatureSSE3
+#endif
+#ifdef __SSSE3__
+ | (Q_UINT64_C(1) << 3) // CpuFeatureSSSE3
+#endif
+#ifdef __FMA__
+ | (Q_UINT64_C(1) << 4) // CpuFeatureFMA
+#endif
+#ifdef __SSE4_1__
+ | (Q_UINT64_C(1) << 5) // CpuFeatureSSE4_1
+#endif
+#ifdef __SSE4_2__
+ | (Q_UINT64_C(1) << 6) // CpuFeatureSSE4_2
+#endif
+#ifdef __MOVBE__
+ | (Q_UINT64_C(1) << 7) // CpuFeatureMOVBE
+#endif
+#ifdef __POPCNT__
+ | (Q_UINT64_C(1) << 8) // CpuFeaturePOPCNT
+#endif
+#ifdef __AES__
+ | (Q_UINT64_C(1) << 9) // CpuFeatureAES
+#endif
+#ifdef __AVX__
+ | (Q_UINT64_C(1) << 10) // CpuFeatureAVX
+#endif
+#ifdef __F16C__
+ | (Q_UINT64_C(1) << 11) // CpuFeatureF16C
+#endif
+#ifdef __RDRND__
+ | (Q_UINT64_C(1) << 12) // CpuFeatureRDRND
+#endif
+#ifdef __BMI__
+ | (Q_UINT64_C(1) << 13) // CpuFeatureBMI
+#endif
+#ifdef __HLE__
+ | (Q_UINT64_C(1) << 14) // CpuFeatureHLE
+#endif
+#ifdef __AVX2__
+ | (Q_UINT64_C(1) << 15) // CpuFeatureAVX2
+#endif
+#ifdef __BMI2__
+ | (Q_UINT64_C(1) << 16) // CpuFeatureBMI2
+#endif
+#ifdef __RTM__
+ | (Q_UINT64_C(1) << 17) // CpuFeatureRTM
+#endif
+#ifdef __AVX512F__
+ | (Q_UINT64_C(1) << 18) // CpuFeatureAVX512F
+#endif
+#ifdef __AVX512DQ__
+ | (Q_UINT64_C(1) << 19) // CpuFeatureAVX512DQ
+#endif
+#ifdef __RDSEED__
+ | (Q_UINT64_C(1) << 20) // CpuFeatureRDSEED
+#endif
+#ifdef __AVX512IFMA__
+ | (Q_UINT64_C(1) << 21) // CpuFeatureAVX512IFMA
+#endif
+#ifdef __AVX512PF__
+ | (Q_UINT64_C(1) << 22) // CpuFeatureAVX512PF
+#endif
+#ifdef __AVX512ER__
+ | (Q_UINT64_C(1) << 23) // CpuFeatureAVX512ER
+#endif
+#ifdef __AVX512CD__
+ | (Q_UINT64_C(1) << 24) // CpuFeatureAVX512CD
+#endif
+#ifdef __SHA__
+ | (Q_UINT64_C(1) << 25) // CpuFeatureSHA
+#endif
+#ifdef __AVX512BW__
+ | (Q_UINT64_C(1) << 26) // CpuFeatureAVX512BW
+#endif
+#ifdef __AVX512VL__
+ | (Q_UINT64_C(1) << 27) // CpuFeatureAVX512VL
+#endif
+#ifdef __AVX512VBMI__
+ | (Q_UINT64_C(1) << 28) // CpuFeatureAVX512VBMI
+#endif
+#ifdef __AVX512VBMI2__
+ | (Q_UINT64_C(1) << 29) // CpuFeatureAVX512VBMI2
+#endif
+#ifdef __GFNI__
+ | (Q_UINT64_C(1) << 30) // CpuFeatureGFNI
+#endif
+#ifdef __VAES__
+ | (Q_UINT64_C(1) << 31) // CpuFeatureVAES
+#endif
+#ifdef __AVX512VNNI__
+ | (Q_UINT64_C(1) << 32) // CpuFeatureAVX512VNNI
+#endif
+#ifdef __AVX512BITALG__
+ | (Q_UINT64_C(1) << 33) // CpuFeatureAVX512BITALG
+#endif
+#ifdef __AVX512VPOPCNTDQ__
+ | (Q_UINT64_C(1) << 34) // CpuFeatureAVX512VPOPCNTDQ
+#endif
+#ifdef __AVX5124NNIW__
+ | (Q_UINT64_C(1) << 35) // CpuFeatureAVX5124NNIW
+#endif
+#ifdef __AVX5124FMAPS__
+ | (Q_UINT64_C(1) << 36) // CpuFeatureAVX5124FMAPS
+#endif
+ ;
+
+QT_END_NAMESPACE
+
+#endif // QSIMD_X86_P_H
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index a83d8833cd..d3a6851e2c 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -254,118 +254,198 @@ inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1,
#endif
#ifdef __SSE2__
+// Scans from \a ptr to \a end until \a maskval is non-zero. Returns true if
+// the no non-zero was found. Returns false and updates \a ptr to point to the
+// first 16-bit word that has any bit set (note: if the input is 8-bit, \a ptr
+// may be updated to one byte short).
static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval)
{
-# if defined(__AVX2__)
+ auto updatePtr = [&](uint result) {
+ // found a character matching the mask
+ uint idx = qCountTrailingZeroBits(~result);
+ ptr += idx;
+ return false;
+ };
+
+# if defined(__SSE4_1__)
+ __m128i mask;
+ auto updatePtrSimd = [&](__m128i data) {
+ __m128i masked = _mm_and_si128(mask, data);
+ __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
+ uint result = _mm_movemask_epi8(comparison);
+ return updatePtr(result);
+ };
+
+# if defined(__AVX2__)
// AVX2 implementation: test 32 bytes at a time
const __m256i mask256 = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(maskval));
while (ptr + 32 <= end) {
__m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
- if (!_mm256_testz_si256(mask256, data))
- return false;
+ if (!_mm256_testz_si256(mask256, data)) {
+ // found a character matching the mask
+ __m256i masked256 = _mm256_and_si256(mask256, data);
+ __m256i comparison256 = _mm256_cmpeq_epi16(masked256, _mm256_setzero_si256());
+ return updatePtr(_mm256_movemask_epi8(comparison256));
+ }
ptr += 32;
}
- const __m128i mask = _mm256_castsi256_si128(mask256);
-# elif defined(__SSE4_1__)
+ mask = _mm256_castsi256_si128(mask256);
+# else
// SSE 4.1 implementation: test 32 bytes at a time (two 16-byte
// comparisons, unrolled)
- const __m128i mask = _mm_set1_epi32(maskval);
+ mask = _mm_set1_epi32(maskval);
while (ptr + 32 <= end) {
__m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
__m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr + 16));
if (!_mm_testz_si128(mask, data1))
- return false;
+ return updatePtrSimd(data1);
+
+ ptr += 16;
if (!_mm_testz_si128(mask, data2))
- return false;
- ptr += 32;
+ return updatePtrSimd(data2);
+ ptr += 16;
}
-# endif
-# if defined(__SSE4_1__)
+# endif
+
// AVX2 and SSE4.1: final 16-byte comparison
if (ptr + 16 <= end) {
__m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
if (!_mm_testz_si128(mask, data1))
- return false;
+ return updatePtrSimd(data1);
ptr += 16;
}
+
+ // and final 8-byte comparison
+ if (ptr + 8 <= end) {
+ __m128i data1 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
+ if (!_mm_testz_si128(mask, data1))
+ return updatePtrSimd(data1);
+ ptr += 8;
+ }
+
# else
// SSE2 implementation: test 16 bytes at a time.
const __m128i mask = _mm_set1_epi32(maskval);
- while (ptr + 16 < end) {
+ while (ptr + 16 <= end) {
__m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
- __m128i masked = _mm_andnot_si128(mask, data);
+ __m128i masked = _mm_and_si128(mask, data);
__m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
- if (quint16(_mm_movemask_epi8(comparison)) != 0xffff)
- return false;
+ quint16 result = _mm_movemask_epi8(comparison);
+ if (result != 0xffff)
+ return updatePtr(result);
ptr += 16;
}
+
+ // and one 8-byte comparison
+ if (ptr + 8 <= end) {
+ __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
+ __m128i masked = _mm_and_si128(mask, data);
+ __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
+ quint8 result = _mm_movemask_epi8(comparison);
+ if (result != 0xff)
+ return updatePtr(result);
+ ptr += 8;
+ }
# endif
return true;
}
#endif
-bool QtPrivate::isAscii(QLatin1String s) Q_DECL_NOTHROW
+// Note: ptr on output may be off by one and point to a preceding US-ASCII
+// character. Usually harmless.
+bool qt_is_ascii(const char *&ptr, const char *end) Q_DECL_NOTHROW
{
- const char *ptr = s.begin();
- const char *end = s.end();
-
#if defined(__SSE2__)
// Testing for the high bit can be done efficiently with just PMOVMSKB
# if defined(__AVX2__)
while (ptr + 32 <= end) {
__m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
quint32 mask = _mm256_movemask_epi8(data);
- if (mask)
+ if (mask) {
+ uint idx = qCountTrailingZeroBits(mask);
+ ptr += idx;
return false;
+ }
ptr += 32;
}
# endif
-
while (ptr + 16 <= end) {
__m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
quint32 mask = _mm_movemask_epi8(data);
- if (mask)
+ if (mask) {
+ uint idx = qCountTrailingZeroBits(mask);
+ ptr += idx;
return false;
+ }
ptr += 16;
}
+ if (ptr + 8 <= end) {
+ __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
+ quint8 mask = _mm_movemask_epi8(data);
+ if (mask) {
+ uint idx = qCountTrailingZeroBits(mask);
+ ptr += idx;
+ return false;
+ }
+ ptr += 8;
+ }
#endif
while (ptr + 4 <= end) {
quint32 data = qFromUnaligned<quint32>(ptr);
- if (data & 0x80808080U)
+ if (data &= 0x80808080U) {
+ uint idx = qCountTrailingZeroBits(data);
+ ptr += idx / 8;
return false;
+ }
ptr += 4;
}
while (ptr != end) {
- if (quint8(*ptr++) & 0x80)
+ if (quint8(*ptr) & 0x80)
return false;
+ ++ptr;
}
return true;
}
-bool QtPrivate::isAscii(QStringView s) Q_DECL_NOTHROW
+bool QtPrivate::isAscii(QLatin1String s) Q_DECL_NOTHROW
{
- const QChar *ptr = s.begin();
- const QChar *end = s.end();
+ const char *ptr = s.begin();
+ const char *end = s.end();
+
+ return qt_is_ascii(ptr, end);
+}
+static bool isAscii(const QChar *&ptr, const QChar *end)
+{
#ifdef __SSE2__
const char *ptr8 = reinterpret_cast<const char *>(ptr);
const char *end8 = reinterpret_cast<const char *>(end);
- if (!simdTestMask(ptr8, end8, 0xff80ff80))
- return false;
+ bool ok = simdTestMask(ptr8, end8, 0xff80ff80);
ptr = reinterpret_cast<const QChar *>(ptr8);
+ if (!ok)
+ return false;
#endif
while (ptr != end) {
- if ((*ptr++).unicode() & 0xff80)
+ if (ptr->unicode() & 0xff80)
return false;
+ ++ptr;
}
return true;
}
+bool QtPrivate::isAscii(QStringView s) Q_DECL_NOTHROW
+{
+ const QChar *ptr = s.begin();
+ const QChar *end = s.end();
+
+ return isAscii(ptr, end);
+}
+
bool QtPrivate::isLatin1(QStringView s) Q_DECL_NOTHROW
{
const QChar *ptr = s.begin();
@@ -439,11 +519,19 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW
#endif
}
- size = size % 16;
+ // we're going to read str[offset..offset+7] (8 bytes)
+ if (str + offset + 7 < e) {
+ const __m128i chunk = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(str + offset));
+ const __m128i unpacked = _mm_unpacklo_epi8(chunk, _mm_setzero_si128());
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), unpacked);
+ offset += 8;
+ }
+
+ size = size % 8;
dst += offset;
str += offset;
# if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__)
- return UnrollTailLoop<15>::exec(int(size), [=](int i) { dst[i] = (uchar)str[i]; });
+ return UnrollTailLoop<7>::exec(int(size), [=](int i) { dst[i] = (uchar)str[i]; });
# endif
#endif
#if defined(__mips_dsp)
@@ -457,86 +545,117 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW
#endif
}
-#if defined(__SSE2__)
-static inline __m128i mergeQuestionMarks(__m128i chunk)
+template <bool Checked>
+static void qt_to_latin1_internal(uchar *dst, const ushort *src, qsizetype length)
{
+#if defined(__SSE2__)
+ uchar *e = dst + length;
+ qptrdiff offset = 0;
+
+# ifdef __AVX2__
+ const __m256i questionMark256 = _mm256_broadcastw_epi16(_mm_cvtsi32_si128('?'));
+ const __m256i outOfRange256 = _mm256_broadcastw_epi16(_mm_cvtsi32_si128(0x100));
+ const __m128i questionMark = _mm256_castsi256_si128(questionMark256);
+ const __m128i outOfRange = _mm256_castsi256_si128(outOfRange256);
+# else
const __m128i questionMark = _mm_set1_epi16('?');
+ const __m128i outOfRange = _mm_set1_epi16(0x100);
+# endif
-# ifdef __SSE4_2__
- // compare the unsigned shorts for the range 0x0100-0xFFFF
- // note on the use of _mm_cmpestrm:
- // The MSDN documentation online (http://technet.microsoft.com/en-us/library/bb514080.aspx)
- // says for range search the following:
- // For each character c in a, determine whether b0 <= c <= b1 or b2 <= c <= b3
- //
- // However, all examples on the Internet, including from Intel
- // (see http://software.intel.com/en-us/articles/xml-parsing-accelerator-with-intel-streaming-simd-extensions-4-intel-sse4/)
- // put the range to be searched first
- //
- // Disassembly and instruction-level debugging with GCC and ICC show
- // that they are doing the right thing. Inverting the arguments in the
- // instruction does cause a bunch of test failures.
-
- const __m128i rangeMatch = _mm_cvtsi32_si128(0xffff0100);
- const __m128i offLimitMask = _mm_cmpestrm(rangeMatch, 2, chunk, 8,
- _SIDD_UWORD_OPS | _SIDD_CMP_RANGES | _SIDD_UNIT_MASK);
-
- // replace the non-Latin 1 characters in the chunk with question marks
- chunk = _mm_blendv_epi8(chunk, questionMark, offLimitMask);
+ auto mergeQuestionMarks = [=](__m128i chunk) {
+ // SSE has no compare instruction for unsigned comparison.
+# ifdef __SSE4_1__
+ // We use an unsigned uc = qMin(uc, 0x100) and then compare for equality.
+ chunk = _mm_min_epu16(chunk, outOfRange);
+ const __m128i offLimitMask = _mm_cmpeq_epi16(chunk, outOfRange);
+ chunk = _mm_blendv_epi8(chunk, questionMark, offLimitMask);
# else
- // SSE has no compare instruction for unsigned comparison.
- // The variables must be shiffted + 0x8000 to be compared
- const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000));
- const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000));
+ // The variables must be shiffted + 0x8000 to be compared
+ const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000));
+ const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000));
- const __m128i signedChunk = _mm_add_epi16(chunk, signedBitOffset);
- const __m128i offLimitMask = _mm_cmpgt_epi16(signedChunk, thresholdMask);
+ const __m128i signedChunk = _mm_add_epi16(chunk, signedBitOffset);
+ const __m128i offLimitMask = _mm_cmpgt_epi16(signedChunk, thresholdMask);
-# ifdef __SSE4_1__
- // replace the non-Latin 1 characters in the chunk with question marks
- chunk = _mm_blendv_epi8(chunk, questionMark, offLimitMask);
-# else
- // offLimitQuestionMark contains '?' for each 16 bits that was off-limit
- // the 16 bits that were correct contains zeros
- const __m128i offLimitQuestionMark = _mm_and_si128(offLimitMask, questionMark);
+ // offLimitQuestionMark contains '?' for each 16 bits that was off-limit
+ // the 16 bits that were correct contains zeros
+ const __m128i offLimitQuestionMark = _mm_and_si128(offLimitMask, questionMark);
- // correctBytes contains the bytes that were in limit
- // the 16 bits that were off limits contains zeros
- const __m128i correctBytes = _mm_andnot_si128(offLimitMask, chunk);
+ // correctBytes contains the bytes that were in limit
+ // the 16 bits that were off limits contains zeros
+ const __m128i correctBytes = _mm_andnot_si128(offLimitMask, chunk);
- // merge offLimitQuestionMark and correctBytes to have the result
- chunk = _mm_or_si128(correctBytes, offLimitQuestionMark);
-# endif
-# endif
- return chunk;
-}
-#endif
+ // merge offLimitQuestionMark and correctBytes to have the result
+ chunk = _mm_or_si128(correctBytes, offLimitQuestionMark);
-static void qt_to_latin1(uchar *dst, const ushort *src, int length)
-{
-#if defined(__SSE2__)
- uchar *e = dst + length;
- qptrdiff offset = 0;
+ Q_UNUSED(outOfRange);
+# endif
+ return chunk;
+ };
// we're going to write to dst[offset..offset+15] (16 bytes)
for ( ; dst + offset + 15 < e; offset += 16) {
+# if defined(__AVX2__)
+ __m256i chunk = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + offset));
+ if (Checked) {
+ // See mergeQuestionMarks lambda above for details
+ chunk = _mm256_min_epu16(chunk, outOfRange256);
+ const __m256i offLimitMask = _mm256_cmpeq_epi16(chunk, outOfRange256);
+ chunk = _mm256_blendv_epi8(chunk, questionMark256, offLimitMask);
+ }
+
+ const __m128i chunk2 = _mm256_extracti128_si256(chunk, 1);
+ const __m128i chunk1 = _mm256_castsi256_si128(chunk);
+# else
__m128i chunk1 = _mm_loadu_si128((const __m128i*)(src + offset)); // load
- chunk1 = mergeQuestionMarks(chunk1);
+ if (Checked)
+ chunk1 = mergeQuestionMarks(chunk1);
__m128i chunk2 = _mm_loadu_si128((const __m128i*)(src + offset + 8)); // load
- chunk2 = mergeQuestionMarks(chunk2);
+ if (Checked)
+ chunk2 = mergeQuestionMarks(chunk2);
+# endif
// pack the two vector to 16 x 8bits elements
const __m128i result = _mm_packus_epi16(chunk1, chunk2);
_mm_storeu_si128((__m128i*)(dst + offset), result); // store
}
- length = length % 16;
+# if !defined(__OPTIMIZE_SIZE__)
+ // we're going to write to dst[offset..offset+7] (8 bytes)
+ if (dst + offset + 7 < e) {
+ __m128i chunk = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + offset));
+ if (Checked)
+ chunk = mergeQuestionMarks(chunk);
+
+ // pack, where the upper half is ignored
+ const __m128i result = _mm_packus_epi16(chunk, chunk);
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(dst + offset), result);
+ offset += 8;
+ }
+
+ // we're going to write to dst[offset..offset+3] (4 bytes)
+ if (dst + offset + 3 < e) {
+ __m128i chunk = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(src + offset));
+ if (Checked)
+ chunk = mergeQuestionMarks(chunk);
+
+ // pack, we'll the upper three quarters
+ const __m128i result = _mm_packus_epi16(chunk, chunk);
+ qToUnaligned(_mm_cvtsi128_si32(result), dst + offset);
+ offset += 4;
+ }
+
+ length = length % 4;
dst += offset;
src += offset;
-# if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__)
- return UnrollTailLoop<15>::exec(length, [=](int i) { dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i]; });
+ return UnrollTailLoop<3>::exec(length, [=](int i) {
+ if (Checked)
+ dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i];
+ else
+ dst[i] = src[i];
+ });
# endif
#elif defined(__ARM_NEON__)
// Refer to the documentation of the SSE2 implementation
@@ -551,10 +670,12 @@ static void qt_to_latin1(uchar *dst, const ushort *src, int length)
uint16x8_t chunk = vld1q_u16((uint16_t *)src); // load
src += 8;
- const uint16x8_t offLimitMask = vcgtq_u16(chunk, thresholdMask); // chunk > thresholdMask
- const uint16x8_t offLimitQuestionMark = vandq_u16(offLimitMask, questionMark); // offLimitMask & questionMark
- const uint16x8_t correctBytes = vbicq_u16(chunk, offLimitMask); // !offLimitMask & chunk
- chunk = vorrq_u16(correctBytes, offLimitQuestionMark); // correctBytes | offLimitQuestionMark
+ if (Checked) {
+ const uint16x8_t offLimitMask = vcgtq_u16(chunk, thresholdMask); // chunk > thresholdMask
+ const uint16x8_t offLimitQuestionMark = vandq_u16(offLimitMask, questionMark); // offLimitMask & questionMark
+ const uint16x8_t correctBytes = vbicq_u16(chunk, offLimitMask); // !offLimitMask & chunk
+ chunk = vorrq_u16(correctBytes, offLimitQuestionMark); // correctBytes | offLimitQuestionMark
+ }
const uint8x8_t result = vmovn_u16(chunk); // narrowing move->packing
vst1_u8(dst, result); // store
dst += 8;
@@ -566,12 +687,25 @@ static void qt_to_latin1(uchar *dst, const ushort *src, int length)
qt_toLatin1_mips_dsp_asm(dst, src, length);
#else
while (length--) {
- *dst++ = (*src>0xff) ? '?' : (uchar) *src;
+ if (Checked)
+ *dst++ = (*src>0xff) ? '?' : (uchar) *src;
+ else
+ *dst++ = *src;
++src;
}
#endif
}
+static void qt_to_latin1(uchar *dst, const ushort *src, qsizetype length)
+{
+ qt_to_latin1_internal<true>(dst, src, length);
+}
+
+void qt_to_latin1_unchecked(uchar *dst, const ushort *src, qsizetype length)
+{
+ qt_to_latin1_internal<false>(dst, src, length);
+}
+
// Unicode case-insensitive comparison
static int ucstricmp(const QChar *a, const QChar *ae, const QChar *b, const QChar *be)
{
@@ -836,12 +970,11 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l)
}
}
-# ifdef Q_PROCESSOR_X86_64
- enum { MaxTailLength = 7 };
+# if !defined(__OPTIMIZE_SIZE__)
// we'll read uc[offset..offset+7] (16 bytes) and c[offset..offset+7] (8 bytes)
if (uc + offset + 7 < e) {
// same, but we're using an 8-byte load
- __m128i chunk = _mm_cvtsi64_si128(qFromUnaligned<long long>(c + offset));
+ __m128i chunk = _mm_loadl_epi64((const __m128i*)(c + offset));
__m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask);
__m128i ucdata = _mm_loadu_si128((const __m128i*)(uc + offset));
@@ -856,17 +989,30 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l)
// still matched
offset += 8;
}
-# else
- // 32-bit, we can't do MOVQ to load 8 bytes
- Q_UNUSED(nullmask);
- enum { MaxTailLength = 15 };
-# endif
+
+ enum { MaxTailLength = 3 };
+ // we'll read uc[offset..offset+3] (8 bytes) and c[offset..offset+3] (4 bytes)
+ if (uc + offset + 3 < e) {
+ __m128i chunk = _mm_cvtsi32_si128(qFromUnaligned<int>(c + offset));
+ __m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask);
+
+ __m128i ucdata = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(uc + offset));
+ __m128i result = _mm_cmpeq_epi8(secondHalf, ucdata);
+ uint mask = ~_mm_movemask_epi8(result);
+ if (uchar(mask)) {
+ // found a different character
+ uint idx = qCountTrailingZeroBits(mask);
+ return uc[offset + idx / 2] - c[offset + idx / 2];
+ }
+
+ // still matched
+ offset += 4;
+ }
// reset uc and c
uc += offset;
c += offset;
-# if !defined(__OPTIMIZE_SIZE__)
const auto lambda = [=](size_t i) { return uc[i] - ushort(c[i]); };
return UnrollTailLoop<MaxTailLength>::exec(e - uc, 0, lambda, lambda);
# endif
@@ -930,14 +1076,12 @@ static int qt_compare_strings(QLatin1String lhs, QStringView rhs, Qt::CaseSensit
static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
+ if (cs == Qt::CaseInsensitive)
+ return qstrnicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size());
if (lhs.isEmpty())
return lencmp(0, rhs.size());
const auto l = std::min(lhs.size(), rhs.size());
- int r;
- if (cs == Qt::CaseSensitive)
- r = qstrncmp(lhs.data(), rhs.data(), l);
- else
- r = qstrnicmp(lhs.data(), rhs.data(), l);
+ int r = qstrncmp(lhs.data(), rhs.data(), l);
return r ? r : lencmp(lhs.size(), rhs.size());
}
@@ -1055,8 +1199,23 @@ static int findChar(const QChar *str, int len, QChar ch, int from,
}
}
-# if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__)
- return UnrollTailLoop<7>::exec(e - n, -1,
+# if !defined(__OPTIMIZE_SIZE__)
+ // we're going to read n[0..3] (8 bytes)
+ if (e - n > 3) {
+ __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(n));
+ __m128i result = _mm_cmpeq_epi16(data, mch);
+ uint mask = _mm_movemask_epi8(result);
+ if (uchar(mask)) {
+ // found a match
+ // same as: return n - s + _bit_scan_forward(mask) / 2
+ return (reinterpret_cast<const char *>(n) - reinterpret_cast<const char *>(s)
+ + qCountTrailingZeroBits(mask)) >> 1;
+ }
+
+ n += 4;
+ }
+
+ return UnrollTailLoop<3>::exec(e - n, -1,
[=](int i) { return n[i] == c; },
[=](int i) { return n - s + i; });
# endif
@@ -4930,16 +5089,55 @@ bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
return qt_ends_with(*this, c, cs);
}
-static QByteArray qt_convert_to_latin1(QStringView string);
+/*!
+ Returns \c true if the string only contains uppercase letters,
+ otherwise returns \c false.
+ \since 5.12
-QByteArray QString::toLatin1_helper(const QString &string)
+ \sa QChar::isUpper(), isLower()
+*/
+bool QString::isUpper() const
{
- return qt_convert_to_latin1(string);
+ if (isEmpty())
+ return false;
+
+ const QChar *d = data();
+
+ for (int i = 0, max = size(); i < max; ++i) {
+ if (!d[i].isUpper())
+ return false;
+ }
+
+ return true;
}
-QByteArray QString::toLatin1_helper(const QChar *data, int length)
+/*!
+ Returns \c true if the string only contains lowercase letters,
+ otherwise returns \c false.
+ \since 5.12
+
+ \sa QChar::isLower(), isUpper()
+ */
+bool QString::isLower() const
+{
+ if (isEmpty())
+ return false;
+
+ const QChar *d = data();
+
+ for (int i = 0, max = size(); i < max; ++i) {
+ if (!d[i].isLower())
+ return false;
+ }
+
+ return true;
+}
+
+static QByteArray qt_convert_to_latin1(QStringView string);
+
+QByteArray QString::toLatin1_helper(const QString &string)
{
- return qt_convert_to_latin1(QStringView(data, length));
+ return qt_convert_to_latin1(string);
}
/*!
@@ -6195,11 +6393,10 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
Qt::CaseSensitive);
#if defined(Q_OS_WIN)
-# ifndef Q_OS_WINRT
- int res = CompareString(GetUserDefaultLCID(), 0, (wchar_t*)data1, length1, (wchar_t*)data2, length2);
-# else
- int res = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, (LPCWSTR)data1, length1, (LPCWSTR)data2, length2, NULL, NULL, 0);
-# endif
+ QString lhs = QString::fromRawData(data1, length1).normalized(QString::NormalizationForm_C);
+ QString rhs = QString::fromRawData(data2, length2).normalized(QString::NormalizationForm_C);
+
+ int res = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, (LPWSTR)lhs.constData(), lhs.length(), (LPWSTR)rhs.constData(), rhs.length(), NULL, NULL, 0);
switch (res) {
case CSTR_LESS_THAN:
@@ -7784,19 +7981,11 @@ QString QString::repeated(int times) const
void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from)
{
- bool simple = true;
- const QChar *p = data->constData();
- int len = data->length();
- for (int i = from; i < len; ++i) {
- if (p[i].unicode() >= 0x80) {
- simple = false;
- if (i > from)
- from = i - 1;
- break;
- }
- }
- if (simple)
+ const QChar *p = data->constData() + from;
+ if (isAscii(p, p + data->length()))
return;
+ if (p > data->constData() + from)
+ from = p - data->constData() - 1; // need one before the non-ASCII to perform NFC
if (version == QChar::Unicode_Unassigned) {
version = QChar::currentUnicodeVersion();
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index f27f7efa2b..f18baf7065 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -409,6 +409,9 @@ public:
bool endsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ bool isUpper() const;
+ bool isLower() const;
+
Q_REQUIRED_RESULT 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;
@@ -875,7 +878,6 @@ private:
static QString fromUtf8_helper(const char *str, int size);
static QString fromLocal8Bit_helper(const char *, int size);
static QByteArray toLatin1_helper(const QString &);
- static QByteArray toLatin1_helper(const QChar *data, int size);
static QByteArray toLatin1_helper_inplace(QString &);
static QByteArray toUtf8_helper(const QString &);
static QByteArray toLocal8Bit_helper(const QChar *data, int size);
diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp
index daa7dc1531..db6be581ec 100644
--- a/src/corelib/tools/qtimezone.cpp
+++ b/src/corelib/tools/qtimezone.cpp
@@ -66,11 +66,10 @@ static QTimeZonePrivate *newBackendTimeZone()
return new QAndroidTimeZonePrivate();
#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED)
return new QTzTimeZonePrivate();
- // Registry based timezone backend not available on WinRT
-#elif defined Q_OS_WIN
- return new QWinTimeZonePrivate();
#elif QT_CONFIG(icu)
return new QIcuTimeZonePrivate();
+#elif defined Q_OS_WIN
+ return new QWinTimeZonePrivate();
#else
return new QUtcTimeZonePrivate();
#endif // System Locales
@@ -93,11 +92,10 @@ static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId)
return new QAndroidTimeZonePrivate(ianaId);
#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED)
return new QTzTimeZonePrivate(ianaId);
- // Registry based timezone backend not available on WinRT
-#elif defined Q_OS_WIN
- return new QWinTimeZonePrivate(ianaId);
#elif QT_CONFIG(icu)
return new QIcuTimeZonePrivate(ianaId);
+#elif defined Q_OS_WIN
+ return new QWinTimeZonePrivate(ianaId);
#else
return new QUtcTimeZonePrivate(ianaId);
#endif // System Locales
@@ -822,8 +820,8 @@ bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &ianaId)
// IDs as availableTimeZoneIds() may be slow
if (!QTimeZonePrivate::isValidId(ianaId))
return false;
- const QList<QByteArray> tzIds = availableTimeZoneIds();
- return std::binary_search(tzIds.begin(), tzIds.end(), ianaId);
+ return QUtcTimeZonePrivate().isTimeZoneIdAvailable(ianaId) ||
+ global_tz->backend->isTimeZoneIdAvailable(ianaId);
}
static QList<QByteArray> set_union(const QList<QByteArray> &l1, const QList<QByteArray> &l2)
diff --git a/src/corelib/tools/qtimezoneprivate.cpp b/src/corelib/tools/qtimezoneprivate.cpp
index 1a5135f103..2b6c2ea6a5 100644
--- a/src/corelib/tools/qtimezoneprivate.cpp
+++ b/src/corelib/tools/qtimezoneprivate.cpp
@@ -486,6 +486,13 @@ QByteArray QTimeZonePrivate::systemTimeZoneId() const
return QByteArray();
}
+bool QTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray& ianaId) const
+{
+ // Fall-back implementation, can be made faster in subclasses
+ const QList<QByteArray> tzIds = availableTimeZoneIds();
+ return std::binary_search(tzIds.begin(), tzIds.end(), ianaId);
+}
+
QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds() const
{
return QList<QByteArray>();
@@ -864,6 +871,17 @@ QByteArray QUtcTimeZonePrivate::systemTimeZoneId() const
return utcQByteArray();
}
+bool QUtcTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
+{
+ for (int i = 0; i < utcDataTableSize; ++i) {
+ const QUtcData *data = utcData(i);
+ if (utcId(data) == ianaId) {
+ return true;
+ }
+ }
+ return false;
+}
+
QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds() const
{
QList<QByteArray> result;
diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h
index 4d357111f2..c9a5726216 100644
--- a/src/corelib/tools/qtimezoneprivate_p.h
+++ b/src/corelib/tools/qtimezoneprivate_p.h
@@ -128,6 +128,7 @@ public:
virtual QByteArray systemTimeZoneId() const;
+ virtual bool isTimeZoneIdAvailable(const QByteArray &ianaId) const;
virtual QList<QByteArray> availableTimeZoneIds() const;
virtual QList<QByteArray> availableTimeZoneIds(QLocale::Country country) const;
virtual QList<QByteArray> availableTimeZoneIds(int utcOffset) const;
@@ -204,6 +205,7 @@ public:
QByteArray systemTimeZoneId() const override;
+ bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
QList<QByteArray> availableTimeZoneIds() const override;
QList<QByteArray> availableTimeZoneIds(QLocale::Country country) const override;
QList<QByteArray> availableTimeZoneIds(int utcOffset) const override;
@@ -323,6 +325,7 @@ public:
QByteArray systemTimeZoneId() const override;
+ bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
QList<QByteArray> availableTimeZoneIds() const override;
QList<QByteArray> availableTimeZoneIds(QLocale::Country country) const override;
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
index 6a5df6272a..f1735a80e7 100644
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
@@ -1098,6 +1098,11 @@ QByteArray QTzTimeZonePrivate::systemTimeZoneId() const
return ianaId;
}
+bool QTzTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
+{
+ return tzZones->contains(ianaId);
+}
+
QList<QByteArray> QTzTimeZonePrivate::availableTimeZoneIds() const
{
QList<QByteArray> result = tzZones->keys();
diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp
index 8bde07c710..ec91b7e8a8 100644
--- a/src/corelib/tools/qtimezoneprivate_win.cpp
+++ b/src/corelib/tools/qtimezoneprivate_win.cpp
@@ -49,6 +49,7 @@
QT_BEGIN_NAMESPACE
#ifndef Q_OS_WINRT
+// The registry-based timezone backend is not available on WinRT, which falls back to equivalent APIs.
#define QT_USE_REGISTRY_TIMEZONE 1
#endif
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 72224f280d..30f7edb5f2 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -159,16 +159,18 @@ qtConfig(timezone) {
SOURCES += \
tools/qtimezone.cpp \
tools/qtimezoneprivate.cpp
- !nacl:darwin: \
+ !nacl:darwin: {
SOURCES += tools/qtimezoneprivate_mac.mm
- else: android:!android-embedded: \
+ } else: android:!android-embedded: {
SOURCES += tools/qtimezoneprivate_android.cpp
- else: unix: \
+ } else: unix: {
SOURCES += tools/qtimezoneprivate_tz.cpp
- else: win32: \
- SOURCES += tools/qtimezoneprivate_win.cpp
- qtConfig(icu): \
+ qtConfig(icu): SOURCES += tools/qtimezoneprivate_icu.cpp
+ } else: qtConfig(icu): {
SOURCES += tools/qtimezoneprivate_icu.cpp
+ } else: win32: {
+ SOURCES += tools/qtimezoneprivate_win.cpp
+ }
}
qtConfig(datetimeparser) {
@@ -179,7 +181,9 @@ qtConfig(datetimeparser) {
qtConfig(regularexpression) {
QMAKE_USE_PRIVATE += pcre2
- HEADERS += tools/qregularexpression.h
+ HEADERS += \
+ tools/qregularexpression.h \
+ tools/qregularexpression_p.h
SOURCES += tools/qregularexpression.cpp
}