diff options
author | Morten Johan Sørvig <morten.sorvig@qt.io> | 2018-06-01 14:15:15 +0200 |
---|---|---|
committer | Morten Johan Sørvig <morten.sorvig@qt.io> | 2018-06-01 14:15:15 +0200 |
commit | 02c8fa204f53af27907ef48bc74c500d7a05c3a0 (patch) | |
tree | 56519f143a72884a47c757d96c411e26c10c8a10 /src/corelib | |
parent | 36e8cf3cdb50c0447695f35c2e63eed139704c13 (diff) | |
parent | 0a63d5fed6e020e81d3c570d299d1292c33fa284 (diff) |
Merge remote-tracking branch 'gerrit/5.11' into wip/webassembly
Change-Id: Ie6757dd81b49f4d9e677dbd08f5378d6190187b7
Diffstat (limited to 'src/corelib')
34 files changed, 423 insertions, 225 deletions
diff --git a/src/corelib/configure.json b/src/corelib/configure.json index 5019497dad..4c2506d8bc 100644 --- a/src/corelib/configure.json +++ b/src/corelib/configure.json @@ -569,7 +569,8 @@ }, "linkat": { "label": "linkat()", - "autoDetect": "config.linux", + "comment": "Currently only used by QTemporaryFile; linkat() exists on Android, but hardlink creation fails due to security rules", + "autoDetect": "config.linux && !config.android", "condition": "tests.linkat", "output": [ "privateFeature" ] }, diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp index ceb3f8adf3..2d7b9a9ac8 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp @@ -387,11 +387,11 @@ CONFIG += no_keywords //! [34] QString FriendlyConversation::greeting(int type) { -static const char *greeting_strings[] = { - QT_TR_NOOP("Hello"), - QT_TR_NOOP("Goodbye") -}; -return tr(greeting_strings[type]); + static const char *greeting_strings[] = { + QT_TR_NOOP("Hello"), + QT_TR_NOOP("Goodbye") + }; + return tr(greeting_strings[type]); } //! [34] @@ -410,7 +410,7 @@ QString FriendlyConversation::greeting(int type) QString global_greeting(int type) { return qApp->translate("FriendlyConversation", - greeting_strings[type]); + greeting_strings[type]); } //! [35] @@ -434,8 +434,8 @@ QString FriendlyConversation::greeting(int type) QString global_greeting(int type) { return qApp->translate("FriendlyConversation", - greeting_strings[type].source, - greeting_strings[type].comment); + greeting_strings[type].source, + greeting_strings[type].comment); } //! [36] diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qlistdata.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qlistdata.cpp index ac17de1bee..27565a7878 100644 --- a/src/corelib/doc/snippets/code/src_corelib_tools_qlistdata.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_tools_qlistdata.cpp @@ -54,11 +54,14 @@ QList<QDate> dateList; //! [0] -//! [1] -QList<QString> list; -list << "one" << "two" << "three"; -// list: ["one", "two", "three"] -//! [1] +//! [1a] +QList<QString> list = { "one", "two", "three" }; +//! [1a] + + +//! [1b] +list << "four" << "five"; +//! [1b] //! [2] diff --git a/src/corelib/doc/snippets/qstringlist/main.cpp b/src/corelib/doc/snippets/qstringlist/main.cpp index 4d9c015747..55c60650fe 100644 --- a/src/corelib/doc/snippets/qstringlist/main.cpp +++ b/src/corelib/doc/snippets/qstringlist/main.cpp @@ -61,10 +61,13 @@ public: Widget::Widget(QWidget *parent) : QWidget(parent) { -//! [0] - QStringList fonts; - fonts << "Arial" << "Helvetica" << "Times" << "Courier"; -//! [0] +//! [0a] + QStringList fonts = { "Arial", "Helvetica", "Times" }; +//! [0a] + +//! [0b] + fonts << "Courier" << "Verdana"; +//! [0b] //! [1] for (int i = 0; i < fonts.size(); ++i) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index ad015ee048..2fbd31b3d7 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -648,10 +648,10 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value)); compiler or platform specific code to their application. The remaining macros are convenience macros for larger operations: - The QT_TRANSLATE_NOOP() and QT_TR_NOOP() macros provide the - possibility of marking text for dynamic translation, - i.e. translation without changing the stored source text. The - Q_ASSERT() and Q_ASSERT_X() enables warning messages of various + The QT_TR_NOOP(), QT_TRANSLATE_NOOP(), and QT_TRANSLATE_NOOP3() + macros provide the possibility of marking strings for delayed + translation. + The Q_ASSERT() and Q_ASSERT_X() enables warning messages of various level of refinement. The Q_FOREACH() and foreach() macros implement Qt's foreach loop. @@ -662,11 +662,11 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value)); memory, if the pointer is 0. The qPrintable() and qUtf8Printable() macros represent an easy way of printing text. - Finally, the QT_POINTER_SIZE macro expands to the size of a - pointer in bytes, and the QT_VERSION and QT_VERSION_STR macros - expand to a numeric value or a string, respectively, specifying - Qt's version number, i.e the version the application is compiled - against. + The QT_POINTER_SIZE macro expands to the size of a pointer in bytes. + + The macros QT_VERSION and QT_VERSION_STR expand to a numeric value + or a string, respectively, that specifies the version of Qt that the + application is compiled against. \sa <QtAlgorithms>, QSysInfo */ @@ -939,6 +939,8 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value)); Rounds \a d to the nearest integer. + Rounds half up (e.g. 0.5 -> 1, -0.5 -> 0). + Example: \snippet code/src_corelib_global_qglobal.cpp 11A @@ -949,6 +951,8 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value)); Rounds \a d to the nearest integer. + Rounds half up (e.g. 0.5f -> 1, -0.5f -> 0). + Example: \snippet code/src_corelib_global_qglobal.cpp 11B @@ -959,6 +963,8 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value)); Rounds \a d to the nearest 64-bit integer. + Rounds half up (e.g. 0.5 -> 1, -0.5 -> 0). + Example: \snippet code/src_corelib_global_qglobal.cpp 12A @@ -969,6 +975,8 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value)); Rounds \a d to the nearest 64-bit integer. + Rounds half up (e.g. 0.5f -> 1, -0.5f -> 0). + Example: \snippet code/src_corelib_global_qglobal.cpp 12B @@ -3268,14 +3276,15 @@ QByteArray qgetenv(const char *varName) /*! - QString qEnvironmentVariable(const char *varName, const QString &defaultValue); + \fn QString qEnvironmentVariable(const char *varName, const QString &defaultValue) + \fn QString qEnvironmentVariable(const char *varName) \relates <QtGlobal> \since 5.10 - Returns the value of the environment variable with name \a varName as a - QString. If no variable by that name is found in the environment, this - function returns \a defaultValue. + These functions return the value of the environment variable, \a varName, as a + QString. If no variable \a varName is found in the environment and \a defaultValue + is provided, \a defaultValue is returned. Otherwise QString() is returned. The Qt environment manipulation functions are thread-safe, but this requires that the C library equivalent functions like getenv and putenv are @@ -3344,9 +3353,6 @@ QString qEnvironmentVariable(const char *varName, const QString &defaultValue) #endif } -/*! - \internal -*/ QString qEnvironmentVariable(const char *varName) { return qEnvironmentVariable(varName, QString()); @@ -3678,19 +3684,18 @@ bool qunsetenv(const char *varName) \macro QT_TR_NOOP(sourceText) \relates <QtGlobal> - Marks the string literal \a sourceText for dynamic translation in - the current context (class), i.e the stored \a sourceText will not - be altered. + Marks the UTF-8 encoded string literal \a sourceText for delayed + translation in the current context (class). - The macro expands to \a sourceText. + The macro tells lupdate to collect the string, and expands to + \a sourceText itself. Example: \snippet code/src_corelib_global_qglobal.cpp 34 - The macro QT_TR_NOOP_UTF8() is identical except that it tells lupdate - that the source string is encoded in UTF-8. Corresponding variants - exist in the QT_TRANSLATE_NOOP() family of macros, too. + The macro QT_TR_NOOP_UTF8() is identical and obsolete; this applies + to all other _UTF8 macros as well. \sa QT_TRANSLATE_NOOP(), {Internationalization with Qt} */ @@ -3699,12 +3704,12 @@ bool qunsetenv(const char *varName) \macro QT_TRANSLATE_NOOP(context, sourceText) \relates <QtGlobal> - Marks the string literal \a sourceText for dynamic translation in - the given \a context; i.e, the stored \a sourceText will not be - altered. The \a context is typically a class and also needs to - be specified as string literal. + Marks the UTF-8 encoded string literal \a sourceText for delayed + translation in the given \a context. The \a context is typically + a class name and also needs to be specified as a string literal. - The macro expands to \a sourceText. + The macro tells lupdate to collect the string, and expands to + \a sourceText itself. Example: @@ -3714,18 +3719,19 @@ bool qunsetenv(const char *varName) */ /*! - \macro QT_TRANSLATE_NOOP3(context, sourceText, comment) + \macro QT_TRANSLATE_NOOP3(context, sourceText, disambiguation) \relates <QtGlobal> \since 4.4 - Marks the string literal \a sourceText for dynamic translation in the - given \a context and with \a comment, i.e the stored \a sourceText will - not be altered. The \a context is typically a class and also needs to - be specified as string literal. The string literal \a comment - will be available for translators using e.g. Qt Linguist. + Marks the UTF-8 encoded string literal \a sourceText for delayed + translation in the given \a context with the given \a disambiguation. + The \a context is typically a class and also needs to be specified + as a string literal. The string literal \a disambiguation should be + a short semantic tag to tell apart otherwise identical strings. - The macro expands to anonymous struct of the two string - literals passed as \a sourceText and \a comment. + The macro tells lupdate to collect the string, and expands to an + anonymous struct of the two string literals passed as \a sourceText + and \a disambiguation. Example: diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index e31d4d9ad7..3684c6b5de 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1062,7 +1062,7 @@ template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelpe #define QT_TRANSLATE_NOOP3(scope, x, comment) {x, comment} #define QT_TRANSLATE_NOOP3_UTF8(scope, x, comment) {x, comment} -#ifndef QT_NO_TRANSLATION // ### This should enclose the NOOPs above +#ifndef QT_NO_TRANSLATION // ### Qt6: This should enclose the NOOPs above // Defined in qcoreapplication.cpp // The better name qTrId() is reserved for an upcoming function which would diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 17002c4231..7444145e82 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -208,6 +208,7 @@ static bool isDefaultCategory(const char *category) /*! Returns true if writing to \c stderr is supported. + \internal \sa stderrHasConsoleAttached() */ static bool systemHasStderr() @@ -236,6 +237,7 @@ static bool systemHasStderr() the output might still end up visible to the user. For this reason, we don't guard the stderr output in the default message handler with stderrHasConsoleAttached(). + \internal \sa systemHasStderr() */ bool stderrHasConsoleAttached() @@ -288,6 +290,7 @@ namespace QtPrivate { This is normally the case if \c stderr has a console attached, but may be overridden by the user by setting the QT_FORCE_STDERR_LOGGING environment variable to \c 1. + \internal \sa stderrHasConsoleAttached() */ bool shouldLogToStderr() diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 11c431d015..0361fd6085 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -1329,7 +1329,14 @@ \omitvalue WA_WState_WindowOpacitySet \omitvalue WA_WState_AcceptedTouchBeginEvent \omitvalue WA_MacNoShadow - \omitvalue WA_ContentsMarginsRespectsSafeArea + \value WA_ContentsMarginsRespectsSafeArea A QWidget respects the safe + area margins of a window by incorporating the margins into its contents' + margins by default. This means, that a QLayout will use the content area + of a widget for its layout, unless the Qt::WA_LayoutOnEntireRect attribute + is set. This along with a contents margin of 0 can be used on the actual + layout, to allow for example a background image to underlay the status bar and other + system areas on an iOS device, while still allowing child widgets of + that background to be inset based on the safe area. */ /*! \typedef Qt::HANDLE diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 0c38731052..5561ecbb6d 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -114,6 +114,8 @@ static int renameat2(int oldfd, const char *oldpath, int newfd, const char *newp # if !QT_CONFIG(statx) && defined(SYS_statx) static int statx(int dirfd, const char *pathname, int flag, unsigned mask, struct statx *statxbuf) { return syscall(SYS_statx, dirfd, pathname, flag, mask, statxbuf); } +# elif !QT_CONFIG(statx) && !defined(SYS_statx) +# undef STATX_BASIC_STATS # endif # endif // !Q_OS_ANDROID #endif diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.mm b/src/corelib/io/qfilesystemwatcher_fsevents.mm index 792ea387ac..0254d0f7a1 100644 --- a/src/corelib/io/qfilesystemwatcher_fsevents.mm +++ b/src/corelib/io/qfilesystemwatcher_fsevents.mm @@ -377,7 +377,7 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths, for (PathRefCounts::const_iterator i = watchingState.watchedPaths.begin(), ei = watchingState.watchedPaths.end(); i != ei; ++i) { - if (watchedPath.startsWith(i.key())) { + if (watchedPath.startsWith(i.key() % QDir::separator())) { watchedPath = i.key(); break; } diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index b029274329..a6c27d19c0 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -147,9 +147,15 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift) Rules are evaluated in text order, from first to last. That is, if two rules apply to a category/type, the rule that comes later is applied. - Rules can be set via \l setFilterRules(). Since Qt 5.3, logging rules can also - be set in the \c QT_LOGGING_RULES environment variable, and - are automatically loaded from the \c [Rules] section of a logging + Rules can be set via \l setFilterRules(): + + \code + QLoggingCategory::setFilterRules("*.debug=false\n" + "driver.usb.debug=true"); + \endcode + + Since Qt 5.3, logging rules are also + automatically loaded from the \c [Rules] section of a logging configuration file. Such configuration files are looked up in the QtProject configuration directory, or explicitly set in a \c QT_LOGGING_CONF environment variable: @@ -160,19 +166,18 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift) driver.usb.debug=true \endcode - Rules set by \l setFilterRules() take precedence over rules specified - in the QtProject configuration directory, and can, in turn, be - overwritten by rules from the configuration file specified by - \c QT_LOGGING_CONF, and rules set by \c QT_LOGGING_RULES. - - - Since Qt 5.6, \c QT_LOGGING_RULES may contain multiple rules separated - by semicolons: + Since Qt 5.3, logging rules can also be specified in a \c QT_LOGGING_RULES + environment variable. And since Qt 5.6, multiple rules can also be + separated by semicolons: \code QT_LOGGING_RULES="*.debug=false;driver.usb.debug=true" \endcode + Rules set by \l setFilterRules() take precedence over rules specified + in the QtProject configuration directory, and can, in turn, be + overwritten by rules from the configuration file specified by + \c QT_LOGGING_CONF, and rules set by \c QT_LOGGING_RULES. Order of evaluation: \list diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 68b7a8bf9b..a849519635 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -925,6 +925,8 @@ bool QProcessPrivate::startDetached(qint64 *pid) closeChannel(&stdinChannel); closeChannel(&stdoutChannel); closeChannel(&stderrChannel); + qt_safe_close(pidPipe[0]); + qt_safe_close(pidPipe[1]); qt_safe_close(startedPipe[0]); qt_safe_close(startedPipe[1]); return false; diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 3a62a67e3b..b1ec2c560c 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -499,8 +499,13 @@ void QProcessPrivate::startProcess() if (!openChannel(stdinChannel) || !openChannel(stdoutChannel) || - !openChannel(stderrChannel)) + !openChannel(stderrChannel)) { + QString errorString = QProcess::tr("Process failed to start: %1").arg(qt_error_string()); + cleanup(); + setErrorAndEmit(QProcess::FailedToStart, errorString); + q->setProcessState(QProcess::NotRunning); return; + } const QString args = qt_create_commandline(program, arguments, nativeArguments); QByteArray envlist; diff --git a/src/corelib/itemmodels/qitemselectionmodel.cpp b/src/corelib/itemmodels/qitemselectionmodel.cpp index 9af4fd9133..edb9bb9098 100644 --- a/src/corelib/itemmodels/qitemselectionmodel.cpp +++ b/src/corelib/itemmodels/qitemselectionmodel.cpp @@ -1502,30 +1502,40 @@ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) cons && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid()) return false; } + + auto isSelectable = [&](int row, int column) { + Qt::ItemFlags flags = d->model->index(row, column, parent).flags(); + return (flags & Qt::ItemIsSelectable); + }; + + const int colCount = d->model->columnCount(parent); + int unselectable = 0; // add ranges and currentSelection and check through them all QList<QItemSelectionRange>::const_iterator it; QList<QItemSelectionRange> joined = d->ranges; if (d->currentSelection.count()) joined += d->currentSelection; - int colCount = d->model->columnCount(parent); for (int column = 0; column < colCount; ++column) { + if (!isSelectable(row, column)) { + ++unselectable; + continue; + } + for (it = joined.constBegin(); it != joined.constEnd(); ++it) { if ((*it).contains(row, column, parent)) { - bool selectable = false; - for (int i = column; !selectable && i <= (*it).right(); ++i) { - Qt::ItemFlags flags = d->model->index(row, i, parent).flags(); - selectable = flags & Qt::ItemIsSelectable; - } - if (selectable){ - column = qMax(column, (*it).right()); - break; + for (int i = column; i <= (*it).right(); ++i) { + if (!isSelectable(row, i)) + ++unselectable; } + + column = qMax(column, (*it).right()); + break; } } if (it == joined.constEnd()) return false; } - return colCount > 0; // no columns means no selected items + return unselectable < colCount; } /*! @@ -1568,26 +1578,39 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent } } } + + auto isSelectable = [&](int row, int column) { + Qt::ItemFlags flags = d->model->index(row, column, parent).flags(); + return (flags & Qt::ItemIsSelectable); + }; + const int rowCount = d->model->rowCount(parent); + int unselectable = 0; + // add ranges and currentSelection and check through them all QList<QItemSelectionRange>::const_iterator it; QList<QItemSelectionRange> joined = d->ranges; if (d->currentSelection.count()) joined += d->currentSelection; - int rowCount = d->model->rowCount(parent); for (int row = 0; row < rowCount; ++row) { - for (it = joined.constBegin(); it != joined.constEnd(); ++it) { - if ((*it).contains(row, column, parent)) { - Qt::ItemFlags flags = d->model->index(row, column, parent).flags(); - if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled)) { - row = qMax(row, (*it).bottom()); - break; - } - } - } - if (it == joined.constEnd()) - return false; + if (!isSelectable(row, column)) { + ++unselectable; + continue; + } + for (it = joined.constBegin(); it != joined.constEnd(); ++it) { + if ((*it).contains(row, column, parent)) { + for (int i = row; i <= (*it).bottom(); ++i) { + if (!isSelectable(i, column)) { + ++unselectable; + } + } + row = qMax(row, (*it).bottom()); + break; + } + } + if (it == joined.constEnd()) + return false; } - return rowCount > 0; // no rows means no selected items + return unselectable < rowCount; } /*! diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 78093727b8..08279cb244 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -1910,7 +1910,10 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); - d->_q_sourceModelDestroyed(); + // same as in _q_sourceReset() + d->invalidatePersistentIndexes(); + d->_q_clearMapping(); + QAbstractProxyModel::setSourceModel(sourceModel); connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h index 4775d3d47a..bd8da5c35d 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.h +++ b/src/corelib/kernel/qabstracteventdispatcher.h @@ -87,6 +87,7 @@ public: QT_DEPRECATED inline void registerTimer(int timerId, int interval, QObject *object) { registerTimer(timerId, interval, Qt::CoarseTimer, object); } #endif + // ### Qt6: change interval range to qint64 (or use QDeadlineTimer) int registerTimer(int interval, Qt::TimerType timerType, QObject *object); virtual void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) = 0; virtual bool unregisterTimer(int timerId) = 0; diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index 5ecd86a30e..c29c4dfc14 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -161,6 +161,34 @@ QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool) } #endif // !QT_NO_DEBUG_STREAM +bool qt_apple_isApplicationExtension() +{ + static bool isExtension = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSExtension"]; + return isExtension; +} + +#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS) +AppleApplication *qt_apple_sharedApplication() +{ + // Application extensions are not allowed to access the shared application + if (qt_apple_isApplicationExtension()) { + qWarning() << "accessing the shared" << [AppleApplication class] + << "is not allowed in application extensions"; + + // In practice the application is actually available, but the the App + // review process will likely catch uses of it, so we return nil just + // in case, unless we don't care about being App Store compliant. +#if QT_CONFIG(appstore_compliant) + return nil; +#endif + } + + // We use performSelector so that building with -fapplication-extension will + // not mistakenly think we're using the shared application in extensions. + return [[AppleApplication class] performSelector:@selector(sharedApplication)]; +} +#endif + #ifdef Q_OS_MACOS /* Ensure that Objective-C objects auto-released in main(), directly or indirectly, diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 9c6cef68b2..9bd2e31bc9 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -158,6 +158,20 @@ QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool); #endif Q_CORE_EXPORT void qt_apple_check_os_version(); +Q_CORE_EXPORT bool qt_apple_isApplicationExtension(); + +#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS) +QT_END_NAMESPACE +# if defined(Q_OS_MACOS) +Q_FORWARD_DECLARE_OBJC_CLASS(NSApplication); +using AppleApplication = NSApplication; +# else +Q_FORWARD_DECLARE_OBJC_CLASS(UIApplication); +using AppleApplication = UIApplication; +# endif +QT_BEGIN_NAMESPACE +Q_CORE_EXPORT AppleApplication *qt_apple_sharedApplication(); +#endif // -------------------------------------------------------------------------- diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm index 8499b3fd57..503836d071 100644 --- a/src/corelib/kernel/qeventdispatcher_cf.mm +++ b/src/corelib/kernel/qeventdispatcher_cf.mm @@ -72,17 +72,12 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(RunLoopModeTracker); if (self = [super init]) { m_runLoopModes.push(kCFRunLoopDefaultMode); - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(receivedNotification:) - name:nil -#ifdef Q_OS_OSX - object:[NSApplication sharedApplication]]; -#elif defined(Q_OS_WATCHOS) - object:[WKExtension sharedExtension]]; -#else - // Use performSelector so this can work in an App Extension - object:[[UIApplication class] performSelector:@selector(sharedApplication)]]; +#if !defined(Q_OS_WATCHOS) + if (!qt_apple_isApplicationExtension()) { + [[NSNotificationCenter defaultCenter] + addObserver:self selector:@selector(receivedNotification:) + name:nil object:qt_apple_sharedApplication()]; + } #endif } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 69d76915c9..016b67d790 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4430,6 +4430,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) /*! \macro Q_NAMESPACE + \relates QObject \since 5.8 The Q_NAMESPACE macro can be used to add QMetaObject capabilities diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index 7d529372c4..68e3c8f10d 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -311,9 +311,9 @@ static inline bool isTextFile(const QByteArray &data) if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM)) return true; - // Check the first 32 bytes (see shared-mime spec) + // Check the first 128 bytes (see shared-mime spec) const char *p = data.constData(); - const char *e = p + qMin(32, data.size()); + const char *e = p + qMin(128, data.size()); for ( ; p < e; ++p) { if ((unsigned char)(*p) < 32 && *p != 9 && *p !=10 && *p != 13) return false; diff --git a/src/corelib/serialization/qjson.cpp b/src/corelib/serialization/qjson.cpp index e4bca3bcd0..7912b5040c 100644 --- a/src/corelib/serialization/qjson.cpp +++ b/src/corelib/serialization/qjson.cpp @@ -326,40 +326,35 @@ int Value::usedStorage(const Base *b) const return alignedSize(s); } +inline bool isValidValueOffset(uint offset, uint tableOffset) +{ + return offset >= sizeof(Base) + && offset + sizeof(uint) <= tableOffset; +} + bool Value::isValid(const Base *b) const { - int offset = 0; switch (type) { + case QJsonValue::Null: + case QJsonValue::Bool: + return true; case QJsonValue::Double: - if (latinOrIntValue) - break; - Q_FALLTHROUGH(); + return latinOrIntValue || isValidValueOffset(value, b->tableOffset); case QJsonValue::String: + if (!isValidValueOffset(value, b->tableOffset)) + return false; + if (latinOrIntValue) + return asLatin1String(b).isValid(b->tableOffset - value); + return asString(b).isValid(b->tableOffset - value); case QJsonValue::Array: + return isValidValueOffset(value, b->tableOffset) + && static_cast<Array *>(base(b))->isValid(b->tableOffset - value); case QJsonValue::Object: - offset = value; - break; - case QJsonValue::Null: - case QJsonValue::Bool: + return isValidValueOffset(value, b->tableOffset) + && static_cast<Object *>(base(b))->isValid(b->tableOffset - value); default: - break; - } - - if (!offset) - return true; - if (offset + sizeof(uint) > b->tableOffset) return false; - - int s = usedStorage(b); - if (!s) - return true; - if (s < 0 || s > (int)b->tableOffset - offset) - return false; - if (type == QJsonValue::Array) - return static_cast<Array *>(base(b))->isValid(s); - if (type == QJsonValue::Object) - return static_cast<Object *>(base(b))->isValid(s); - return true; + } } /*! diff --git a/src/corelib/serialization/qjson_p.h b/src/corelib/serialization/qjson_p.h index 7743382806..dc56a49084 100644 --- a/src/corelib/serialization/qjson_p.h +++ b/src/corelib/serialization/qjson_p.h @@ -450,7 +450,7 @@ static inline void copyString(char *dest, const QString &str, bool compress) /* - Base is the base class for both Object and Array. Both classe work more or less the same way. + Base is the base class for both Object and Array. Both classes work more or less the same way. The class starts with a header (defined by the struct below), then followed by data (the data for values in the Array case and Entry's (see below) for objects. diff --git a/src/corelib/serialization/qjsondocument.cpp b/src/corelib/serialization/qjsondocument.cpp index 9794bca60d..ab27b45fda 100644 --- a/src/corelib/serialization/qjsondocument.cpp +++ b/src/corelib/serialization/qjsondocument.cpp @@ -210,6 +210,9 @@ QJsonDocument QJsonDocument::fromRawData(const char *data, int size, DataValidat return QJsonDocument(); } + if (size < (int)(sizeof(QJsonPrivate::Header) + sizeof(QJsonPrivate::Base))) + return QJsonDocument(); + QJsonPrivate::Data *d = new QJsonPrivate::Data((char *)data, size); d->ownsData = false; diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index d0f83d2b6a..7e1b43f9b1 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -65,7 +65,7 @@ struct QPodArrayOps Q_ASSERT(newSize > uint(this->size)); Q_ASSERT(newSize <= this->alloc); - ::memset(this->end(), 0, (newSize - this->size) * sizeof(T)); + ::memset(static_cast<void *>(this->end()), 0, (newSize - this->size) * sizeof(T)); this->size = int(newSize); } @@ -121,8 +121,9 @@ struct QPodArrayOps Q_ASSERT(e <= where || b > this->end()); // No overlap Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size)); - ::memmove(where + (e - b), where, (static_cast<const T*>(this->end()) - where) * sizeof(T)); - ::memcpy(where, b, (e - b) * sizeof(T)); + ::memmove(static_cast<void *>(where + (e - b)), static_cast<void *>(where), + (static_cast<const T*>(this->end()) - where) * sizeof(T)); + ::memcpy(static_cast<void *>(where), static_cast<const void *>(b), (e - b) * sizeof(T)); this->size += (e - b); } @@ -133,7 +134,8 @@ struct QPodArrayOps Q_ASSERT(b >= this->begin() && b < this->end()); Q_ASSERT(e > this->begin() && e < this->end()); - ::memmove(b, e, (static_cast<T *>(this->end()) - e) * sizeof(T)); + ::memmove(static_cast<void *>(b), static_cast<void *>(e), + (static_cast<T *>(this->end()) - e) * sizeof(T)); this->size -= (e - b); } }; diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 421e716d14..7c601e1336 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -238,7 +238,8 @@ qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t heade Returns a duplicate string. Allocates space for a copy of \a src, copies it, and returns a - pointer to the copy. If \a src is 0, it immediately returns 0. + pointer to the copy. If \a src is nullptr, it immediately returns + nullptr. Ownership is passed to the caller, so the returned string must be deleted using \c delete[]. @@ -247,7 +248,7 @@ qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t heade char *qstrdup(const char *src) { if (!src) - return 0; + return nullptr; char *dst = new char[strlen(src) + 1]; return qstrcpy(dst, src); } @@ -255,26 +256,28 @@ char *qstrdup(const char *src) /*! \relates QByteArray Copies all the characters up to and including the '\\0' from \a - src into \a dst and returns a pointer to \a dst. If \a src is 0, - it immediately returns 0. + src into \a dst and returns a pointer to \a dst. If \a src is + nullptr, it immediately returns nullptr. This function assumes that \a dst is large enough to hold the contents of \a src. + \note If \a dst and \a src overlap, the behavior is undefined. + \sa qstrncpy() */ char *qstrcpy(char *dst, const char *src) { if (!src) - return 0; + return nullptr; #ifdef Q_CC_MSVC const int len = int(strlen(src)); // This is actually not secure!!! It will be fixed // properly in a later release! if (len >= 0 && strcpy_s(dst, len+1, src) == 0) return dst; - return 0; + return nullptr; #else return strcpy(dst, src); #endif @@ -287,11 +290,13 @@ char *qstrcpy(char *dst, const char *src) Copies at most \a len bytes from \a src (stopping at \a len or the terminating '\\0' whichever comes first) into \a dst and returns a pointer to \a dst. Guarantees that \a dst is '\\0'-terminated. If - \a src or \a dst is 0, returns 0 immediately. + \a src or \a dst is nullptr, returns nullptr immediately. This function assumes that \a dst is at least \a len characters long. + \note If \a dst and \a src overlap, the behavior is undefined. + \note When compiling with Visual C++ compiler version 14.00 (Visual C++ 2005) or later, internally the function strncpy_s will be used. @@ -302,7 +307,7 @@ char *qstrcpy(char *dst, const char *src) char *qstrncpy(char *dst, const char *src, uint len) { if (!src || !dst) - return 0; + return nullptr; if (len > 0) { #ifdef Q_CC_MSVC strncpy_s(dst, len, src, len - 1); @@ -320,7 +325,7 @@ char *qstrncpy(char *dst, const char *src, uint len) A safe \c strlen() function. Returns the number of characters that precede the terminating '\\0', - or 0 if \a str is 0. + or 0 if \a str is nullptr. \sa qstrnlen() */ @@ -332,7 +337,7 @@ char *qstrncpy(char *dst, const char *src, uint len) A safe \c strnlen() function. Returns the number of characters that precede the terminating '\\0', but - at most \a maxlen. If \a str is 0, returns 0. + at most \a maxlen. If \a str is nullptr, returns 0. \sa qstrlen() */ @@ -346,10 +351,10 @@ char *qstrncpy(char *dst, const char *src, uint len) is less than \a str2, 0 if \a str1 is equal to \a str2 or a positive value if \a str1 is greater than \a str2. - Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + Special case 1: Returns 0 if \a str1 and \a str2 are both nullptr. - Special case 2: Returns an arbitrary non-zero value if \a str1 is 0 - or \a str2 is 0 (but not both). + Special case 2: Returns an arbitrary non-zero value if \a str1 is + nullptr or \a str2 is nullptr (but not both). \sa qstrncmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons} */ @@ -371,10 +376,10 @@ int qstrcmp(const char *str1, const char *str2) str1 is equal to \a str2 or a positive value if \a str1 is greater than \a str2. - Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + Special case 1: Returns 0 if \a str1 and \a str2 are both nullptr. - Special case 2: Returns a random non-zero value if \a str1 is 0 - or \a str2 is 0 (but not both). + Special case 2: Returns a random non-zero value if \a str1 is nullptr + or \a str2 is nullptr (but not both). \sa qstrcmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons} */ @@ -390,10 +395,10 @@ int qstrcmp(const char *str1, const char *str2) str1 is equal to \a str2 or a positive value if \a str1 is greater than \a str2. - Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + Special case 1: Returns 0 if \a str1 and \a str2 are both nullptr. - Special case 2: Returns a random non-zero value if \a str1 is 0 - or \a str2 is 0 (but not both). + Special case 2: Returns a random non-zero value if \a str1 is nullptr + or \a str2 is nullptr (but not both). \sa qstrcmp(), qstrncmp(), qstrnicmp(), {8-bit Character Comparisons} */ @@ -424,10 +429,10 @@ int qstricmp(const char *str1, const char *str2) is equal to \a str2 or a positive value if \a str1 is greater than \a str2. - Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + Special case 1: Returns 0 if \a str1 and \a str2 are both nullptr. - Special case 2: Returns a random non-zero value if \a str1 is 0 - or \a str2 is 0 (but not both). + Special case 2: Returns a random non-zero value if \a str1 is nullptr + or \a str2 is nullptr (but not both). \sa qstrcmp(), qstrncmp(), qstricmp(), {8-bit Character Comparisons} */ @@ -777,19 +782,6 @@ QByteArray qUncompress(const uchar* data, int nbytes) } #endif -static inline bool qIsUpper(char c) -{ - return c >= 'A' && c <= 'Z'; -} - -static inline char qToLower(char c) -{ - if (c >= 'A' && c <= 'Z') - return c - 'A' + 'a'; - else - return c; -} - /*! \class QByteArray \inmodule QtCore @@ -4131,9 +4123,10 @@ QByteArray &QByteArray::setNum(double n, char f, int prec) QLocaleData::DoubleForm form = QLocaleData::DFDecimal; uint flags = QLocaleData::ZeroPadExponent; - if (qIsUpper(f)) + char lower = latin1_lowercased[uchar(f)]; + if (f != lower) flags |= QLocaleData::CapitalEorX; - f = qToLower(f); + f = lower; switch (f) { case 'f': diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index 551e01e076..d03518e70d 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -44,7 +44,9 @@ #include "qset.h" #include "qlocale.h" #include "qdatetime.h" +#if QT_CONFIG(timezone) #include "qtimezone.h" +#endif #include "qregexp.h" #include "qdebug.h" diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 33835e3d28..17aba8035b 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -408,15 +408,20 @@ void **QListData::erase(void **xi) from strings. QList stores a list of items. The default constructor creates an - empty list. To insert items into the list, you can use - operator<<(): + empty list. You can use the initializer-list constructor to create + a list with elements: - \snippet code/src_corelib_tools_qlistdata.cpp 1 + \snippet code/src_corelib_tools_qlistdata.cpp 1a QList provides these basic functions to add, move, and remove items: insert(), replace(), removeAt(), move(), and swap(). In addition, it provides the following convenience functions: - append(), prepend(), removeFirst(), and removeLast(). + append(), \l{operator<<()}, \l{operator+=()}, prepend(), removeFirst(), + and removeLast(). + + \l{operator<<()} allows to conveniently add multiple elements to a list: + + \snippet code/src_corelib_tools_qlistdata.cpp 1b QList uses 0-based indexes, just like C++ arrays. To access the item at a particular index position, you can use operator[](). On diff --git a/src/corelib/tools/qlocale_unix.cpp b/src/corelib/tools/qlocale_unix.cpp index 095001e0a3..f202082213 100644 --- a/src/corelib/tools/qlocale_unix.cpp +++ b/src/corelib/tools/qlocale_unix.cpp @@ -107,27 +107,55 @@ Q_GLOBAL_STATIC(QSystemLocaleData, qSystemLocaleData) #ifndef QT_NO_SYSTEMLOCALE +static bool contradicts(const QString &maybe, const QString &known) +{ + if (maybe.isEmpty()) + return false; + + /* + If \a known (our current best shot at deciding which language to use) + provides more information (e.g. script, country) than \a maybe (a + candidate to replace \a known) and \a maybe agrees with \a known in what + it does provide, we keep \a known; this happens when \a maybe comes from + LANGUAGE (usually a simple language code) and LANG includes script and/or + country. A textual comparison won't do because, for example, bn (Bengali) + isn't a prefix of ben_IN, but the latter is a refinement of the former. + (Meanwhile, bn is a prefix of bnt, Bantu; and a prefix of ben is be, + Belarusian. There are many more such prefixings between two- and + three-letter codes.) + */ + QLocale::Language langm, langk; + QLocale::Script scriptm, scriptk; + QLocale::Country landm, landk; + QLocalePrivate::getLangAndCountry(maybe, langm, scriptm, landm); + QLocalePrivate::getLangAndCountry(known, langk, scriptk, landk); + return (langm != QLocale::AnyLanguage && langm != langk) + || (scriptm != QLocale::AnyScript && scriptm != scriptk) + || (landm != QLocale::AnyCountry && landm != landk); +} + QLocale QSystemLocale::fallbackUiLocale() const { - QByteArray lang = qgetenv("LC_ALL"); + // See man 7 locale for precedence - LC_ALL beats LC_MESSAGES beats LANG: + QString lang = qEnvironmentVariable("LC_ALL"); if (lang.isEmpty()) - lang = qgetenv("LC_MESSAGES"); + lang = qEnvironmentVariable("LC_MESSAGES"); if (lang.isEmpty()) - lang = qgetenv("LANG"); + lang = qEnvironmentVariable("LANG"); // if the locale is the "C" locale, then we can return the language we found here: - if (lang.isEmpty() || lang == QByteArray("C") || lang == QByteArray("POSIX")) - return QLocale(QString::fromLatin1(lang)); + if (lang.isEmpty() || lang == QLatin1String("C") || lang == QLatin1String("POSIX")) + return QLocale(lang); - // if the locale is not the "C" locale and LANGUAGE is not empty, return - // the first part of LANGUAGE if LANGUAGE is set and has a first part: - QByteArray language = qgetenv("LANGUAGE"); + // ... otherwise, if the first part of LANGUAGE says more than or + // contradicts what we have, use that: + QString language = qEnvironmentVariable("LANGUAGE"); if (!language.isEmpty()) { - language = language.split(':').constFirst(); - if (!language.isEmpty()) - return QLocale(QString::fromLatin1(language)); + language = language.split(QLatin1Char(':')).constFirst(); + if (contradicts(language, lang)) + return QLocale(language); } - return QLocale(QString::fromLatin1(lang)); + return QLocale(lang); } QVariant QSystemLocale::query(QueryType type, QVariant in) const diff --git a/src/corelib/tools/qpoint.h b/src/corelib/tools/qpoint.h index 0f3e0c3517..ae46f0d39f 100644 --- a/src/corelib/tools/qpoint.h +++ b/src/corelib/tools/qpoint.h @@ -345,16 +345,24 @@ Q_DECL_RELAXED_CONSTEXPR inline QPointF &QPointF::operator*=(qreal c) xp*=c; yp*=c; return *this; } +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG("-Wfloat-equal") +QT_WARNING_DISABLE_GCC("-Wfloat-equal") + Q_DECL_CONSTEXPR inline bool operator==(const QPointF &p1, const QPointF &p2) { - return qFuzzyIsNull(p1.xp - p2.xp) && qFuzzyIsNull(p1.yp - p2.yp); + return ((!p1.xp && !p1.yp) || (!p2.xp && !p2.yp)) + ? (qFuzzyIsNull(p1.xp - p2.xp) && qFuzzyIsNull(p1.yp - p2.yp)) + : (qFuzzyCompare(p1.xp, p2.xp) && qFuzzyCompare(p1.yp, p2.yp)); } Q_DECL_CONSTEXPR inline bool operator!=(const QPointF &p1, const QPointF &p2) { - return !qFuzzyIsNull(p1.xp - p2.xp) || !qFuzzyIsNull(p1.yp - p2.yp); + return !(p1 == p2); } +QT_WARNING_POP + Q_DECL_CONSTEXPR inline const QPointF operator+(const QPointF &p1, const QPointF &p2) { return QPointF(p1.xp+p2.xp, p1.yp+p2.yp); diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index a0e408b94a..bccf8c5740 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -246,7 +246,8 @@ namespace QtSharedPointer { struct ExternalRefCountWithContiguousData: public ExternalRefCountData { typedef ExternalRefCountData Parent; - T data; + typedef typename std::remove_cv<T>::type NoCVType; + NoCVType data; static void deleter(ExternalRefCountData *self) { @@ -262,7 +263,7 @@ namespace QtSharedPointer { } static void noDeleter(ExternalRefCountData *) { } - static inline ExternalRefCountData *create(T **ptr, DestroyerFn destroy) + static inline ExternalRefCountData *create(NoCVType **ptr, DestroyerFn destroy) { ExternalRefCountWithContiguousData *d = static_cast<ExternalRefCountWithContiguousData *>(::operator new(sizeof(ExternalRefCountWithContiguousData))); @@ -437,10 +438,12 @@ public: # endif typename Private::DestroyerFn noDestroy = &Private::noDeleter; QSharedPointer result(Qt::Uninitialized); - result.d = Private::create(&result.value, noDestroy); + typename std::remove_cv<T>::type *ptr; + result.d = Private::create(&ptr, noDestroy); // now initialize the data - new (result.data()) T(std::forward<Args>(arguments)...); + new (ptr) T(std::forward<Args>(arguments)...); + result.value = ptr; result.d->destroyer = destroy; result.d->setQObjectShared(result.value, true); # ifdef QT_SHAREDPOINTER_TRACK_POINTERS diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index eb56b31348..18684caefb 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -219,9 +219,8 @@ // AVX intrinsics # 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 -// (but neither MSVC nor the Intel compiler define these macros) -# define __AES__ 1 +// All processors that support AVX support PCLMULQDQ +// (but neither MSVC nor the Intel compiler define this macro) # define __PCLMUL__ 1 # endif diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index f6360f5504..a4b34263df 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -259,7 +259,7 @@ 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) { + while (ptr + 32 <= end) { __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr)); if (!_mm256_testz_si256(mask256, data)) return false; @@ -271,7 +271,7 @@ static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval) // 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) { + 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)) @@ -283,7 +283,7 @@ static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval) # endif # if defined(__SSE4_1__) // AVX2 and SSE4.1: final 16-byte comparison - if (ptr + 16 < end) { + if (ptr + 16 <= end) { __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); if (!_mm_testz_si128(mask, data1)) return false; @@ -311,12 +311,19 @@ 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__) +#if defined(__SSE2__) // Testing for the high bit can be done efficiently with just PMOVMSKB - while (ptr + 16 < end) { +# if defined(__AVX2__) + while (ptr + 32 <= end) { + __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr)); + quint32 mask = _mm256_movemask_epi8(data); + if (mask) + return false; + ptr += 32; + } +# endif + + while (ptr + 16 <= end) { __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); quint32 mask = _mm_movemask_epi8(data); if (mask) @@ -325,7 +332,7 @@ bool QtPrivate::isAscii(QLatin1String s) Q_DECL_NOTHROW } #endif - while (ptr + 4 < end) { + while (ptr + 4 <= end) { quint32 data = qFromUnaligned<quint32>(ptr); if (data & 0x80808080U) return false; @@ -646,30 +653,70 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) } #endif // __mips_dsp #ifdef __SSE2__ - const char *ptr = reinterpret_cast<const char*>(a); - qptrdiff distance = reinterpret_cast<const char*>(b) - ptr; - a += l & ~7; - b += l & ~7; - l &= 7; - - // we're going to read ptr[0..15] (16 bytes) - for ( ; ptr + 15 < reinterpret_cast<const char *>(a); ptr += 16) { - __m128i a_data = _mm_loadu_si128((const __m128i*)ptr); - __m128i b_data = _mm_loadu_si128((const __m128i*)(ptr + distance)); + const QChar *end = a + l; + qptrdiff offset = 0; + + // we're going to read a[0..15] and b[0..15] (32 bytes) + for ( ; a + offset + 16 <= end; offset += 16) { +#ifdef __AVX2__ + __m256i a_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(a + offset)); + __m256i b_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(b + offset)); + __m256i result = _mm256_cmpeq_epi16(a_data, b_data); + uint mask = _mm256_movemask_epi8(result); +#else + __m128i a_data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset)); + __m128i a_data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset + 8)); + __m128i b_data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset)); + __m128i b_data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset + 8)); + __m128i result1 = _mm_cmpeq_epi16(a_data1, b_data1); + __m128i result2 = _mm_cmpeq_epi16(a_data2, b_data2); + uint mask = _mm_movemask_epi8(result1) | (_mm_movemask_epi8(result2) << 16); +#endif + mask = ~mask; + if (mask) { + // found a different character + uint idx = qCountTrailingZeroBits(mask); + return a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode(); + } + } + + // we're going to read a[0..7] and b[0..7] (16 bytes) + if (a + offset + 8 <= end) { + __m128i a_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset)); + __m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset)); __m128i result = _mm_cmpeq_epi16(a_data, b_data); uint mask = ~_mm_movemask_epi8(result); if (ushort(mask)) { - // found a different byte + // found a different character + uint idx = qCountTrailingZeroBits(mask); + return a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode(); + } + + offset += 8; + } + + // we're going to read a[0..3] and b[0..3] (8 bytes) + if (a + offset + 4 <= end) { + __m128i a_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(a + offset)); + __m128i b_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(b + offset)); + __m128i result = _mm_cmpeq_epi16(a_data, b_data); + uint mask = ~_mm_movemask_epi8(result); + if (uchar(mask)) { + // found a different character uint idx = qCountTrailingZeroBits(mask); - return reinterpret_cast<const QChar *>(ptr + idx)->unicode() - - reinterpret_cast<const QChar *>(ptr + distance + idx)->unicode(); + return a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode(); } + + offset += 4; } + + // reset l + l &= 3; + const auto lambda = [=](size_t i) -> int { - return reinterpret_cast<const QChar *>(ptr)[i].unicode() - - reinterpret_cast<const QChar *>(ptr + distance)[i].unicode(); + return a[offset + i].unicode() - b[offset + i].unicode(); }; - return UnrollTailLoop<7>::exec(l, 0, lambda, lambda); + return UnrollTailLoop<3>::exec(l, 0, lambda, lambda); #endif #if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64 if (l >= 8) { diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp index d10d9ad9d0..c9db39a29f 100644 --- a/src/corelib/tools/qstringlist.cpp +++ b/src/corelib/tools/qstringlist.cpp @@ -98,14 +98,25 @@ QT_BEGIN_NAMESPACE \tableofcontents + \section1 Initializing + + The default constructor creates an empty list. You can use the + initializer-list constructor to create a list with elements: + + \snippet qstringlist/main.cpp 0a + \section1 Adding Strings Strings can be added to a list using the \l + {QList::insert()}{insert()} \l {QList::append()}{append()}, \l {QList::operator+=()}{operator+=()} and \l - {QStringList::operator<<()}{operator<<()} functions. For example: + {operator<<()} functions. + + \l{operator<<()} can be used to + conveniently add multiple elements to a list: - \snippet qstringlist/main.cpp 0 + \snippet qstringlist/main.cpp 0b \section1 Iterating Over the Strings |