diff options
Diffstat (limited to 'src/corelib')
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> |