summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/doc/snippets/qstring/main.cpp4
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp23
-rw-r--r--src/corelib/global/qoperatingsystemversion.h24
-rw-r--r--src/corelib/global/qoperatingsystemversion_p.h19
-rw-r--r--src/corelib/global/qrandom.cpp69
-rw-r--r--src/corelib/global/qrandom.h35
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp1
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp13
-rw-r--r--src/corelib/io/qtemporaryfile.cpp2
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.h2
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm66
-rw-r--r--src/corelib/kernel/qcore_mac_p.h4
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp61
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h4
-rw-r--r--src/corelib/kernel/qvariant.cpp92
-rw-r--r--src/corelib/thread/qthread.cpp24
-rw-r--r--src/corelib/thread/qthread.h128
-rw-r--r--src/corelib/thread/qthreadpool.cpp10
-rw-r--r--src/corelib/tools/qhash.cpp2
-rw-r--r--src/corelib/tools/qlocale.cpp2
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h9
-rw-r--r--src/corelib/tools/qstring.cpp38
-rw-r--r--src/corelib/tools/qstringalgorithms.h2
-rw-r--r--src/corelib/tools/qstringview.h22
24 files changed, 436 insertions, 220 deletions
diff --git a/src/corelib/doc/snippets/qstring/main.cpp b/src/corelib/doc/snippets/qstring/main.cpp
index 3a6f6483fb..f740888fe7 100644
--- a/src/corelib/doc/snippets/qstring/main.cpp
+++ b/src/corelib/doc/snippets/qstring/main.cpp
@@ -263,14 +263,14 @@ void Widget::argFunction()
//! [11]
{
- //! [11]
+ //! [11-qstringview]
int i; // current file's number
int total; // number of files to process
QStringView fileName; // current file's name
QString status = QString("Processing file %1 of %2: %3")
.arg(i).arg(total).arg(fileName);
- //! [11]
+ //! [11-qstringview]
}
//! [12] //! [13]
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index 594dc6bc17..682c9bab61 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -43,6 +43,7 @@
#endif
#include <qversionnumber.h>
+#include <qdebug.h>
#if defined(Q_OS_ANDROID)
#include <private/qjni_p.h>
@@ -154,6 +155,8 @@ QT_BEGIN_NAMESPACE
\fn QOperatingSystemVersion QOperatingSystemVersion::current()
Returns a QOperatingSystemVersion indicating the current OS and its version number.
+
+ \sa currentType()
*/
#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
QOperatingSystemVersion QOperatingSystemVersion::current()
@@ -300,6 +303,14 @@ int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1,
*/
/*!
+ \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::currentType()
+
+ Returns the current OS type without constructing a QOperatingSystemVersion instance.
+
+ \sa current()
+*/
+
+/*!
\fn QString QOperatingSystemVersion::name() const
Returns a string representation of the OS type identified by the QOperatingSystemVersion.
@@ -510,4 +521,16 @@ const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat_MR1 =
const QOperatingSystemVersion QOperatingSystemVersion::AndroidOreo =
QOperatingSystemVersion(QOperatingSystemVersion::Android, 8, 0);
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QOperatingSystemVersion &ov)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QOperatingSystemVersion(" << ov.name()
+ << ", " << ov.majorVersion() << '.' << ov.minorVersion()
+ << '.' << ov.microVersion() << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
index 1f3ff8e1ab..5f27deab9e 100644
--- a/src/corelib/global/qoperatingsystemversion.h
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -92,6 +92,25 @@ public:
static QOperatingSystemVersion current();
+ static Q_DECL_CONSTEXPR OSType currentType()
+ {
+#if defined(Q_OS_WIN)
+ return Windows;
+#elif defined(Q_OS_MACOS)
+ return MacOS;
+#elif defined(Q_OS_IOS)
+ return IOS;
+#elif defined(Q_OS_TVOS)
+ return TvOS;
+#elif defined(Q_OS_WATCHOS)
+ return WatchOS;
+#elif defined(Q_OS_ANDROID)
+ return Android;
+#else
+ return Unknown;
+#endif
+ }
+
Q_DECL_CONSTEXPR int majorVersion() const { return m_major; }
Q_DECL_CONSTEXPR int minorVersion() const { return m_minor; }
Q_DECL_CONSTEXPR int microVersion() const { return m_micro; }
@@ -128,6 +147,11 @@ private:
};
Q_DECLARE_TYPEINFO(QOperatingSystemVersion, QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ? Q_RELOCATABLE_TYPE : Q_PRIMITIVE_TYPE);
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QOperatingSystemVersion &ov);
+#endif
+
QT_END_NAMESPACE
#endif // QOPERATINGSYSTEMVERSION_H
diff --git a/src/corelib/global/qoperatingsystemversion_p.h b/src/corelib/global/qoperatingsystemversion_p.h
index 78d0daf0c6..6922f4ad54 100644
--- a/src/corelib/global/qoperatingsystemversion_p.h
+++ b/src/corelib/global/qoperatingsystemversion_p.h
@@ -63,25 +63,6 @@ QT_BEGIN_NAMESPACE
OSVERSIONINFOEX qWindowsVersionInfo();
#endif
-static inline QOperatingSystemVersion::OSType currentType()
-{
-#if defined(Q_OS_WIN)
- return QOperatingSystemVersion::Windows;
-#elif defined(Q_OS_MACOS)
- return QOperatingSystemVersion::MacOS;
-#elif defined(Q_OS_IOS)
- return QOperatingSystemVersion::IOS;
-#elif defined(Q_OS_TVOS)
- return QOperatingSystemVersion::TvOS;
-#elif defined(Q_OS_WATCHOS)
- return QOperatingSystemVersion::WatchOS;
-#elif defined(Q_OS_ANDROID)
- return QOperatingSystemVersion::Android;
-#else
- return QOperatingSystemVersion::Unknown;
-#endif
-}
-
QT_END_NAMESPACE
#endif // QOPERATINGSYSTEMVERSION_P_H
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index 395bf0b0cb..2247394363 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -458,14 +458,14 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
reliable sequence, which may be needed for debugging.
The class can generate 32-bit or 64-bit quantities, or fill an array of
- those. The most common way of generating new values is to call the get32(),
+ those. The most common way of generating new values is to call the generate(),
get64() or fillRange() functions. One would use it as:
\code
- quint32 value = QRandomGenerator::get32();
+ quint32 value = QRandomGenerator::generate();
\endcode
- Additionally, it provides a floating-point function getReal() that returns
+ Additionally, it provides a floating-point function generateDouble() that returns
a number in the range [0, 1) (that is, inclusive of zero and exclusive of
1). There's also a set of convenience functions that facilitate obtaining a
random number in a bounded, integral range.
@@ -567,7 +567,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
Generates a 32-bit random quantity and returns it.
- \sa QRandomGenerator::get32(), QRandomGenerator::get64()
+ \sa QRandomGenerator::generate(), QRandomGenerator::generate64()
*/
/*!
@@ -611,7 +611,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
and \a end. This function is equivalent to (and is implemented as):
\code
- std::generate(begin, end, []() { return get32(); });
+ std::generate(begin, end, []() { return generate(); });
\endcode
This function complies with the requirements for the function
@@ -683,7 +683,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn qreal QRandomGenerator::getReal()
+ \fn qreal QRandomGenerator::generateReal()
Generates one random qreal in the canonical range [0, 1) (that is,
inclusive of zero and exclusive of 1).
@@ -698,7 +698,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution}{std::uniform_real_distribution}}
with parameters 0 and 1.
- \sa get32(), get64(), bounded()
+ \sa generate(), get64(), bounded()
*/
/*!
@@ -708,10 +708,10 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
sup (exclusive). This function is equivalent to and is implemented as:
\code
- return getReal() * sup;
+ return generateDouble() * sup;
\endcode
- \sa getReal(), bounded()
+ \sa generateDouble(), bounded()
*/
/*!
@@ -730,13 +730,13 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
quint32 v = QRandomGenerator::bounded(256);
\endcode
- Naturally, the same could also be obtained by masking the result of get32()
+ Naturally, the same could also be obtained by masking the result of generate()
to only the lower 8 bits. Either solution is as efficient.
Note that this function cannot be used to obtain values in the full 32-bit
- range of quint32. Instead, use get32().
+ range of quint32. Instead, use generate().
- \sa get32(), get64(), getReal()
+ \sa generate(), get64(), generateDouble()
*/
/*!
@@ -747,9 +747,9 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
\a sup (exclusive). \a sup must not be negative.
Note that this function cannot be used to obtain values in the full 32-bit
- range of int. Instead, use get32() and cast to int.
+ range of int. Instead, use generate() and cast to int.
- \sa get32(), get64(), getReal()
+ \sa generate(), get64(), generateDouble()
*/
/*!
@@ -771,9 +771,9 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
Note that this function cannot be used to obtain values in the full 32-bit
- range of quint32. Instead, use get32().
+ range of quint32. Instead, use generate().
- \sa get32(), get64(), getReal()
+ \sa generate(), get64(), generateDouble()
*/
/*!
@@ -784,9 +784,9 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
(inclusive) and \a sup (exclusive), both of which may be negative.
Note that this function cannot be used to obtain values in the full 32-bit
- range of int. Instead, use get32() and cast to int.
+ range of int. Instead, use generate() and cast to int.
- \sa get32(), get64(), getReal()
+ \sa generate(), get64(), generateDouble()
*/
/*!
@@ -798,7 +798,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
from a high-quality, seed-less Random Number Generator.
QRandomGenerator64 is a simple adaptor class around QRandomGenerator, making the
- QRandomGenerator::get64() function the default for operator()(), instead of the
+ QRandomGenerator::generate64() function the default for operator()(), instead of the
function that returns 32-bit quantities. This class is intended to be used
in conjunction with Standard Library algorithms that need 64-bit quantities
instead of 32-bit ones.
@@ -824,11 +824,28 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
+ \fn quint64 QRandomGenerator64::generate()
+
+ Generates one 64-bit random value and returns it.
+
+ Note about casting to a signed integer: all bits returned by this function
+ are random, so there's a 50% chance that the most significant bit will be
+ set. If you wish to cast the returned value to qint64 and keep it positive,
+ you should mask the sign bit off:
+
+ \code
+ qint64 value = QRandomGenerator64::generate() & std::numeric_limits<qint64>::max();
+ \endcode
+
+ \sa QRandomGenerator, QRandomGenerator::generate64()
+ */
+
+/*!
\fn result_type QRandomGenerator64::operator()()
Generates a 64-bit random quantity and returns it.
- \sa QRandomGenerator::get32(), QRandomGenerator::get64()
+ \sa QRandomGenerator::generate(), QRandomGenerator::generate64()
*/
/*!
@@ -874,12 +891,12 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
you should mask the sign bit off:
\code
- int value = QRandomGenerator::get32() & std::numeric_limits<int>::max();
+ int value = QRandomGenerator::generate() & std::numeric_limits<int>::max();
\endcode
- \sa get64(), getReal()
+ \sa get64(), generateDouble()
*/
-quint32 QRandomGenerator::get32()
+quint32 QRandomGenerator::generate()
{
quint32 ret;
fill(&ret, &ret + 1);
@@ -895,12 +912,12 @@ quint32 QRandomGenerator::get32()
you should mask the sign bit off:
\code
- qint64 value = QRandomGenerator::get64() & std::numeric_limits<qint64>::max();
+ qint64 value = QRandomGenerator::generate64() & std::numeric_limits<qint64>::max();
\endcode
- \sa get32(), getReal(), QRandomGenerator64
+ \sa generate(), generateDouble(), QRandomGenerator64
*/
-quint64 QRandomGenerator::get64()
+quint64 QRandomGenerator::generate64()
{
quint64 ret;
fill(&ret, &ret + 1);
diff --git a/src/corelib/global/qrandom.h b/src/corelib/global/qrandom.h
index 3bede87fa6..7f96cd6749 100644
--- a/src/corelib/global/qrandom.h
+++ b/src/corelib/global/qrandom.h
@@ -53,29 +53,27 @@ class QRandomGenerator
public:
QRandomGenerator() = default;
- static Q_CORE_EXPORT quint32 get32();
- static Q_CORE_EXPORT quint64 get64();
- static qreal getReal()
+ // ### REMOVE BEFORE 5.10
+ static quint32 get32() { return generate(); }
+ static quint64 get64() { return generate64(); }
+ static qreal getReal() { return generateDouble(); }
+
+ static Q_CORE_EXPORT quint32 generate();
+ static Q_CORE_EXPORT quint64 generate64();
+ static double generateDouble()
{
- const int digits = std::numeric_limits<qreal>::digits;
- if (digits < std::numeric_limits<quint32>::digits) {
- // use get32()
- return qreal(get32()) / ((max)() + qreal(1.0));
- } else {
- // use get64()
- // we won't have enough bits for a __float128 though
- return qreal(get64()) / ((std::numeric_limits<quint64>::max)() + qreal(1.0));
- }
+ // use get64() to get enough bits
+ return double(generate64()) / ((std::numeric_limits<quint64>::max)() + double(1.0));
}
static qreal bounded(qreal sup)
{
- return getReal() * sup;
+ return generateDouble() * sup;
}
static quint32 bounded(quint32 sup)
{
- quint64 value = get32();
+ quint64 value = generate();
value *= sup;
value /= (max)() + quint64(1);
return quint32(value);
@@ -112,7 +110,8 @@ public:
template <typename ForwardIterator>
void generate(ForwardIterator begin, ForwardIterator end)
{
- std::generate(begin, end, &QRandomGenerator::get32);
+ auto generator = static_cast<quint32 (*)()>(&QRandomGenerator::generate);
+ std::generate(begin, end, generator);
}
void generate(quint32 *begin, quint32 *end)
@@ -122,7 +121,7 @@ public:
// API like std::random_device
typedef quint32 result_type;
- result_type operator()() { return get32(); }
+ result_type operator()() { return generate(); }
double entropy() const Q_DECL_NOTHROW { return 0.0; }
static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); }
static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); }
@@ -137,9 +136,11 @@ class QRandomGenerator64
public:
QRandomGenerator64() = default;
+ static quint64 generate() { return QRandomGenerator::generate64(); }
+
// API like std::random_device
typedef quint64 result_type;
- result_type operator()() { return QRandomGenerator::get64(); }
+ result_type operator()() { return QRandomGenerator::generate64(); }
double entropy() const Q_DECL_NOTHROW { return 0.0; }
static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); }
static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); }
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 2828c85048..9fb3855472 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -47,6 +47,7 @@
#include <QtCore/private/qcore_unix_p.h>
#include <QtCore/qvarlengtharray.h>
+#include <pwd.h>
#include <stdlib.h> // for realpath()
#include <sys/types.h>
#include <sys/stat.h>
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 79a9936785..35ddb41215 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -440,12 +440,17 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
if (data.missingFlags(QFileSystemMetaData::LinkType))
QFileSystemEngine::fillMetaData(link, data, QFileSystemMetaData::LinkType);
- QString ret;
+ QString target;
if (data.isLnkFile())
- ret = readLink(link);
+ target = readLink(link);
else if (data.isLink())
- ret = readSymLink(link);
- return QFileSystemEntry(ret);
+ target = readSymLink(link);
+ QFileSystemEntry ret(target);
+ if (!target.isEmpty() && ret.isRelative()) {
+ target.prepend(absoluteName(link).path() + QLatin1Char('/'));
+ ret = QFileSystemEntry(QDir::cleanPath(target));
+ }
+ return ret;
}
//static
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 3ecc24a5db..5865d9e19a 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -165,7 +165,7 @@ QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
Char *rIter = placeholderEnd;
while (rIter != placeholderStart) {
- quint32 rnd = QRandomGenerator::get32();
+ quint32 rnd = QRandomGenerator::generate();
auto applyOne = [&]() {
quint32 v = rnd & ((1 << BitsPerCharacter) - 1);
rnd >>= BitsPerCharacter;
diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h
index d012be6c61..cd294ef8fa 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.h
+++ b/src/corelib/itemmodels/qabstractitemmodel.h
@@ -79,7 +79,7 @@ public:
return r < other.r
|| (r == other.r && (c < other.c
|| (c == other.c && (i < other.i
- || (i == other.i && m < other.m )))));
+ || (i == other.i && std::less<const QAbstractItemModel *>()(m, other.m))))));
}
private:
inline QModelIndex(int arow, int acolumn, void *ptr, const QAbstractItemModel *amodel) Q_DECL_NOTHROW
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm
index db7e55f4b1..24d73fa8be 100644
--- a/src/corelib/kernel/qcore_mac_objc.mm
+++ b/src/corelib/kernel/qcore_mac_objc.mm
@@ -84,18 +84,82 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY
// -------------------------------------------------------------------------
+QT_END_NAMESPACE
+QT_USE_NAMESPACE
+@interface QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) : NSObject
+{
+ NSAutoreleasePool **m_pool;
+}
+-(id)initWithPool:(NSAutoreleasePool**)pool;
+@end
+@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker)
+-(id)initWithPool:(NSAutoreleasePool**)pool
+{
+ if (self = [super init])
+ m_pool = pool;
+ return self;
+}
+-(void)dealloc
+{
+ if (*m_pool) {
+ // The pool is still valid, which means we're not being drained from
+ // the corresponding QMacAutoReleasePool (see below).
+
+ // QMacAutoReleasePool has only a single member, the NSAutoreleasePool*
+ // so the address of that member is also the QMacAutoReleasePool itself.
+ QMacAutoReleasePool *pool = reinterpret_cast<QMacAutoReleasePool *>(m_pool);
+ qWarning() << "Premature drain of" << pool << "This can happen if you've allocated"
+ << "the pool on the heap, or as a member of a heap-allocated object. This is not a"
+ << "supported use of QMacAutoReleasePool, and might result in crashes when objects"
+ << "in the pool are deallocated and then used later on under the assumption they"
+ << "will be valid until" << pool << "has been drained.";
+
+ // Reset the pool so that it's not drained again later on
+ *m_pool = nullptr;
+ }
+
+ [super dealloc];
+}
+@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
+QT_BEGIN_NAMESPACE
+
QMacAutoReleasePool::QMacAutoReleasePool()
: pool([[NSAutoreleasePool alloc] init])
{
+ [[[QMacAutoReleasePoolTracker alloc] initWithPool:
+ reinterpret_cast<NSAutoreleasePool **>(&pool)] autorelease];
}
QMacAutoReleasePool::~QMacAutoReleasePool()
{
+ if (!pool) {
+ qWarning() << "Prematurely drained pool" << this << "finally drained. Any objects belonging"
+ << "to this pool have already been released, and have potentially been invalid since the"
+ << "premature drain earlier on.";
+ return;
+ }
+
+ // Save and reset pool before draining, so that the pool tracker can know
+ // that it's being drained by its owning pool.
+ NSAutoreleasePool *savedPool = static_cast<NSAutoreleasePool*>(pool);
+ pool = nullptr;
+
// Drain behaves the same as release, with the advantage that
// if we're ever used in a garbage-collected environment, the
// drain acts as a hint to the garbage collector to collect.
- [static_cast<NSAutoreleasePool*>(pool) drain];
+ [savedPool drain];
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QMacAutoReleasePool(" << (const void *)pool << ')';
+ return debug;
}
+#endif // !QT_NO_DEBUG_STREAM
#ifdef Q_OS_MACOS
/*
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 5522a617b3..13143a08bb 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -153,6 +153,10 @@ Q_CORE_EXPORT QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Q_CORE_EXPORT Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
#endif
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool);
+#endif
+
Q_CORE_EXPORT void qt_apple_check_os_version();
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 19db06b015..d1640bdc49 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -263,7 +263,7 @@ Q_GLOBAL_STATIC(QStartUpFuncList, preRList)
typedef QList<QtCleanUpFunction> QVFuncList;
Q_GLOBAL_STATIC(QVFuncList, postRList)
#ifndef QT_NO_QOBJECT
-static QBasicMutex globalPreRoutinesMutex;
+static QBasicMutex globalRoutinesMutex;
#endif
/*!
@@ -277,13 +277,15 @@ void qAddPreRoutine(QtStartUpFunction p)
QStartUpFuncList *list = preRList();
if (!list)
return;
+
+ if (QCoreApplication::instance())
+ p();
+
// Due to C++11 parallel dynamic initialization, this can be called
// from multiple threads.
#ifndef QT_NO_THREAD
- QMutexLocker locker(&globalPreRoutinesMutex);
+ QMutexLocker locker(&globalRoutinesMutex);
#endif
- if (QCoreApplication::instance())
- p();
list->prepend(p); // in case QCoreApplication is re-created, see qt_call_pre_routines
}
@@ -292,6 +294,9 @@ void qAddPostRoutine(QtCleanUpFunction p)
QVFuncList *list = postRList();
if (!list)
return;
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(&globalRoutinesMutex);
+#endif
list->prepend(p);
}
@@ -300,6 +305,9 @@ void qRemovePostRoutine(QtCleanUpFunction p)
QVFuncList *list = postRList();
if (!list)
return;
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(&globalRoutinesMutex);
+#endif
list->removeAll(p);
}
@@ -308,15 +316,18 @@ static void qt_call_pre_routines()
if (!preRList.exists())
return;
+ QVFuncList list;
+ {
#ifndef QT_NO_THREAD
- QMutexLocker locker(&globalPreRoutinesMutex);
+ QMutexLocker locker(&globalRoutinesMutex);
#endif
- QVFuncList *list = &(*preRList);
- // Unlike qt_call_post_routines, we don't empty the list, because
- // Q_COREAPP_STARTUP_FUNCTION is a macro, so the user expects
- // the function to be executed every time QCoreApplication is created.
- for (int i = 0; i < list->count(); ++i)
- list->at(i)();
+ // Unlike qt_call_post_routines, we don't empty the list, because
+ // Q_COREAPP_STARTUP_FUNCTION is a macro, so the user expects
+ // the function to be executed every time QCoreApplication is created.
+ list = *preRList;
+ }
+ for (int i = 0; i < list.count(); ++i)
+ list.at(i)();
}
void Q_CORE_EXPORT qt_call_post_routines()
@@ -324,9 +335,21 @@ void Q_CORE_EXPORT qt_call_post_routines()
if (!postRList.exists())
return;
- QVFuncList *list = &(*postRList);
- while (!list->isEmpty())
- (list->takeFirst())();
+ forever {
+ QVFuncList list;
+ {
+ // extract the current list and make the stored list empty
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(&globalRoutinesMutex);
+#endif
+ qSwap(*postRList, list);
+ }
+
+ if (list.isEmpty())
+ break;
+ for (QtCleanUpFunction f : qAsConst(list))
+ f();
+ }
}
@@ -2864,6 +2887,7 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
/*!
\fn void qAddPostRoutine(QtCleanUpFunction ptr)
+ \threadsafe
\relates QCoreApplication
Adds a global routine that will be called from the QCoreApplication
@@ -2877,10 +2901,10 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
\snippet code/src_corelib_kernel_qcoreapplication.cpp 4
- Note that for an application- or module-wide cleanup, qaddPostRoutine()
+ Note that for an application- or module-wide cleanup, qAddPostRoutine()
is often not suitable. For example, if the program is split into dynamically
loaded modules, the relevant module may be unloaded long before the
- QCoreApplication destructor is called. In such cases, if using qaddPostRoutine()
+ QCoreApplication destructor is called. In such cases, if using qAddPostRoutine()
is still desirable, qRemovePostRoutine() can be used to prevent a routine
from being called by the QCoreApplication destructor. For example, if that
routine was called before the module was unloaded.
@@ -2896,11 +2920,14 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
By selecting the right parent object, this can often be made to
clean up the module's data at the right moment.
+ \note This function has been thread-safe since Qt 5.10.
+
\sa qRemovePostRoutine()
*/
/*!
\fn void qRemovePostRoutine(QtCleanUpFunction ptr)
+ \threadsafe
\relates QCoreApplication
\since 5.3
@@ -2909,6 +2936,8 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
must have been previously added to the list by a call to
qAddPostRoutine(), otherwise this function has no effect.
+ \note This function has been thread-safe since Qt 5.10.
+
\sa qAddPostRoutine()
*/
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 963aec70e8..cd995c17f1 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -89,10 +89,6 @@ public:
QString appName() const;
QString appVersion() const;
-#ifdef Q_OS_MACOS
- QMacRootLevelAutoReleasePool autoReleasePool;
-#endif
-
#ifdef Q_OS_DARWIN
static QString infoDictionaryStringProperty(const QString &propertyName);
#endif
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index b79716ff4c..29429b5e55 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -3173,6 +3173,9 @@ static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject)
*/
bool QVariant::canConvert(int targetTypeId) const
{
+ if (d.type == targetTypeId)
+ return true;
+
if ((targetTypeId == QMetaType::QModelIndex && d.type == QMetaType::QPersistentModelIndex)
|| (targetTypeId == QMetaType::QPersistentModelIndex && d.type == QMetaType::QModelIndex))
return true;
@@ -3639,29 +3642,36 @@ static int numericCompare(const QVariant::Private *d1, const QVariant::Private *
*/
bool QVariant::cmp(const QVariant &v) const
{
+ auto cmp_helper = [] (const QVariant::Private &d1, const QVariant::Private &d2)
+ {
+ Q_ASSERT(d1.type == d2.type);
+ if (d1.type >= QMetaType::User) {
+ int result;
+ if (QMetaType::equals(QT_PREPEND_NAMESPACE(constData(d1)), QT_PREPEND_NAMESPACE(constData(d2)), d1.type, &result))
+ return result == 0;
+ }
+ return handlerManager[d1.type]->compare(&d1, &d2);
+ };
+
// try numerics first, with C++ type promotion rules (no conversion)
if (qIsNumericType(d.type) && qIsNumericType(v.d.type))
return numericCompare(&d, &v.d) == 0;
+ if (d.type == v.d.type)
+ return cmp_helper(d, v.d);
+
QVariant v1 = *this;
QVariant v2 = v;
- if (d.type != v2.d.type) {
- if (v2.canConvert(v1.d.type)) {
- if (!v2.convert(v1.d.type))
- return false;
- } else {
- // try the opposite conversion, it might work
- qSwap(v1, v2);
- if (!v2.convert(v1.d.type))
- return false;
- }
- }
- if (v1.d.type >= QMetaType::User) {
- int result;
- if (QMetaType::equals(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result))
- return result == 0;
+ if (v2.canConvert(v1.d.type)) {
+ if (!v2.convert(v1.d.type))
+ return false;
+ } else {
+ // try the opposite conversion, it might work
+ qSwap(v1, v2);
+ if (!v2.convert(v1.d.type))
+ return false;
}
- return handlerManager[v1.d.type]->compare(&v1.d, &v2.d);
+ return cmp_helper(v1.d, v2.d);
}
/*!
@@ -3677,51 +3687,53 @@ int QVariant::compare(const QVariant &v) const
if (cmp(v))
return 0;
- QVariant v1 = *this;
- QVariant v2 = v;
+ const QVariant *v1 = this;
+ const QVariant *v2 = &v;
+ QVariant converted1;
+ QVariant converted2;
- if (v1.d.type != v2.d.type) {
+ if (d.type != v.d.type) {
// if both types differ, try to convert
- if (v2.canConvert(v1.d.type)) {
- QVariant temp = v2;
- if (temp.convert(v1.d.type))
- v2 = temp;
+ if (v2->canConvert(v1->d.type)) {
+ converted2 = *v2;
+ if (converted2.convert(v1->d.type))
+ v2 = &converted2;
}
- if (v1.d.type != v2.d.type && v1.canConvert(v2.d.type)) {
- QVariant temp = v1;
- if (temp.convert(v2.d.type))
- v1 = temp;
+ if (v1->d.type != v2->d.type && v1->canConvert(v2->d.type)) {
+ converted1 = *v1;
+ if (converted1.convert(v2->d.type))
+ v1 = &converted1;
}
- if (v1.d.type != v2.d.type) {
+ if (v1->d.type != v2->d.type) {
// if conversion fails, default to toString
- int r = v1.toString().compare(v2.toString(), Qt::CaseInsensitive);
+ int r = v1->toString().compare(v2->toString(), Qt::CaseInsensitive);
if (r == 0) {
// cmp(v) returned false, so we should try to agree with it.
- return (v1.d.type < v2.d.type) ? -1 : 1;
+ return (v1->d.type < v2->d.type) ? -1 : 1;
}
return r;
}
// did we end up with two numerics? If so, restart
- if (qIsNumericType(v1.d.type) && qIsNumericType(v2.d.type))
- return v1.compare(v2);
+ if (qIsNumericType(v1->d.type) && qIsNumericType(v2->d.type))
+ return v1->compare(*v2);
}
- if (v1.d.type >= QMetaType::User) {
+ if (v1->d.type >= QMetaType::User) {
int result;
- if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v2.d)), d.type, &result))
+ if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v2->d)), d.type, &result))
return result;
}
- switch (v1.d.type) {
+ switch (v1->d.type) {
case QVariant::Date:
- return v1.toDate() < v2.toDate() ? -1 : 1;
+ return v1->toDate() < v2->toDate() ? -1 : 1;
case QVariant::Time:
- return v1.toTime() < v2.toTime() ? -1 : 1;
+ return v1->toTime() < v2->toTime() ? -1 : 1;
case QVariant::DateTime:
- return v1.toDateTime() < v2.toDateTime() ? -1 : 1;
+ return v1->toDateTime() < v2->toDateTime() ? -1 : 1;
case QVariant::StringList:
- return v1.toStringList() < v2.toStringList() ? -1 : 1;
+ return v1->toStringList() < v2->toStringList() ? -1 : 1;
}
- int r = v1.toString().compare(v2.toString(), Qt::CaseInsensitive);
+ int r = v1->toString().compare(v2->toString(), Qt::CaseInsensitive);
if (r == 0) {
// cmp(v) returned false, so we should try to agree with it.
return (d.type < v.d.type) ? -1 : 1;
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 1ec626a53b..e3ba1e4449 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -925,6 +925,30 @@ bool QThread::isInterruptionRequested() const
\sa start()
*/
+#ifdef QTHREAD_HAS_CREATE
+class QThreadCreateThread : public QThread
+{
+public:
+ explicit QThreadCreateThread(std::future<void> &&future)
+ : m_future(std::move(future))
+ {
+ }
+
+private:
+ void run() override
+ {
+ m_future.get();
+ }
+
+ std::future<void> m_future;
+};
+
+QThread *QThread::createThreadImpl(std::future<void> &&future)
+{
+ return new QThreadCreateThread(std::move(future));
+}
+#endif // QTHREAD_HAS_CREATE
+
/*!
\class QDaemonThread
\since 5.5
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h
index b1d02a2b75..d18152a52d 100644
--- a/src/corelib/thread/qthread.h
+++ b/src/corelib/thread/qthread.h
@@ -119,6 +119,12 @@ public:
bool event(QEvent *event) override;
int loopLevel() const;
+#ifdef Q_QDOC
+ template <typename Function, typename... Args>
+ static QThread *create(Function &&f, Args &&... args);
+ template <typename Function>
+ static QThread *create(Function &&f);
+#else
#ifdef QTHREAD_HAS_CREATE
#ifdef QTHREAD_HAS_VARIADIC_CREATE
template <typename Function, typename... Args>
@@ -128,6 +134,7 @@ public:
static QThread *create(Function &&f);
#endif
#endif
+#endif
public Q_SLOTS:
void start(Priority = InheritPriority);
@@ -158,98 +165,81 @@ protected:
private:
Q_DECLARE_PRIVATE(QThread)
+#ifdef QTHREAD_HAS_CREATE
+ static QThread *createThreadImpl(std::future<void> &&future);
+#endif
+
friend class QCoreApplication;
friend class QThreadData;
};
#ifdef QTHREAD_HAS_CREATE
-namespace QtPrivate {
-class QThreadCreateThread : public QThread
+#ifdef QTHREAD_HAS_VARIADIC_CREATE
+// C++17: std::thread's constructor complying call
+template <typename Function, typename... Args>
+QThread *QThread::create(Function &&f, Args &&... args)
{
-public:
-#if defined(QTHREAD_HAS_VARIADIC_CREATE)
- // C++17: std::thread's constructor complying call
- template <typename Function, typename... Args>
- explicit QThreadCreateThread(Function &&f, Args &&... args)
- : m_future(std::async(std::launch::deferred,
- [f = static_cast<typename std::decay<Function>::type>(std::forward<Function>(f))](auto &&... largs) mutable -> void
- {
- (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
- }, std::forward<Args>(args)...))
- {
- }
-#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304
- // C++14: implementation for just one callable
- template <typename Function>
- explicit QThreadCreateThread(Function &&f)
- : m_future(std::async(std::launch::deferred,
- [f = static_cast<typename std::decay<Function>::type>(std::forward<Function>(f))]() mutable -> void
- {
- (void)f();
- }))
- {
- }
-#else
-private:
- // C++11: same as C++14, but with a workaround for not having generalized lambda captures
- template <typename Function>
- struct Callable
- {
- explicit Callable(Function &&f)
- : m_function(std::forward<Function>(f))
+ using DecayedFunction = typename std::decay<Function>::type;
+ auto threadFunction =
+ [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
{
- }
-
-#if defined(Q_COMPILER_DEFAULT_MEMBERS) && defined(Q_COMPILER_DELETE_MEMBERS)
- // Apply the same semantics of a lambda closure type w.r.t. the special
- // member functions, if possible: delete the copy assignment operator,
- // bring back all the others as per the RO5 (cf. §8.1.5.1/11 [expr.prim.lambda.closure])
- ~Callable() = default;
- Callable(const Callable &) = default;
- Callable(Callable &&) = default;
- Callable &operator=(const Callable &) = delete;
- Callable &operator=(Callable &&) = default;
-#endif
+ (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
+ };
- void operator()()
+ return createThreadImpl(std::async(std::launch::deferred,
+ std::move(threadFunction),
+ std::forward<Args>(args)...));
+}
+#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304
+// C++14: implementation for just one callable
+template <typename Function>
+QThread *QThread::create(Function &&f)
+{
+ using DecayedFunction = typename std::decay<Function>::type;
+ auto threadFunction =
+ [f = static_cast<DecayedFunction>(std::forward<Function>(f))]() mutable -> void
{
- (void)m_function();
- }
-
- typename std::decay<Function>::type m_function;
- };
+ (void)f();
+ };
-public:
- template <typename Function>
- explicit QThreadCreateThread(Function &&f)
- : m_future(std::async(std::launch::deferred, Callable<Function>(std::forward<Function>(f))))
+ return createThreadImpl(std::async(std::launch::deferred, std::move(threadFunction)));
+}
+#else
+// C++11: same as C++14, but with a workaround for not having generalized lambda captures
+namespace QtPrivate {
+template <typename Function>
+struct Callable
+{
+ explicit Callable(Function &&f)
+ : m_function(std::forward<Function>(f))
{
}
-#endif // QTHREAD_HAS_VARIADIC_CREATE
-private:
- void run() override
+#if defined(Q_COMPILER_DEFAULT_MEMBERS) && defined(Q_COMPILER_DELETE_MEMBERS)
+ // Apply the same semantics of a lambda closure type w.r.t. the special
+ // member functions, if possible: delete the copy assignment operator,
+ // bring back all the others as per the RO5 (cf. §8.1.5.1/11 [expr.prim.lambda.closure])
+ ~Callable() = default;
+ Callable(const Callable &) = default;
+ Callable(Callable &&) = default;
+ Callable &operator=(const Callable &) = delete;
+ Callable &operator=(Callable &&) = default;
+#endif
+
+ void operator()()
{
- m_future.get();
+ (void)m_function();
}
- std::future<void> m_future;
+ typename std::decay<Function>::type m_function;
};
-
} // namespace QtPrivate
-#ifdef QTHREAD_HAS_VARIADIC_CREATE
-template <typename Function, typename... Args>
-QThread *QThread::create(Function &&f, Args &&... args)
-{
- return new QtPrivate::QThreadCreateThread(std::forward<Function>(f), std::forward<Args>(args)...);
-}
-#else
template <typename Function>
QThread *QThread::create(Function &&f)
{
- return new QtPrivate::QThreadCreateThread(std::forward<Function>(f));
+ return createThreadImpl(std::async(std::launch::deferred, QtPrivate::Callable<Function>(std::forward<Function>(f))));
}
#endif // QTHREAD_HAS_VARIADIC_CREATE
diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp
index 2ebf910992..fd5a1106a0 100644
--- a/src/corelib/thread/qthreadpool.cpp
+++ b/src/corelib/thread/qthreadpool.cpp
@@ -606,17 +606,19 @@ void QThreadPool::reserveThread()
++d->reservedThreads;
}
-/*! \property QThreadPool::stacksize
+/*! \property QThreadPool::stackSize
This property contains the stack size for the thread pool worker
threads.
- The value of the property is uses when the thread pool creates
- new threads only. Changing it has no effect for already created
+ The value of the property is only used when the thread pool creates
+ new threads. Changing it has no effect for already created
or running threads.
The default value is 0, which makes QThread use the operating
- system default stack stize.
+ system default stack size.
+
+ \since 5.10
*/
void QThreadPool::setStackSize(uint stackSize)
{
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index e336b7e618..485c6591c2 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -296,7 +296,7 @@ static uint qt_create_qhash_seed()
return seed;
}
- seed = QRandomGenerator::get32();
+ seed = QRandomGenerator::generate();
#endif // QT_BOOTSTRAPPED
return seed;
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 5db181885c..9a46018ede 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -3814,8 +3814,6 @@ QString QLocale::toCurrencyString(double value, const QString &symbol, int preci
1000. DataSizeIecFormat uses the new IEC standard quantifiers Ki, Mi and so
on, whereas DataSizeSIFormat uses and DataSizeTraditionalFormat abuses the
older SI quantifiers k, M, etc.
-
- \sa refresh(), caching()
*/
QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats format)
{
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index 736049b722..a0e408b94a 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -851,17 +851,20 @@ Q_INLINE_TEMPLATE typename QSharedPointer<X>::difference_type operator-(T *ptr1,
template <class T, class X>
Q_INLINE_TEMPLATE bool operator<(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
{
- return ptr1.data() < ptr2.data();
+ using CT = typename std::common_type<T *, X *>::type;
+ return std::less<CT>()(ptr1.data(), ptr2.data());
}
template <class T, class X>
Q_INLINE_TEMPLATE bool operator<(const QSharedPointer<T> &ptr1, X *ptr2)
{
- return ptr1.data() < ptr2;
+ using CT = typename std::common_type<T *, X *>::type;
+ return std::less<CT>()(ptr1.data(), ptr2);
}
template <class T, class X>
Q_INLINE_TEMPLATE bool operator<(T *ptr1, const QSharedPointer<X> &ptr2)
{
- return ptr1 < ptr2.data();
+ using CT = typename std::common_type<T *, X *>::type;
+ return std::less<CT>()(ptr1, ptr2.data());
}
//
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index ea157a23d0..eeeff280ff 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -72,6 +72,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
+#include <wchar.h>
#include "qchar.cpp"
#include "qstringmatcher.cpp"
@@ -159,6 +160,43 @@ static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::Ca
static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs);
static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
+qssize_t qustrlen(const ushort *str) Q_DECL_NOTHROW
+{
+ qssize_t result = 0;
+
+#ifdef __SSE2__
+ // progress until we get an aligned pointer
+ const ushort *ptr = str;
+ while (*ptr && quintptr(ptr) % 16)
+ ++ptr;
+ if (*ptr == 0)
+ return ptr - str;
+
+ // load 16 bytes and see if we have a null
+ // (aligned loads can never segfault)
+ int mask;
+ const __m128i zeroes = _mm_setzero_si128();
+ do {
+ __m128i data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr));
+ ptr += 8;
+
+ __m128i comparison = _mm_cmpeq_epi16(data, zeroes);
+ mask = _mm_movemask_epi8(comparison);
+ } while (mask == 0);
+
+ // found a null
+ uint idx = qCountTrailingZeroBits(quint32(mask));
+ return ptr - str - 8 + idx / 2;
+#endif
+
+ if (sizeof(wchar_t) == sizeof(ushort))
+ return wcslen(reinterpret_cast<const wchar_t *>(str));
+
+ while (*str++)
+ ++result;
+ return result;
+}
+
#if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__)
namespace {
template <uint MaxCount> struct UnrollTailLoop
diff --git a/src/corelib/tools/qstringalgorithms.h b/src/corelib/tools/qstringalgorithms.h
index e1b8b90428..eaa7207bec 100644
--- a/src/corelib/tools/qstringalgorithms.h
+++ b/src/corelib/tools/qstringalgorithms.h
@@ -53,6 +53,8 @@ class QLatin1String;
class QStringView;
template <typename T> class QVector;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qssize_t qustrlen(const ushort *str) Q_DECL_NOTHROW;
+
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int qCompareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int qCompareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int qCompareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
diff --git a/src/corelib/tools/qstringview.h b/src/corelib/tools/qstringview.h
index 24be441b00..764da71d0b 100644
--- a/src/corelib/tools/qstringview.h
+++ b/src/corelib/tools/qstringview.h
@@ -143,20 +143,22 @@ private:
{
return qssize_t(N - 1);
}
+
template <typename Char>
- static Q_DECL_RELAXED_CONSTEXPR qssize_t lengthHelperPointer(const Char *str) Q_DECL_NOTHROW
+ static qssize_t lengthHelperPointer(const Char *str) Q_DECL_NOTHROW
{
- qssize_t result = 0;
- while (*str++)
- ++result;
- return result;
+#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL)
+ if (__builtin_constant_p(*str)) {
+ qssize_t result = 0;
+ while (*str++)
+ ++result;
+ }
+#endif
+ return qustrlen(reinterpret_cast<const ushort *>(str));
}
- static Q_DECL_RELAXED_CONSTEXPR qssize_t lengthHelperPointer(const QChar *str) Q_DECL_NOTHROW
+ static qssize_t lengthHelperPointer(const QChar *str) Q_DECL_NOTHROW
{
- qssize_t result = 0;
- while (!str++->isNull())
- ++result;
- return result;
+ return qustrlen(reinterpret_cast<const ushort *>(str));
}
template <typename Char>