summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2018-02-06 12:38:51 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2018-02-10 15:55:52 +0100
commit32b506d1db1f8cee748a27b548ba8208f2928058 (patch)
tree2d5b23baafe22ccc3518719f8f5d19bb846b2b61 /src/corelib/tools
parent2cb1db64370989fffeec313c196fe573c479e6aa (diff)
parentc0948d508e7179e2e23c893ba6152c40400de060 (diff)
Merge remote-tracking branch 'origin/dev' into 5.11
Conflicts: src/corelib/tools/qvarlengtharray.qdoc src/corelib/tools/qvector.qdoc Resolved documentation changes in favor of 017569f702b6dd0, which keeps the move overloads along with its const-ref sibling. Change-Id: I0835b0b3211a418e5e50defc4cf315f0964fab79
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qbitarray.cpp40
-rw-r--r--src/corelib/tools/qbitarray.h3
-rw-r--r--src/corelib/tools/qsimd_p.h96
-rw-r--r--src/corelib/tools/qstring.cpp188
-rw-r--r--src/corelib/tools/qstring.h7
-rw-r--r--src/corelib/tools/qstringalgorithms.h5
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc3
-rw-r--r--src/corelib/tools/qvector.qdoc3
8 files changed, 267 insertions, 78 deletions
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index 12e4687b3c..f68a807203 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -300,6 +300,46 @@ void QBitArray::fill(bool value, int begin, int end)
setBit(begin++, value);
}
+/*!
+ \fn const char *QBitArray::bits() const
+ \since 5.11
+
+ Returns a pointer to a dense bit array for this QBitArray. Bits are counted
+ upwards from the least significant bit in each byte. The the number of bits
+ relevant in the last byte is given by \c{size() % 8}.
+
+ \sa fromBits(), size()
+ */
+
+/*!
+ \since 5.11
+
+ Creates a QBitArray with the dense bit array located at \a data, with \a
+ len bits. The byte array at \a data must be at least \a size / 8 (rounded up)
+ bytes long.
+
+ If \a size is not a multiple of 8, this function will include the lowest
+ \a size % 8 bits from the last byte in \a data.
+
+ \sa bits()
+ */
+QBitArray QBitArray::fromBits(const char *data, qsizetype size)
+{
+ QBitArray result;
+ qsizetype nbytes = (size + 7) / 8;
+
+ result.d = QByteArray(nbytes + 1, Qt::Uninitialized);
+ char *bits = result.d.data();
+ memcpy(bits + 1, data, nbytes);
+
+ // clear any unused bits from the last byte
+ if (size & 7)
+ bits[nbytes] &= 0xffU >> (size & 7);
+
+ *bits = result.d.size() * 8 - size;
+ return result;
+}
+
/*! \fn bool QBitArray::isDetached() const
\internal
diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h
index 8fa5323127..ff40bf5654 100644
--- a/src/corelib/tools/qbitarray.h
+++ b/src/corelib/tools/qbitarray.h
@@ -104,6 +104,9 @@ public:
inline void truncate(int pos) { if (pos < size()) resize(pos); }
+ const char *bits() const { return isEmpty() ? nullptr : d.constData() + 1; }
+ static QBitArray fromBits(const char *data, qsizetype len);
+
public:
typedef QByteArray::DataPtr DataPtr;
inline DataPtr &data_ptr() { return d.data_ptr(); }
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
index fafc3e37b0..eb56b31348 100644
--- a/src/corelib/tools/qsimd_p.h
+++ b/src/corelib/tools/qsimd_p.h
@@ -177,55 +177,37 @@
# define QT_FUNCTION_TARGET(x)
#endif
-#if defined(Q_CC_MSVC) && (defined(_M_AVX) || defined(__AVX__))
-// Visual Studio defines __AVX__ when /arch:AVX is passed, but not the earlier macros
-// See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx
-// SSE2 is handled by _M_IX86_FP below
-# define __SSE3__ 1
-# define __SSSE3__ 1
-// no Intel CPU supports SSE4a, so don't define it
-# define __SSE4_1__ 1
-# define __SSE4_2__ 1
-# ifndef __AVX__
-# define __AVX__ 1
-# endif
-#endif
-
-// SSE intrinsics
-#if defined(__SSE2__) || (defined(QT_COMPILER_SUPPORTS_SSE2) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS))
-#if defined(QT_LINUXBASE)
-/// this is an evil hack - the posix_memalign declaration in LSB
-/// is wrong - see http://bugs.linuxbase.org/show_bug.cgi?id=2431
-# define posix_memalign _lsb_hack_posix_memalign
-# include <emmintrin.h>
-# undef posix_memalign
-#else
-# include <emmintrin.h>
-#endif
-#if defined(Q_CC_MSVC) && (defined(_M_X64) || _M_IX86_FP >= 2)
-# define __SSE__ 1
-# define __SSE2__ 1
-#endif
-#endif
+#ifdef Q_PROCESSOR_X86
+/* -- x86 intrinsic support -- */
-// SSE3 intrinsics
-#if defined(__SSE3__) || (defined(QT_COMPILER_SUPPORTS_SSE3) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS))
-#include <pmmintrin.h>
-#endif
+# if defined(Q_CC_MSVC) && (defined(_M_X64) || _M_IX86_FP >= 2)
+// MSVC doesn't define __SSE2__, so do it ourselves
+# define __SSE__ 1
+# define __SSE2__ 1
+# endif
-// SSSE3 intrinsics
-#if defined(__SSSE3__) || (defined(QT_COMPILER_SUPPORTS_SSSE3) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS))
-#include <tmmintrin.h>
-#endif
+# ifdef __SSE2__
+// #include the intrinsics
+# include <immintrin.h>
+# endif
-// SSE4.1 intrinsics
-#if defined(__SSE4_1__) || (defined(QT_COMPILER_SUPPORTS_SSE4_1) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS))
-#include <smmintrin.h>
-#endif
+# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
+// GCC 4.4 and Clang 2.8 added a few more intrinsics there
+# include <x86intrin.h>
+# endif
-// SSE4.2 intrinsics
-#if defined(__SSE4_2__) || (defined(QT_COMPILER_SUPPORTS_SSE4_2) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS))
-#include <nmmintrin.h>
+# if defined(Q_CC_MSVC) && (defined(_M_AVX) || defined(__AVX__))
+// Visual Studio defines __AVX__ when /arch:AVX is passed, but not the earlier macros
+// See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx
+# define __SSE3__ 1
+# define __SSSE3__ 1
+// no Intel CPU supports SSE4a, so don't define it
+# define __SSE4_1__ 1
+# define __SSE4_2__ 1
+# ifndef __AVX__
+# define __AVX__ 1
+# endif
+# endif
# if defined(__SSE4_2__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
// POPCNT instructions:
@@ -233,13 +215,8 @@
// (but neither MSVC nor the Intel compiler define this macro)
# define __POPCNT__ 1
# endif
-#endif
// AVX intrinsics
-#if defined(__AVX__) || (defined(QT_COMPILER_SUPPORTS_AVX) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS))
-// immintrin.h is the ultimate header, we don't need anything else after this
-#include <immintrin.h>
-
# if defined(__AVX__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
// AES, PCLMULQDQ instructions:
// All processors that support AVX support AES, PCLMULQDQ
@@ -255,11 +232,6 @@
# define __F16C__ 1
# define __RDRND__ 1
# endif
-#endif
-
-#if defined(__AES__) || defined(__PCLMUL__) || (defined(QT_COMPILER_SUPPORTS_AES) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS))
-# include <wmmintrin.h>
-#endif
#define QT_FUNCTION_TARGET_STRING_SSE2 "sse2"
#define QT_FUNCTION_TARGET_STRING_SSE3 "sse3"
@@ -288,19 +260,7 @@
#define QT_FUNCTION_TARGET_STRING_RDSEED "rdseed"
#define QT_FUNCTION_TARGET_STRING_SHA "sha"
-// other x86 intrinsics
-#if defined(Q_PROCESSOR_X86) && ((defined(Q_CC_GNU) && (Q_CC_GNU >= 404)) \
- || (defined(Q_CC_CLANG) && (Q_CC_CLANG >= 208)) \
- || defined(Q_CC_INTEL))
-# define QT_COMPILER_SUPPORTS_X86INTRIN
-# ifdef Q_CC_INTEL
-// The Intel compiler has no <x86intrin.h> -- all intrinsics are in <immintrin.h>;
-# include <immintrin.h>
-# else
-// GCC 4.4 and Clang 2.8 added a few more intrinsics there
-# include <x86intrin.h>
-# endif
-#endif
+#endif /* Q_PROCESSOR_X86 */
// Clang compiler fix, see http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20160222/151168.html
// This should be tweaked with an "upper version" of clang once we know which release fixes the
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 5eeaa2a2a8..4040d59b0a 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.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.
@@ -251,6 +251,151 @@ inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1,
}
#endif
+#ifdef __SSE2__
+static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval)
+{
+# 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;
+ ptr += 32;
+ }
+
+ const __m128i mask = _mm256_castsi256_si128(mask256);
+# elif defined(__SSE4_1__)
+ // SSE 4.1 implementation: test 32 bytes at a time (two 16-byte
+ // comparisons, unrolled)
+ const __m128i 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;
+ if (!_mm_testz_si128(mask, data2))
+ return false;
+ ptr += 32;
+ }
+# endif
+# if defined(__SSE4_1__)
+ // 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;
+ ptr += 16;
+ }
+# else
+ // SSE2 implementation: test 16 bytes at a time.
+ const __m128i mask = _mm_set1_epi32(maskval);
+ while (ptr + 16 < end) {
+ __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ __m128i masked = _mm_andnot_si128(mask, data);
+ __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
+ if (quint16(_mm_movemask_epi8(comparison)) != 0xffff)
+ return false;
+ ptr += 16;
+ }
+# endif
+
+ return true;
+}
+#endif
+
+bool QtPrivate::isAscii(QLatin1String s) Q_DECL_NOTHROW
+{
+ const char *ptr = s.begin();
+ const char *end = s.end();
+
+#if defined(__AVX2__)
+ if (!simdTestMask(ptr, end, 0x80808080))
+ return false;
+#elif defined(__SSE2__)
+ // Testing for the high bit can be done efficiently with just PMOVMSKB
+ while (ptr + 16 < end) {
+ __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ quint32 mask = _mm_movemask_epi8(data);
+ if (mask)
+ return false;
+ ptr += 16;
+ }
+#endif
+
+ while (ptr + 4 < end) {
+ quint32 data = qFromUnaligned<quint32>(ptr);
+ if (data & 0x80808080U)
+ return false;
+ ptr += 4;
+ }
+
+ while (ptr != end) {
+ if (quint8(*ptr++) & 0x80)
+ return false;
+ }
+ return true;
+}
+
+bool QtPrivate::isAscii(QStringView s) Q_DECL_NOTHROW
+{
+ const QChar *ptr = s.begin();
+ const QChar *end = s.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;
+ ptr = reinterpret_cast<const QChar *>(ptr8);
+#endif
+
+ while (ptr != end) {
+ if ((*ptr++).unicode() & 0xff80)
+ return false;
+ }
+ return true;
+}
+
+bool QtPrivate::isLatin1(QStringView s) Q_DECL_NOTHROW
+{
+ const QChar *ptr = s.begin();
+ const QChar *end = s.end();
+
+#if defined(__SSE4_1__)
+ const char *ptr8 = reinterpret_cast<const char *>(ptr);
+ const char *end8 = reinterpret_cast<const char *>(end);
+ if (!simdTestMask(ptr8, end8, 0xff00ff00))
+ return false;
+ ptr = reinterpret_cast<const QChar *>(ptr8);
+#elif defined(__SSE2__)
+ // Testing if every other byte is non-zero can be done efficiently by
+ // using PUNPCKHBW (unpack high order bytes) and comparing that to zero.
+ 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));
+ __m128i high = _mm_unpackhi_epi8(data1, data2);
+ __m128i comparison = _mm_cmpeq_epi16(high, _mm_setzero_si128());
+ if (_mm_movemask_epi8(comparison))
+ return false;
+ ptr += 16;
+ }
+ if (ptr + 16 < end) {
+ __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ __m128i high = _mm_unpackhi_epi8(data1, data1);
+ __m128i comparison = _mm_cmpeq_epi16(high, _mm_setzero_si128());
+ if (_mm_movemask_epi8(comparison))
+ return false;
+ }
+#endif
+
+ while (ptr != end) {
+ if ((*ptr++).unicode() > 0xff)
+ return false;
+ }
+ return true;
+}
+
// conversion between Latin 1 and UTF-16
void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW
{
@@ -2441,6 +2586,21 @@ QString &QString::remove(int pos, int len)
return *this;
}
+template<typename T>
+static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs)
+{
+ const int needleSize = needle.size();
+ if (needleSize) {
+ if (needleSize == 1) {
+ s.remove(needle.front(), cs);
+ } else {
+ int i = 0;
+ while ((i = s.indexOf(needle, i, cs)) != -1)
+ s.remove(i, needleSize);
+ }
+ }
+}
+
/*!
Removes every occurrence of the given \a str string in this
string, and returns a reference to this string.
@@ -2454,11 +2614,27 @@ QString &QString::remove(int pos, int len)
*/
QString &QString::remove(const QString &str, Qt::CaseSensitivity cs)
{
- if (str.d->size) {
- int i = 0;
- while ((i = indexOf(str, i, cs)) != -1)
- remove(i, str.d->size);
- }
+ removeStringImpl(*this, str, cs);
+ return *this;
+}
+
+/*!
+ \since 5.11
+ \overload
+
+ Removes every occurrence of the given \a str string in this
+ string, and returns a reference to this string.
+
+ If \a cs is Qt::CaseSensitive (default), the search is
+ case sensitive; otherwise the search is case insensitive.
+
+ This is the same as \c replace(str, "", cs).
+
+ \sa replace()
+*/
+QString &QString::remove(QLatin1String str, Qt::CaseSensitivity cs)
+{
+ removeStringImpl(*this, str, cs);
return *this;
}
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 808f388c89..0138ae4098 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -202,6 +202,12 @@ Q_DECLARE_TYPEINFO(QLatin1String, Q_MOVABLE_TYPE);
typedef QLatin1String QLatin1Literal;
//
+// QLatin1String inline implementations
+//
+inline bool QtPrivate::isLatin1(QLatin1String) Q_DECL_NOTHROW
+{ return true; }
+
+//
// QStringView members that require QLatin1String:
//
bool QStringView::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
@@ -477,6 +483,7 @@ public:
QString &remove(int i, int len);
QString &remove(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive);
+ QString &remove(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive);
QString &remove(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive);
QString &replace(int i, int len, QChar after);
QString &replace(int i, int len, const QChar *s, int slen);
diff --git a/src/corelib/tools/qstringalgorithms.h b/src/corelib/tools/qstringalgorithms.h
index 6146e525d9..8446d85239 100644
--- a/src/corelib/tools/qstringalgorithms.h
+++ b/src/corelib/tools/qstringalgorithms.h
@@ -82,6 +82,11 @@ Q_REQUIRED_RESULT Q_CORE_EXPORT QByteArray convertToLocal8Bit(QStringView str);
Q_REQUIRED_RESULT Q_CORE_EXPORT QVector<uint> convertToUcs4(QStringView str);
Q_REQUIRED_RESULT Q_CORE_EXPORT bool isRightToLeft(QStringView string);
+Q_REQUIRED_RESULT Q_CORE_EXPORT bool isAscii(QLatin1String s) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT bool isAscii(QStringView s) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT bool isLatin1(QLatin1String s) Q_DECL_NOTHROW; // in qstring.h
+Q_REQUIRED_RESULT Q_CORE_EXPORT bool isLatin1(QStringView s) Q_DECL_NOTHROW;
+
} // namespace QtPRivate
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index aff2f986e6..336f2afaca 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -725,8 +725,7 @@
vector.
*/
-/*!
- \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value)
+/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value)
\fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&value)
\overload
diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc
index 173bdb5abf..cc250b72a5 100644
--- a/src/corelib/tools/qvector.qdoc
+++ b/src/corelib/tools/qvector.qdoc
@@ -607,8 +607,7 @@
\sa append(), insert()
*/
-/*!
- \fn template <typename T> void QVector<T>::insert(int i, const T &value)
+/*! \fn template <typename T> void QVector<T>::insert(int i, const T &value)
\fn template <typename T> void QVector<T>::insert(int i, T &&value)
Inserts \a value at index position \a i in the vector. If \a i is