diff options
Diffstat (limited to 'src/corelib')
63 files changed, 1857 insertions, 519 deletions
diff --git a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp index 39b03f5ff3..e91c41b305 100644 --- a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp +++ b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp @@ -49,6 +49,7 @@ ****************************************************************************/ #include <QtGui> +#include <QtWidgets> #include "buttonwidget.h" @@ -74,3 +75,18 @@ ButtonWidget::ButtonWidget(const QStringList &texts, QWidget *parent) setLayout(gridLayout); } //! [2] + +//! [3] +ButtonWidget::ButtonWidget(const QStringList &texts, QWidget *parent) + : QWidget(parent) +{ + QGridLayout *gridLayout = new QGridLayout; + for (int i = 0; i < texts.size(); ++i) { + QString text = texts[i]; + QPushButton *button = new QPushButton(text); + connect(button, &QPushButton::clicked, [=] { clicked(text); }); + gridLayout->addWidget(button, i / 3, i % 3); + } + setLayout(gridLayout); +} +//! [3] diff --git a/src/corelib/doc/snippets/signalmapper/filereader.cpp b/src/corelib/doc/snippets/signalmapper/filereader.cpp deleted file mode 100644 index 674f73d671..0000000000 --- a/src/corelib/doc/snippets/signalmapper/filereader.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the config.tests of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtGui> -#include "filereader.h" - - -FileReader::FileReader(QWidget *parent) - : QWidget(parent) -{ - textEdit = new QTextEdit; - - taxFileButton = new QPushButton("Tax File"); - accountFileButton = new QPushButton("Accounts File"); - reportFileButton = new QPushButton("Report File"); - -//! [0] - signalMapper = new QSignalMapper(this); - signalMapper->setMapping(taxFileButton, QString("taxfile.txt")); - signalMapper->setMapping(accountFileButton, QString("accountsfile.txt")); - signalMapper->setMapping(reportFileButton, QString("reportfile.txt")); - - connect(taxFileButton, &QPushButton::clicked, - signalMapper, &QSignalMapper::map); - connect(accountFileButton, &QPushButton::clicked, - signalMapper, &QSignalMapper::map); - connect(reportFileButton, &QPushButton::clicked, - signalMapper, &QSignalMapper::map); -//! [0] - -//! [1] - connect(signalMapper, SIGNAL(mapped(QString)), - this, SLOT(readFile(QString))); -//! [1] - -/* -//! [2] - //slower due to signature normalization at runtime - - connect(signalMapper, SIGNAL(mapped(QString)), - this, SLOT(readFile(QString))); -//! [2] -*/ - QHBoxLayout *buttonLayout = new QHBoxLayout; - buttonLayout->addWidget(taxFileButton); - buttonLayout->addWidget(accountFileButton); - buttonLayout->addWidget(reportFileButton); - - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(textEdit); - mainLayout->addLayout(buttonLayout); - - setLayout(mainLayout); -} - -void FileReader::readFile(const QString &filename) -{ - QFile file(filename); - - if (!file.open(QIODevice::ReadOnly)) { - QMessageBox::information(this, tr("Unable to open file"), - file.errorString()); - return; - } - - - QTextStream in(&file); - textEdit->setPlainText(in.readAll()); -} - diff --git a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc index ed61511c62..6d3064d217 100644 --- a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc +++ b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc @@ -395,24 +395,12 @@ signal, Qt provides the QObject::sender() function, which returns a pointer to the object that sent the signal. - The QSignalMapper class is provided for situations where many - signals are connected to the same slot and the slot needs to - handle each signal differently. + Lambda expressions are a convenient way to pass custom arguments to a slot: - Suppose you have three push buttons that determine which file you - will open: "Tax File", "Accounts File", or "Report File". - - In order to open the correct file, you use QSignalMapper::setMapping() to - map all the QPushButton::clicked() signals to a QSignalMapper object. Then you connect - the file's QPushButton::clicked() signal to the QSignalMapper::map() slot. - - \snippet signalmapper/filereader.cpp 0 - - Then, you connect the \l{QSignalMapper::}{mapped()} signal to - \c{readFile()} where a different file will be opened, depending on - which push button is pressed. - - \snippet signalmapper/filereader.cpp 1 + \code + connect(action, &QAction::triggered, engine, + [=]() { engine->processAction(action->text()); }); + \endcode \sa {Meta-Object System}, {Qt's Property System} diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 6dba733fb4..871810e5a3 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -4419,8 +4419,11 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters) stderr. Under Windows, the message is sent to the debugger. On QNX the message is sent to slogger2. This function does nothing if \c QT_NO_WARNING_OUTPUT was defined - during compilation; it exits if the environment variable \c - QT_FATAL_WARNINGS is not empty. + during compilation; it exits if at the nth warning corresponding to the + counter in environment variable \c QT_FATAL_WARNINGS. That is, if the + environment variable contains the value 1, it will exit on the 1st message; + if it contains the value 10, it will exit on the 10th message. Any + non-numeric value is equivalent to 1. This function takes a format string and a list of arguments, similar to the C printf() function. The format should be a Latin-1 diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 9ac29acd16..12220e10b5 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -612,6 +612,18 @@ private: void *pool; }; +#else + +#define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) (0) +#define QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios) (0) +#define QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos) (0) +#define QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(ios) (0) +#define QT_TVOS_PLATFORM_SDK_EQUAL_OR_ABOVE(tvos) (0) +#define QT_WATCHOS_PLATFORM_SDK_EQUAL_OR_ABOVE(watchos) (0) + +#define QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, ios) (0) +#define QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(osx) (0) + #endif // Q_OS_DARWIN /* @@ -704,9 +716,9 @@ Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line) #if !defined(Q_ASSERT) # if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) -# define Q_ASSERT(cond) do { } while ((false) && (cond)) +# define Q_ASSERT(cond) static_cast<void>(false && (cond)) # else -# define Q_ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop()) +# define Q_ASSERT(cond) ((cond) ? static_cast<void>(0) : qt_assert(#cond, __FILE__, __LINE__)) # endif #endif @@ -721,9 +733,9 @@ Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char * #if !defined(Q_ASSERT_X) # if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) -# define Q_ASSERT_X(cond, where, what) do { } while ((false) && (cond)) +# define Q_ASSERT_X(cond, where, what) static_cast<void>(false && (cond)) # else -# define Q_ASSERT_X(cond, where, what) ((!(cond)) ? qt_assert_x(where, what,__FILE__,__LINE__) : qt_noop()) +# define Q_ASSERT_X(cond, where, what) ((cond) ? static_cast<void>(0) : qt_assert_x(where, what, __FILE__, __LINE__)) # endif #endif diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 6573e0a53e..927c1bb76b 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -153,19 +153,39 @@ Q_NORETURN static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message); static void qt_message_print(QtMsgType, const QMessageLogContext &context, const QString &message); +static int checked_var_value(const char *varname) +{ + // qEnvironmentVariableIntValue returns 0 on both parsing failure and on + // empty, but we need to distinguish between the two for backwards + // compatibility reasons. + QByteArray str = qgetenv(varname); + if (str.isEmpty()) + return 0; + + bool ok; + int value = str.toInt(&ok, 0); + return ok ? value : 1; +} + static bool isFatal(QtMsgType msgType) { if (msgType == QtFatalMsg) return true; if (msgType == QtCriticalMsg) { - static bool fatalCriticals = !qEnvironmentVariableIsEmpty("QT_FATAL_CRITICALS"); - return fatalCriticals; + static QAtomicInt fatalCriticals = checked_var_value("QT_FATAL_CRITICALS"); + + // it's fatal if the current value is exactly 1, + // otherwise decrement if it's non-zero + return fatalCriticals.load() && fatalCriticals.fetchAndAddRelaxed(-1) == 1; } if (msgType == QtWarningMsg || msgType == QtCriticalMsg) { - static bool fatalWarnings = !qEnvironmentVariableIsEmpty("QT_FATAL_WARNINGS"); - return fatalWarnings; + static QAtomicInt fatalWarnings = checked_var_value("QT_FATAL_WARNINGS"); + + // it's fatal if the current value is exactly 1, + // otherwise decrement if it's non-zero + return fatalWarnings.load() && fatalWarnings.fetchAndAddRelaxed(-1) == 1; } return false; diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index da44c01594..dbc8b368b3 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -508,6 +508,7 @@ public: AA_CompressHighFrequencyEvents = 25, AA_DontCheckOpenGLContextThreadAffinity = 26, AA_DisableShaderDiskCache = 27, + AA_DontShowShortcutsInContextMenus = 28, // Add new attributes before this line AA_AttributeCount diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 404bbfe65a..cd60774ee6 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -114,6 +114,11 @@ \macos menubar \e{may not} pick up a change in this attribute. Changes in the QAction::iconVisibleInMenu property will always be picked up. + \value AA_DontShowShortcutsInContextMenus Actions with the Shortcut property + won't be shown in any shortcut menus unless specifically set by the + QAction::shortcutVisibleInContextMenu property. This value has + been added in Qt 5.10. + \value AA_NativeWindows Ensures that widgets have native windows. \value AA_DontCreateNativeWidgetSiblings Ensures that siblings of native diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h index 7031021e16..4f79c48c51 100644 --- a/src/corelib/global/qtypeinfo.h +++ b/src/corelib/global/qtypeinfo.h @@ -311,14 +311,11 @@ Q_DECLARE_TYPEINFO(qint64, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(quint64, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(float, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(double, Q_PRIMITIVE_TYPE); -#ifndef Q_OS_DARWIN -Q_DECLARE_TYPEINFO(long double, Q_PRIMITIVE_TYPE); -#endif - #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) // ### Qt 6: remove the other branch // This was required so that QList<T> for these types allocates out of the array storage +Q_DECLARE_TYPEINFO(long double, Q_PRIMITIVE_TYPE); # ifdef Q_COMPILER_UNICODE_STRINGS Q_DECLARE_TYPEINFO(char16_t, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(char32_t, Q_PRIMITIVE_TYPE); @@ -327,6 +324,11 @@ Q_DECLARE_TYPEINFO(char32_t, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(wchar_t, Q_PRIMITIVE_TYPE); # endif #else +# ifndef Q_OS_DARWIN +Q_DECLARE_TYPEINFO(long double, Q_PRIMITIVE_TYPE); +# else +Q_DECLARE_TYPEINFO(long double, Q_RELOCATABLE_TYPE); +# endif # ifdef Q_COMPILER_UNICODE_STRINGS Q_DECLARE_TYPEINFO(char16_t, Q_RELOCATABLE_TYPE); Q_DECLARE_TYPEINFO(char32_t, Q_RELOCATABLE_TYPE); diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 9606ec68e9..5f1f7e381e 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -832,6 +832,19 @@ bool QAbstractFileEngine::unmap(uchar *address) } /*! + \since 5.10 + + Copies the contents from the file specified by \a sourceHandle to this file + by cloning it. + Returns \c true on success; otherwise, \c false is returned. + */ +bool QAbstractFileEngine::clone(int sourceHandle) +{ + Q_UNUSED(sourceHandle); + return false; +} + +/*! \since 4.3 \class QAbstractFileEngineIterator \inmodule QtCore diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index 48b3dec324..dbf0d77b15 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -147,6 +147,7 @@ public: virtual QDateTime fileTime(FileTime time) const; virtual void setFileName(const QString &file); virtual int handle() const; + virtual bool clone(int sourceHandle); bool atEnd() const; uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags); bool unmap(uchar *ptr); diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 2369fe4726..58e2500057 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -562,6 +562,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_5_7 Same as Qt_5_6 \value Qt_5_8 Same as Qt_5_6 \value Qt_5_9 Same as Qt_5_6 + \value Qt_5_10 Same as Qt_5_6 \omitvalue Qt_DefaultCompiledVersion \sa setVersion(), version() diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index db1bbfbd63..993a20fcd3 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -96,10 +96,11 @@ public: Qt_5_7 = Qt_5_6, Qt_5_8 = Qt_5_7, Qt_5_9 = Qt_5_8, -#if QT_VERSION >= 0x050a00 + Qt_5_10 = Qt_5_9, +#if QT_VERSION >= 0x050b00 #error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion #endif - Qt_DefaultCompiledVersion = Qt_5_9 + Qt_DefaultCompiledVersion = Qt_5_10 }; enum ByteOrder { diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index be33ec2d23..341400fd93 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -648,6 +648,21 @@ QDebug &QDebug::resetFormat() */ /*! + \since 5.10 + \fn QDebug &QDebug::operator<<(QStringView s) + + Writes the string view, \a s, to the stream and returns a reference to the + stream. Normally, QDebug prints the string inside quotes and transforms + non-printable characters to their Unicode values (\\u1234). + + To print non-printable characters without transformation, enable the + noquote() functionality. Note that some QDebug backends might not be 8-bit + clean. + + See the QString overload for examples. +*/ + +/*! \fn QDebug &QDebug::operator<<(QLatin1String s) Writes the string, \a s, to the stream and returns a reference to the diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 61059dd694..d5f32a6efd 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -151,8 +151,11 @@ public: inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); } +#if QT_STRINGVIEW_LEVEL < 2 inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); } inline QDebug &operator<<(const QStringRef & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); } +#endif + inline QDebug &operator<<(QStringView s) { putString(s.data(), size_t(s.size())); return maybeSpace(); } inline QDebug &operator<<(QLatin1String t) { putByteArray(t.latin1(), t.size(), ContainsLatin1); return maybeSpace(); } inline QDebug &operator<<(const QByteArray & t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); } inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); } diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 41fae69bb2..6249d54f7d 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -42,6 +42,7 @@ #include "qfile.h" #include "qfsfileengine_p.h" #include "qtemporaryfile.h" +#include "qtemporaryfile_p.h" #include "qlist.h" #include "qfileinfo.h" #include "private/qiodevice_p.h" @@ -790,25 +791,27 @@ QFile::copy(const QString &newName) close(); d->setError(QFile::CopyError, tr("Cannot open for output")); } else { - char block[4096]; - qint64 totalRead = 0; - while(!atEnd()) { - qint64 in = read(block, sizeof(block)); - if (in <= 0) - break; - totalRead += in; - if(in != out.write(block, in)) { - close(); - d->setError(QFile::CopyError, tr("Failure to write block")); - error = true; - break; + if (!out.d_func()->engine()->clone(d->engine()->handle())) { + char block[4096]; + qint64 totalRead = 0; + while (!atEnd()) { + qint64 in = read(block, sizeof(block)); + if (in <= 0) + break; + totalRead += in; + if (in != out.write(block, in)) { + close(); + d->setError(QFile::CopyError, tr("Failure to write block")); + error = true; + break; + } } - } - if (totalRead != size()) { - // Unable to read from the source. The error string is - // already set from read(). - error = true; + if (totalRead != size()) { + // Unable to read from the source. The error string is + // already set from read(). + error = true; + } } if (!error && !out.rename(newName)) { error = true; diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 3cb412e47c..b8dca93f61 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -42,6 +42,7 @@ #include "qfilesystemengine_p.h" #include "qfile.h" +#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qvarlengtharray.h> #include <stdlib.h> // for realpath() @@ -66,6 +67,9 @@ #endif #if defined(Q_OS_DARWIN) +# if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000) +# include <sys/clonefile.h> +# endif // We cannot include <Foundation/Foundation.h> (it's an Objective-C header), but // we need these declarations: Q_FORWARD_DECLARE_OBJC_CLASS(NSString); @@ -659,8 +663,22 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy //static bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) { +#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000) + const auto current = QOperatingSystemVersion::current(); + if (current >= QOperatingSystemVersion::MacOSSierra || + current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 10) || + current >= QOperatingSystemVersion(QOperatingSystemVersion::TvOS, 10) || + current >= QOperatingSystemVersion(QOperatingSystemVersion::WatchOS, 3)) { + if (::clonefile(source.nativeFilePath().constData(), + target.nativeFilePath().constData(), 0) == 0) + return true; + error = QSystemError(errno, QSystemError::StandardLibraryError); + return false; + } +#else Q_UNUSED(source); Q_UNUSED(target); +#endif error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented return false; } diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index b1e218de9c..d95a6de777 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -48,7 +48,6 @@ #include "qfile.h" #include "qdir.h" -#include "private/qmutexpool_p.h" #include "qvarlengtharray.h" #include "qdatetime.h" #include "qt_windows.h" @@ -179,6 +178,7 @@ static TRUSTEE_W worldTrusteeW; static PSID currentUserSID = 0; static PSID worldSID = 0; +namespace { /* Deletes the allocated SIDs during global static cleanup */ @@ -202,25 +202,10 @@ SidCleanup::~SidCleanup() Q_GLOBAL_STATIC(SidCleanup, initSidCleanup) -static void resolveLibs() +struct LibResolver { - static bool triedResolve = false; - if (!triedResolve) { - // need to resolve the security info functions - - // protect initialization -#ifndef QT_NO_THREAD - QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); - // check triedResolve again, since another thread may have already - // done the initialization - if (triedResolve) { - // another thread did initialize the security function pointers, - // so we shouldn't do it again. - return; - } -#endif - - triedResolve = true; + LibResolver() + { HINSTANCE advapiHnd = QSystemLibrary::load(L"advapi32"); if (advapiHnd) { ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW"); @@ -267,9 +252,13 @@ static void resolveLibs() if (userenvHnd) ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW"); } -} +}; +Q_GLOBAL_STATIC(LibResolver, resolveLibs) + +} // anonymous namespace #endif // QT_CONFIG(fslibs) +QT_BEGIN_INCLUDE_NAMESPACE typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD); static PtrNetShareEnum ptrNetShareEnum = 0; typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID); @@ -279,19 +268,13 @@ typedef struct _SHARE_INFO_1 { DWORD shi1_type; LPWSTR shi1_remark; } SHARE_INFO_1; +QT_END_INCLUDE_NAMESPACE - -static bool resolveUNCLibs() +namespace { +struct UNCLibResolver { - static bool triedResolve = false; - if (!triedResolve) { -#ifndef QT_NO_THREAD - QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); - if (triedResolve) { - return ptrNetShareEnum && ptrNetApiBufferFree; - } -#endif - triedResolve = true; + UNCLibResolver() + { #if !defined(Q_OS_WINRT) HINSTANCE hLib = QSystemLibrary::load(L"Netapi32"); if (hLib) { @@ -301,6 +284,13 @@ static bool resolveUNCLibs() } #endif // !Q_OS_WINRT } +}; +Q_GLOBAL_STATIC(UNCLibResolver, uncLibResolver) +} // anonymous namespace + +static bool resolveUNCLibs() +{ + uncLibResolver(); return ptrNetShareEnum && ptrNetApiBufferFree; } diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 0b9cd0557f..de921c0be6 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -860,9 +860,9 @@ bool QFSFileEngine::supportsExtension(Extension extension) const /*! \fn bool QFSFileEngine::copy(const QString ©Name) - For windows, copy the file to file \a copyName. + For Windows or Apple platforms, copy the file to file \a copyName. - Not implemented for Unix. + Not implemented for other Unix platforms. */ /*! \fn QString QFSFileEngine::currentPath(const QString &fileName) diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 593ecc2687..742cebad87 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -108,6 +108,7 @@ public: qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 readLine(char *data, qint64 maxlen) Q_DECL_OVERRIDE; qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; + bool clone(int sourceHandle) override; bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) Q_DECL_OVERRIDE; bool supportsExtension(Extension extension) const Q_DECL_OVERRIDE; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index e152b035e2..4be4e893b3 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -793,6 +793,23 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) #endif } +/*! + \reimp +*/ +bool QFSFileEngine::clone(int sourceHandle) +{ +#if defined(Q_OS_LINUX) + Q_D(QFSFileEngine); +# if !defined FICLONE +# define FICLONE _IOW (0x94, 9, int) +# endif + return ::ioctl(d->fd, FICLONE, sourceHandle) == 0; +#else + Q_UNUSED(sourceHandle); + return false; +#endif +} + QT_END_NAMESPACE #endif // QT_NO_FSFILEENGINE diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 7d16e59195..4a477b8429 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -998,4 +998,13 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) return true; } +/*! + \reimp +*/ +bool QFSFileEngine::clone(int sourceHandle) +{ + Q_UNUSED(sourceHandle); + return false; +} + QT_END_NAMESPACE diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 16dab38a60..24fa00c4d9 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1802,6 +1802,8 @@ struct QSettingsIniSection inline QSettingsIniSection() : position(-1) {} }; +Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE); + typedef QMap<QString, QSettingsIniSection> IniMap; /* diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index 639605d8c4..d8e91e48ce 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -109,6 +109,8 @@ private: }; #endif +Q_DECLARE_TYPEINFO(QSettingsKey, Q_MOVABLE_TYPE); + typedef QMap<QSettingsKey, QByteArray> UnparsedSettingsMap; typedef QMap<QSettingsKey, QVariant> ParsedSettingsMap; diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h index 7f365f0e8a..bf40e1627a 100644 --- a/src/corelib/io/qtemporaryfile_p.h +++ b/src/corelib/io/qtemporaryfile_p.h @@ -65,7 +65,7 @@ class QTemporaryFilePrivate : public QFilePrivate { Q_DECLARE_PUBLIC(QTemporaryFile) -protected: +public: QTemporaryFilePrivate(); explicit QTemporaryFilePrivate(const QString &templateNameIn); ~QTemporaryFilePrivate(); diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 226a2401e1..7824559f5f 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -56,6 +56,15 @@ QT_BEGIN_NAMESPACE typedef QVector<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList; +struct QSortFilterProxyModelDataChanged +{ + QSortFilterProxyModelDataChanged(const QModelIndex &tl, const QModelIndex &br) + : topLeft(tl), bottomRight(br) { } + + QModelIndex topLeft; + QModelIndex bottomRight; +}; + static inline QSet<int> qVectorToSet(const QVector<int> &vector) { QSet<int> set; @@ -164,9 +173,12 @@ public: bool sort_localeaware; int filter_column; - QRegExp filter_regexp; int filter_role; + QRegExp filter_regexp; + QModelIndex last_top_source; + bool filter_recursive; + bool complete_insert; bool dynamic_sortfilter; QRowsRemoval itemsBeingRemoved; @@ -289,6 +301,11 @@ public: Qt::Orientation orient, int start, int end, int delta_item_count, bool remove); virtual void _q_sourceModelDestroyed() Q_DECL_OVERRIDE; + + bool needsReorder(const QVector<int> &source_rows, const QModelIndex &source_parent) const; + + bool filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const; + bool filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const; }; typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap; @@ -300,6 +317,32 @@ void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed() source_index_mapping.clear(); } +bool QSortFilterProxyModelPrivate::filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const +{ + Q_Q(const QSortFilterProxyModel); + return filter_recursive + ? filterRecursiveAcceptsRow(source_row, source_parent) + : q->filterAcceptsRow(source_row, source_parent); +} + +bool QSortFilterProxyModelPrivate::filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + Q_Q(const QSortFilterProxyModel); + + if (q->filterAcceptsRow(source_row, source_parent)) + return true; + + const QModelIndex index = model->index(source_row, 0, source_parent); + const int count = model->rowCount(index); + + for (int i = 0; i < count; ++i) { + if (filterRecursiveAcceptsRow(i, index)) + return true; + } + + return false; +} + void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent) { if (Mapping *m = source_index_mapping.take(source_parent)) { @@ -340,7 +383,7 @@ IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping( int source_rows = model->rowCount(source_parent); m->source_rows.reserve(source_rows); for (int i = 0; i < source_rows; ++i) { - if (q->filterAcceptsRow(i, source_parent)) + if (filterAcceptsRowInternal(i, source_parent)) m->source_rows.append(i); } int source_cols = model->columnCount(source_parent); @@ -794,7 +837,7 @@ void QSortFilterProxyModelPrivate::source_items_inserted( QVector<int> source_items; for (int i = start; i <= end; ++i) { if ((orient == Qt::Vertical) - ? q->filterAcceptsRow(i, source_parent) + ? filterAcceptsRowInternal(i, source_parent) : q->filterAcceptsColumn(i, source_parent)) { source_items.append(i); } @@ -814,7 +857,7 @@ void QSortFilterProxyModelPrivate::source_items_inserted( orthogonal_source_to_proxy.resize(ortho_end); for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) { - if ((orient == Qt::Horizontal) ? q->filterAcceptsRow(ortho_item, source_parent) + if ((orient == Qt::Horizontal) ? filterAcceptsRowInternal(ortho_item, source_parent) : q->filterAcceptsColumn(ortho_item, source_parent)) { orthogonal_proxy_to_source.append(ortho_item); } @@ -1125,7 +1168,7 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed( for (int i = 0; i < proxy_to_source.count(); ++i) { const int source_item = proxy_to_source.at(i); if ((orient == Qt::Vertical) - ? !q->filterAcceptsRow(source_item, source_parent) + ? !filterAcceptsRowInternal(source_item, source_parent) : !q->filterAcceptsColumn(source_item, source_parent)) { // This source item does not satisfy the filter, so it must be removed source_items_remove.append(source_item); @@ -1137,7 +1180,7 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed( for (int source_item = 0; source_item < source_count; ++source_item) { if (source_to_proxy.at(source_item) == -1) { if ((orient == Qt::Vertical) - ? q->filterAcceptsRow(source_item, source_parent) + ? filterAcceptsRowInternal(source_item, source_parent) : q->filterAcceptsColumn(source_item, source_parent)) { // This source item satisfies the filter, so it must be added source_items_insert.append(source_item); @@ -1156,6 +1199,33 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed( return qVectorToSet(source_items_remove); } +bool QSortFilterProxyModelPrivate::needsReorder(const QVector<int> &source_rows, const QModelIndex &source_parent) const +{ + Q_Q(const QSortFilterProxyModel); + Q_ASSERT(source_sort_column != -1); + const int proxyRowCount = q->rowCount(source_to_proxy(source_parent)); + // If any modified proxy row no longer passes lessThan(previous, current) or lessThan(current, next) then we need to reorder. + return std::any_of(source_rows.begin(), source_rows.end(), + [this, q, proxyRowCount, source_parent](int sourceRow) -> bool { + const QModelIndex sourceIndex = model->index(sourceRow, source_sort_column, source_parent); + const QModelIndex proxyIndex = source_to_proxy(sourceIndex); + Q_ASSERT(proxyIndex.isValid()); // caller ensured source_rows were not filtered out + if (proxyIndex.row() > 0) { + const QModelIndex prevProxyIndex = q->sibling(proxyIndex.row() - 1, proxy_sort_column, proxyIndex); + const QModelIndex prevSourceIndex = proxy_to_source(prevProxyIndex); + if (sort_order == Qt::AscendingOrder ? q->lessThan(sourceIndex, prevSourceIndex) : q->lessThan(prevSourceIndex, sourceIndex)) + return true; + } + if (proxyIndex.row() < proxyRowCount - 1) { + const QModelIndex nextProxyIndex = q->sibling(proxyIndex.row() + 1, proxy_sort_column, proxyIndex); + const QModelIndex nextSourceIndex = proxy_to_source(nextProxyIndex); + if (sort_order == Qt::AscendingOrder ? q->lessThan(nextSourceIndex, sourceIndex) : q->lessThan(sourceIndex, nextSourceIndex)) + return true; + } + return false; + }); +} + void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector<int> &roles) @@ -1163,106 +1233,127 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc Q_Q(QSortFilterProxyModel); if (!source_top_left.isValid() || !source_bottom_right.isValid()) return; - QModelIndex source_parent = source_top_left.parent(); - IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); - if (it == source_index_mapping.constEnd()) { - // Don't care, since we don't have mapping for this index - return; + + std::vector<QSortFilterProxyModelDataChanged> data_changed_list; + data_changed_list.emplace_back(source_top_left, source_bottom_right); + + // Do check parents if the filter role have changed and we are recursive + if (filter_recursive && (roles.isEmpty() || roles.contains(filter_role))) { + QModelIndex source_parent = source_top_left.parent(); + + while (source_parent.isValid()) { + data_changed_list.emplace_back(source_parent, source_parent); + source_parent = source_parent.parent(); + } } - Mapping *m = it.value(); - // Figure out how the source changes affect us - QVector<int> source_rows_remove; - QVector<int> source_rows_insert; - QVector<int> source_rows_change; - QVector<int> source_rows_resort; - int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1); - for (int source_row = source_top_left.row(); source_row <= end; ++source_row) { - if (dynamic_sortfilter) { - if (m->proxy_rows.at(source_row) != -1) { - if (!q->filterAcceptsRow(source_row, source_parent)) { - // This source row no longer satisfies the filter, so it must be removed - source_rows_remove.append(source_row); - } else if (source_sort_column >= source_top_left.column() && source_sort_column <= source_bottom_right.column()) { - // This source row has changed in a way that may affect sorted order - source_rows_resort.append(source_row); + for (const QSortFilterProxyModelDataChanged &data_changed : data_changed_list) { + const QModelIndex &source_top_left = data_changed.topLeft; + const QModelIndex &source_bottom_right = data_changed.bottomRight; + const QModelIndex source_parent = source_top_left.parent(); + + IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); + if (it == source_index_mapping.constEnd()) { + // Don't care, since we don't have mapping for this index + continue; + } + Mapping *m = it.value(); + + // Figure out how the source changes affect us + QVector<int> source_rows_remove; + QVector<int> source_rows_insert; + QVector<int> source_rows_change; + QVector<int> source_rows_resort; + int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1); + for (int source_row = source_top_left.row(); source_row <= end; ++source_row) { + if (dynamic_sortfilter) { + if (m->proxy_rows.at(source_row) != -1) { + if (!filterAcceptsRowInternal(source_row, source_parent)) { + // This source row no longer satisfies the filter, so it must be removed + source_rows_remove.append(source_row); + } else if (source_sort_column >= source_top_left.column() && source_sort_column <= source_bottom_right.column()) { + // This source row has changed in a way that may affect sorted order + source_rows_resort.append(source_row); + } else { + // This row has simply changed, without affecting filtering nor sorting + source_rows_change.append(source_row); + } } else { - // This row has simply changed, without affecting filtering nor sorting - source_rows_change.append(source_row); + if (!itemsBeingRemoved.contains(source_parent, source_row) && filterAcceptsRowInternal(source_row, source_parent)) { + // This source row now satisfies the filter, so it must be added + source_rows_insert.append(source_row); + } } } else { - if (!itemsBeingRemoved.contains(source_parent, source_row) && q->filterAcceptsRow(source_row, source_parent)) { - // This source row now satisfies the filter, so it must be added - source_rows_insert.append(source_row); + if (m->proxy_rows.at(source_row) != -1) + source_rows_change.append(source_row); + } + } + + if (!source_rows_remove.isEmpty()) { + remove_source_items(m->proxy_rows, m->source_rows, + source_rows_remove, source_parent, Qt::Vertical); + QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove); + QVector<QModelIndex>::iterator childIt = m->mapped_children.end(); + while (childIt != m->mapped_children.begin()) { + --childIt; + const QModelIndex source_child_index = *childIt; + if (source_rows_remove_set.contains(source_child_index.row())) { + childIt = m->mapped_children.erase(childIt); + remove_from_mapping(source_child_index); } } - } else { - if (m->proxy_rows.at(source_row) != -1) - source_rows_change.append(source_row); } - } - if (!source_rows_remove.isEmpty()) { - remove_source_items(m->proxy_rows, m->source_rows, - source_rows_remove, source_parent, Qt::Vertical); - QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove); - QVector<QModelIndex>::iterator childIt = m->mapped_children.end(); - while (childIt != m->mapped_children.begin()) { - --childIt; - const QModelIndex source_child_index = *childIt; - if (source_rows_remove_set.contains(source_child_index.row())) { - childIt = m->mapped_children.erase(childIt); - remove_from_mapping(source_child_index); + if (!source_rows_resort.isEmpty()) { + if (needsReorder(source_rows_resort, source_parent)) { + // Re-sort the rows of this level + QList<QPersistentModelIndex> parents; + parents << q->mapFromSource(source_parent); + emit q->layoutAboutToBeChanged(parents, QAbstractItemModel::VerticalSortHint); + QModelIndexPairList source_indexes = store_persistent_indexes(); + remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort, + source_parent, Qt::Vertical, false); + sort_source_rows(source_rows_resort, source_parent); + insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort, + source_parent, Qt::Vertical, false); + update_persistent_indexes(source_indexes); + emit q->layoutChanged(parents, QAbstractItemModel::VerticalSortHint); } + // Make sure we also emit dataChanged for the rows + source_rows_change += source_rows_resort; } - } - if (!source_rows_resort.isEmpty()) { - // Re-sort the rows of this level - QList<QPersistentModelIndex> parents; - parents << q->mapFromSource(source_parent); - emit q->layoutAboutToBeChanged(parents, QAbstractItemModel::VerticalSortHint); - QModelIndexPairList source_indexes = store_persistent_indexes(); - remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort, - source_parent, Qt::Vertical, false); - sort_source_rows(source_rows_resort, source_parent); - insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort, - source_parent, Qt::Vertical, false); - update_persistent_indexes(source_indexes); - emit q->layoutChanged(parents, QAbstractItemModel::VerticalSortHint); - // Make sure we also emit dataChanged for the rows - source_rows_change += source_rows_resort; - } - - if (!source_rows_change.isEmpty()) { - // Find the proxy row range - int proxy_start_row; - int proxy_end_row; - proxy_item_range(m->proxy_rows, source_rows_change, - proxy_start_row, proxy_end_row); - // ### Find the proxy column range also - if (proxy_end_row >= 0) { - // the row was accepted, but some columns might still be filtered out - int source_left_column = source_top_left.column(); - while (source_left_column < source_bottom_right.column() - && m->proxy_columns.at(source_left_column) == -1) - ++source_left_column; - const QModelIndex proxy_top_left = create_index( - proxy_start_row, m->proxy_columns.at(source_left_column), it); - int source_right_column = source_bottom_right.column(); - while (source_right_column > source_top_left.column() - && m->proxy_columns.at(source_right_column) == -1) - --source_right_column; - const QModelIndex proxy_bottom_right = create_index( - proxy_end_row, m->proxy_columns.at(source_right_column), it); - emit q->dataChanged(proxy_top_left, proxy_bottom_right, roles); + if (!source_rows_change.isEmpty()) { + // Find the proxy row range + int proxy_start_row; + int proxy_end_row; + proxy_item_range(m->proxy_rows, source_rows_change, + proxy_start_row, proxy_end_row); + // ### Find the proxy column range also + if (proxy_end_row >= 0) { + // the row was accepted, but some columns might still be filtered out + int source_left_column = source_top_left.column(); + while (source_left_column < source_bottom_right.column() + && m->proxy_columns.at(source_left_column) == -1) + ++source_left_column; + const QModelIndex proxy_top_left = create_index( + proxy_start_row, m->proxy_columns.at(source_left_column), it); + int source_right_column = source_bottom_right.column(); + while (source_right_column > source_top_left.column() + && m->proxy_columns.at(source_right_column) == -1) + --source_right_column; + const QModelIndex proxy_bottom_right = create_index( + proxy_end_row, m->proxy_columns.at(source_right_column), it); + emit q->dataChanged(proxy_top_left, proxy_bottom_right, roles); + } } - } - if (!source_rows_insert.isEmpty()) { - sort_source_rows(source_rows_insert, source_parent); - insert_source_items(m->proxy_rows, m->source_rows, - source_rows_insert, source_parent, Qt::Vertical); + if (!source_rows_insert.isEmpty()) { + sort_source_rows(source_rows_insert, source_parent); + insert_source_items(m->proxy_rows, m->source_rows, + source_rows_insert, source_parent, Qt::Vertical); + } } } @@ -1386,18 +1477,60 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted( { Q_UNUSED(start); Q_UNUSED(end); + + const bool toplevel = !source_parent.isValid(); + const bool recursive_accepted = filter_recursive && !toplevel && filterAcceptsRowInternal(source_parent.row(), source_parent.parent()); //Force the creation of a mapping now, even if its empty. //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items - if (can_create_mapping(source_parent)) - create_mapping(source_parent); + if (!filter_recursive || toplevel || recursive_accepted) { + if (can_create_mapping(source_parent)) + create_mapping(source_parent); + if (filter_recursive) + complete_insert = true; + } else { + // The row could have been rejected or the parent might be not yet known... let's try to discover it + QModelIndex top_source_parent = source_parent; + QModelIndex parent = source_parent.parent(); + QModelIndex grandParent = parent.parent(); + + while (parent.isValid() && !filterAcceptsRowInternal(parent.row(), grandParent)) { + top_source_parent = parent; + parent = grandParent; + grandParent = parent.parent(); + } + + last_top_source = top_source_parent; + } } void QSortFilterProxyModelPrivate::_q_sourceRowsInserted( const QModelIndex &source_parent, int start, int end) { - source_items_inserted(source_parent, start, end, Qt::Vertical); - if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column. - sort(); // now it should succeed so we need to make sure to sort again + if (!filter_recursive || complete_insert) { + if (filter_recursive) + complete_insert = false; + source_items_inserted(source_parent, start, end, Qt::Vertical); + if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column. + sort(); // now it should succeed so we need to make sure to sort again + return; + } + + if (filter_recursive) { + bool accept = false; + + for (int row = start; row <= end; ++row) { + if (filterAcceptsRowInternal(row, source_parent)) { + accept = true; + break; + } + } + + if (!accept) // the new rows have no descendants that match the filter, filter them out. + return; + + // last_top_source should now become visible + _q_sourceDataChanged(last_top_source, last_top_source, QVector<int>()); + } } void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved( @@ -1413,6 +1546,27 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsRemoved( { itemsBeingRemoved = QRowsRemoval(); source_items_removed(source_parent, start, end, Qt::Vertical); + + if (filter_recursive) { + // Find out if removing this visible row means that some ascendant + // row can now be hidden. + // We go up until we find a row that should still be visible + // and then make QSFPM re-evaluate the last one we saw before that, to hide it. + + QModelIndex to_hide; + QModelIndex source_ascendant = source_parent; + + while (source_ascendant.isValid()) { + if (filterAcceptsRowInternal(source_ascendant.row(), source_ascendant.parent())) + break; + + to_hide = source_ascendant; + source_ascendant = source_ascendant.parent(); + } + + if (to_hide.isValid()) + _q_sourceDataChanged(to_hide, to_hide, QVector<int>()); + } } void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved( @@ -1685,7 +1839,9 @@ QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent) d->sort_localeaware = false; d->filter_column = 0; d->filter_role = Qt::DisplayRole; + d->filter_recursive = false; d->dynamic_sortfilter = true; + d->complete_insert = false; connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping())); } @@ -2506,6 +2662,32 @@ void QSortFilterProxyModel::setFilterRole(int role) } /*! + \since 5.9 + \property QSortFilterProxyModel::recursiveFiltering + \brief whether the filter to be applied recursively on children, and for + any matching child, its parents will be visible as well. + + The default value is false. + + \sa filterAcceptsRow() +*/ +bool QSortFilterProxyModel::recursiveFiltering() const +{ + Q_D(const QSortFilterProxyModel); + return d->filter_recursive; +} + +void QSortFilterProxyModel::setRecursiveFiltering(bool recursive) +{ + Q_D(QSortFilterProxyModel); + if (d->filter_recursive == recursive) + return; + d->filter_about_to_be_changed(); + d->filter_recursive = recursive; + d->filter_changed(); +} + +/*! \obsolete This function is obsolete. Use invalidate() instead. diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.h b/src/corelib/itemmodels/qsortfilterproxymodel.h index 06ff79ef5f..6f2e9806ed 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.h +++ b/src/corelib/itemmodels/qsortfilterproxymodel.h @@ -67,6 +67,7 @@ class Q_CORE_EXPORT QSortFilterProxyModel : public QAbstractProxyModel Q_PROPERTY(bool isSortLocaleAware READ isSortLocaleAware WRITE setSortLocaleAware) Q_PROPERTY(int sortRole READ sortRole WRITE setSortRole) Q_PROPERTY(int filterRole READ filterRole WRITE setFilterRole) + Q_PROPERTY(bool recursiveFiltering READ recursiveFiltering WRITE setRecursiveFiltering) public: explicit QSortFilterProxyModel(QObject *parent = Q_NULLPTR); @@ -107,6 +108,9 @@ public: int filterRole() const; void setFilterRole(int role); + bool recursiveFiltering() const; + void setRecursiveFiltering(bool recursive); + public Q_SLOTS: void setFilterRegExp(const QString &pattern); void setFilterWildcard(const QString &pattern); diff --git a/src/corelib/itemmodels/qstringlistmodel.cpp b/src/corelib/itemmodels/qstringlistmodel.cpp index 0f7472aa5a..da232cc142 100644 --- a/src/corelib/itemmodels/qstringlistmodel.cpp +++ b/src/corelib/itemmodels/qstringlistmodel.cpp @@ -131,7 +131,7 @@ int QStringListModel::rowCount(const QModelIndex &parent) const */ QModelIndex QStringListModel::sibling(int row, int column, const QModelIndex &idx) const { - if (!idx.isValid() || column != 0 || row >= lst.count()) + if (!idx.isValid() || column != 0 || row >= lst.count() || row < 0) return QModelIndex(); return createIndex(row, 0); diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h index 68d9bf180f..961148d9ec 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.h +++ b/src/corelib/kernel/qabstracteventdispatcher.h @@ -124,6 +124,8 @@ protected: QObject *parent); }; +Q_DECLARE_TYPEINFO(QAbstractEventDispatcher::TimerInfo, (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) ? Q_PRIMITIVE_TYPE : Q_RELOCATABLE_TYPE)); + QT_END_NAMESPACE #endif // QABSTRACTEVENTDISPATCHER_H diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index 231afb991c..a91c02f54e 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -42,7 +42,6 @@ #ifdef Q_OS_OSX #include <AppKit/NSText.h> -#include <Carbon/Carbon.h> #endif #include <qdebug.h> @@ -140,6 +139,7 @@ struct qtKey2CocoaKeySortLessThan } }; +static const int NSEscapeCharacter = 27; // not defined by Cocoa headers static const int NumEntries = 59; static const KeyPair entries[NumEntries] = { { NSEnterCharacter, Qt::Key_Enter }, @@ -148,7 +148,7 @@ static const KeyPair entries[NumEntries] = { { NSNewlineCharacter, Qt::Key_Return }, { NSCarriageReturnCharacter, Qt::Key_Return }, { NSBackTabCharacter, Qt::Key_Backtab }, - { kEscapeCharCode, Qt::Key_Escape }, + { NSEscapeCharacter, Qt::Key_Escape }, // Cocoa sends us delete when pressing backspace! // (NB when we reverse this list in qtKey2CocoaKey, there // will be two indices of Qt::Key_Backspace. But is seems to work diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h index 8f37aec6e2..c8771bfee5 100644 --- a/src/corelib/kernel/qcore_unix_p.h +++ b/src/corelib/kernel/qcore_unix_p.h @@ -103,6 +103,8 @@ struct sockaddr; QT_BEGIN_NAMESPACE +Q_DECLARE_TYPEINFO(pollfd, Q_PRIMITIVE_TYPE); + // Internal operator functions for timespecs inline timespec &normalizedTimespec(timespec &t) { diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index d728040343..bcf5b10baa 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -55,7 +55,6 @@ #include "QtCore/qlist.h" #include "private/qabstracteventdispatcher_p.h" #include "private/qcore_unix_p.h" -#include "private/qpodlist_p.h" #include "QtCore/qvarlengtharray.h" #include "private/qtimerinfo_unix_p.h" diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index 93bc477e7d..306c0845ef 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -406,7 +406,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative, "runPendingCppRunnablesOnAndroidThread", "()V"); - g_hideSplashScreenMethodID = env->GetStaticMethodID(jQtNative, "hideSplashScreen", "()V"); + g_hideSplashScreenMethodID = env->GetStaticMethodID(jQtNative, "hideSplashScreen", "(I)V"); g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative)); env->DeleteLocalRef(jQtNative); @@ -566,9 +566,9 @@ void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventList g_keyEventListeners()->listeners.removeOne(listener); } -void QtAndroidPrivate::hideSplashScreen(JNIEnv *env) +void QtAndroidPrivate::hideSplashScreen(JNIEnv *env, int duration) { - env->CallStaticVoidMethod(g_jNativeClass, g_hideSplashScreenMethodID); + env->CallStaticVoidMethod(g_jNativeClass, g_hideSplashScreenMethodID, duration); } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index 62f9358513..9fa47d5302 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -140,7 +140,7 @@ namespace QtAndroidPrivate Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener); Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener); - Q_CORE_EXPORT void hideSplashScreen(JNIEnv *env); + Q_CORE_EXPORT void hideSplashScreen(JNIEnv *env, int duration = 0); } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 3674ebc1a1..5e2e746bbc 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -462,7 +462,8 @@ public: WeakPointerToQObject = 0x40, TrackingPointerToQObject = 0x80, WasDeclaredAsMetaType = 0x100, - IsGadget = 0x200 + IsGadget = 0x200, + PointerToGadget = 0x400 }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) @@ -1388,6 +1389,19 @@ namespace QtPrivate enum { Value = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *) }; }; + template<typename T, typename Enable = void> + struct IsPointerToGadgetHelper { enum { Value = false }; }; + + template<typename T> + struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper> + { + using BaseType = T; + template <typename X> + static char checkType(void (X::*)()); + static void *checkType(void (T::*)()); + enum { Value = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *) }; + }; + template<typename T> char qt_getEnumMetaObject(const T&); @@ -1423,6 +1437,11 @@ namespace QtPrivate static inline const QMetaObject *value() { return &T::staticMetaObject; } }; template<typename T> + struct MetaObjectForType<T, typename QEnableIf<IsPointerToGadgetHelper<T>::Value>::Type> + { + static inline const QMetaObject *value() { return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject; } + }; + template<typename T> struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type > { static inline const QMetaObject *value() { return qt_getEnumMetaObject(T()); } @@ -1578,6 +1597,7 @@ namespace QtPrivate template <typename T, int = QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : QtPrivate::IsGadgetHelper<T>::Value ? QMetaType::IsGadget : + QtPrivate::IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget : QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0> struct QMetaTypeIdQObject { @@ -1631,6 +1651,7 @@ namespace QtPrivate { | (IsTrackingPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::TrackingPointerToQObject : 0) | (std::is_enum<T>::value ? QMetaType::IsEnumeration : 0) | (IsGadgetHelper<T>::Value ? QMetaType::IsGadget : 0) + | (IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget : 0) }; }; @@ -1798,6 +1819,30 @@ struct QMetaTypeIdQObject<T, QMetaType::IsGadget> }; template <typename T> +struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget> +{ + enum { + Defined = 1 + }; + + static int qt_metatype_id() + { + static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); + if (const int id = metatype_id.loadAcquire()) + return id; + const char * const cName = T::staticMetaObject.className(); + QByteArray typeName; + typeName.reserve(int(strlen(cName)) + 1); + typeName.append(cName).append('*'); + const int newId = qRegisterNormalizedMetaType<T*>( + typeName, + reinterpret_cast<T**>(quintptr(-1))); + metatype_id.storeRelease(newId); + return newId; + } +}; + +template <typename T> struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> { enum { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 1b05962c07..24ad9d140c 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -2339,7 +2339,7 @@ static void err_info_about_objects(const char * func, a thread different from this object's thread. Do not use this function in this type of scenario. - \sa senderSignalIndex(), QSignalMapper + \sa senderSignalIndex() */ QObject *QObject::sender() const diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index a7d7ef0889..2bdaffb465 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -243,6 +243,7 @@ public: QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; }; +Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE); /*! \internal diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp index a483717da5..d56965281e 100644 --- a/src/corelib/kernel/qsignalmapper.cpp +++ b/src/corelib/kernel/qsignalmapper.cpp @@ -58,10 +58,10 @@ public: }; - /*! \class QSignalMapper \inmodule QtCore + \obsolete \brief The QSignalMapper class bundles signals from identifiable senders. \ingroup objectmodel @@ -108,6 +108,12 @@ public: widget will emit a single \c clicked() signal whose argument is the text of the button the user clicked. + This class was mostly useful before lambda functions could be used as + slots. The example above can be rewritten simpler without QSignalMapper + by connecting to a lambda function. + + \snippet qsignalmapper/buttonwidget.cpp 3 + \sa QObject, QButtonGroup, QActionGroup */ diff --git a/src/corelib/kernel/qsignalmapper.h b/src/corelib/kernel/qsignalmapper.h index f960c7cabf..6c4cfa9627 100644 --- a/src/corelib/kernel/qsignalmapper.h +++ b/src/corelib/kernel/qsignalmapper.h @@ -42,6 +42,8 @@ #include <QtCore/qobject.h> +#if QT_DEPRECATED_SINCE(5, 10) + QT_BEGIN_NAMESPACE class QSignalMapperPrivate; @@ -51,7 +53,7 @@ class Q_CORE_EXPORT QSignalMapper : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QSignalMapper) public: - explicit QSignalMapper(QObject *parent = Q_NULLPTR); + QT_DEPRECATED explicit QSignalMapper(QObject *parent = nullptr); ~QSignalMapper(); void setMapping(QObject *sender, int id); @@ -82,4 +84,6 @@ private: QT_END_NAMESPACE +#endif + #endif // QSIGNALMAPPER_H diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index 5c0acce4c3..ed7ebb2ef5 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -655,7 +655,7 @@ void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data) } // Binary search in the icons or generic-icons list -QString QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime) +QLatin1String QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime) { const int iconsListOffset = cacheFile->getUint32(posListOffset); const int numIcons = cacheFile->getUint32(iconsListOffset); @@ -676,7 +676,7 @@ QString QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posListOffset return QLatin1String(cacheFile->getCharStar(iconOffset)); } } - return QString(); + return QLatin1String(); } void QMimeBinaryProvider::loadIcon(QMimeTypePrivate &data) @@ -684,7 +684,7 @@ void QMimeBinaryProvider::loadIcon(QMimeTypePrivate &data) checkCache(); const QByteArray inputMime = data.name.toLatin1(); for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const QString icon = iconForMime(cacheFile, PosIconsListOffset, inputMime); + const QLatin1String icon = iconForMime(cacheFile, PosIconsListOffset, inputMime); if (!icon.isEmpty()) { data.iconName = icon; return; @@ -697,7 +697,7 @@ void QMimeBinaryProvider::loadGenericIcon(QMimeTypePrivate &data) checkCache(); const QByteArray inputMime = data.name.toLatin1(); for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const QString icon = iconForMime(cacheFile, PosGenericIconsListOffset, inputMime); + const QLatin1String icon = iconForMime(cacheFile, PosGenericIconsListOffset, inputMime); if (!icon.isEmpty()) { data.genericIconName = icon; return; diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h index f410e62267..0be01d2fd0 100644 --- a/src/corelib/mimetypes/qmimeprovider_p.h +++ b/src/corelib/mimetypes/qmimeprovider_p.h @@ -116,7 +116,7 @@ private: void matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int offset, const QString &fileName); bool matchSuffixTree(QMimeGlobMatchResult &result, CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck); bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data); - QString iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime); + QLatin1String iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime); void loadMimeTypeList(); void checkCache(); diff --git a/src/corelib/mimetypes/qmimetypeparser.cpp b/src/corelib/mimetypes/qmimetypeparser.cpp index 20b4461b03..5ecd339908 100644 --- a/src/corelib/mimetypes/qmimetypeparser.cpp +++ b/src/corelib/mimetypes/qmimetypeparser.cpp @@ -49,7 +49,6 @@ #include <QtCore/QCoreApplication> #include <QtCore/QDebug> #include <QtCore/QDir> -#include <QtCore/QPair> #include <QtCore/QXmlStreamReader> #include <QtCore/QXmlStreamWriter> #include <QtCore/QStack> diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 21f1007d5b..05f9c68a7b 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -122,8 +122,8 @@ void QFactoryLoader::update() // // ### FIXME find a proper solution // - const bool isLoadingDebugAndReleaseCocoa = plugins.contains(QStringLiteral("libqcocoa_debug.dylib")) - && plugins.contains(QStringLiteral("libqcocoa.dylib")); + const bool isLoadingDebugAndReleaseCocoa = plugins.contains(QLatin1String("libqcocoa_debug.dylib")) + && plugins.contains(QLatin1String("libqcocoa.dylib")); #endif for (int j = 0; j < plugins.count(); ++j) { QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j)); @@ -131,10 +131,10 @@ void QFactoryLoader::update() #ifdef Q_OS_MAC if (isLoadingDebugAndReleaseCocoa) { #ifdef QT_DEBUG - if (fileName.contains(QStringLiteral("libqcocoa.dylib"))) + if (fileName.contains(QLatin1String("libqcocoa.dylib"))) continue; // Skip release plugin in debug mode #else - if (fileName.contains(QStringLiteral("libqcocoa_debug.dylib"))) + if (fileName.contains(QLatin1String("libqcocoa_debug.dylib"))) continue; // Skip debug plugin in release mode #endif } diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h index be9f632557..6c814ef854 100644 --- a/src/corelib/thread/qresultstore.h +++ b/src/corelib/thread/qresultstore.h @@ -196,6 +196,8 @@ public: } // namespace QtPrivate +Q_DECLARE_TYPEINFO(QtPrivate::ResultItem, Q_PRIMITIVE_TYPE); + #endif //Q_QDOC QT_END_NAMESPACE diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp index 8427b0e696..397d6203aa 100644 --- a/src/corelib/thread/qsemaphore.cpp +++ b/src/corelib/thread/qsemaphore.cpp @@ -94,7 +94,7 @@ QT_BEGIN_NAMESPACE seated (taking the available seats to 5, making the party of 10 people wait longer). - \sa QMutex, QWaitCondition, QThread, {Semaphores Example} + \sa QSemaphoreReleaser, QMutex, QWaitCondition, QThread, {Semaphores Example} */ class QSemaphorePrivate { @@ -152,7 +152,10 @@ void QSemaphore::acquire(int n) \snippet code/src_corelib_thread_qsemaphore.cpp 1 - \sa acquire(), available() + QSemaphoreReleaser is a \l{http://en.cppreference.com/w/cpp/language/raii}{RAII} + wrapper around this function. + + \sa acquire(), available(), QSemaphoreReleaser */ void QSemaphore::release(int n) { @@ -234,6 +237,152 @@ bool QSemaphore::tryAcquire(int n, int timeout) } +/*! + \class QSemaphoreReleaser + \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call + \since 5.10 + \ingroup thread + \inmodule QtCore + + \reentrant + + QSemaphoreReleaser can be used wherever you would otherwise use + QSemaphore::release(). Constructing a QSemaphoreReleaser defers the + release() call on the semaphore until the QSemaphoreReleaser is + destroyed (see + \l{http://en.cppreference.com/w/cpp/language/raii}{RAII pattern}). + + You can use this to reliably release a semaphore to avoid dead-lock + in the face of exceptions or early returns: + + \code + // ... do something that may throw or return early + sem.release(); + \endcode + + If an early return is taken or an exception is thrown before the + \c{sem.release()} call is reached, the semaphore is not released, + possibly preventing the thread waiting in the corresponding + \c{sem.acquire()} call from ever continuing execution. + + When using RAII instead: + + \code + const QSemaphoreReleaser releaser(sem); + // ... do something that may throw or early return + // implicitly calls sem.release() here and at every other return in between + \endcode + + this can no longer happen, because the compiler will make sure that + the QSemaphoreReleaser destructor is always called, and therefore + the semaphore is always released. + + QSemaphoreReleaser is move-enabled and can therefore be returned + from functions to transfer responsibility for releasing a semaphore + out of a function or a scope: + + \code + { // some scope + QSemaphoreReleaser releaser; // does nothing + // ... + if (someCondition) { + releaser = QSemaphoreReleaser(sem); + // ... + } + // ... + } // conditionally calls sem.release(), depending on someCondition + \endcode + + A QSemaphoreReleaser can be canceled by a call to cancel(). A canceled + semaphore releaser will no longer call QSemaphore::release() in its + destructor. + + \sa QMutexLocker +*/ + +/*! + \fn QSemaphoreReleaser::QSemaphoreReleaser() + + Default constructor. Creates a QSemaphoreReleaser that does nothing. +*/ + +/*! + \fn QSemaphoreReleaser::QSemaphoreReleaser(QSemaphore &sem, int n) + + Constructor. Stores the arguments and calls \a{sem}.release(\a{n}) + in the destructor. +*/ + +/*! + \fn QSemaphoreReleaser::QSemaphoreReleaser(QSemaphore *sem, int n) + + Constructor. Stores the arguments and calls \a{sem}->release(\a{n}) + in the destructor. +*/ + +/*! + \fn QSemaphoreReleaser::QSemaphoreReleaser(QSemaphoreReleaser &&other) + + Move constructor. Takes over responsibility to call QSemaphore::release() + from \a other, which in turn is canceled. + + \sa cancel() +*/ + +/*! + \fn QSemaphoreReleaser::operator=(QSemaphoreReleaser &&other) + + Move assignment operator. Takes over responsibility to call QSemaphore::release() + from \a other, which in turn is canceled. + + If this semaphore releaser had the responsibility to call some QSemaphore::release() + itself, it performs the call before taking over from \a other. + + \sa cancel() +*/ + +/*! + \fn QSemaphoreReleaser::~QSemaphoreReleaser() + + Unless canceled, calls QSemaphore::release() with the arguments provided + to the constructor, or by the last move assignment. +*/ + +/*! + \fn QSemaphoreReleaser::swap(QSemaphoreReleaser &other) + + Exchanges the responsibilites of \c{*this} and \a other. + + Unlike move assignment, neither of the two objects ever releases its + semaphore, if any, as a consequence of swapping. + + Therefore this function is very fast and never fails. +*/ + +/*! + \fn QSemaphoreReleaser::semaphore() const + + Returns a pointer to the QSemaphore object provided to the constructor, + or by the last move assignment, if any. Otherwise, returns \c nullptr. +*/ + +/*! + \fn QSemaphoreReleaser::cancel() + + Cancels this QSemaphoreReleaser such that the destructor will no longer + call \c{semaphore()->release()}. Returns the value of semaphore() + before this call. After this call, semaphore() will return \c nullptr. + + To enable again, assign a new QSemaphoreReleaser: + + \code + releaser.cancel(); // avoid releasing old semaphore() + releaser = QSemaphoreReleaser(sem, 42); + // now will call sem.release(42) when 'releaser' is destroyed + \endcode +*/ + + QT_END_NAMESPACE #endif // QT_NO_THREAD diff --git a/src/corelib/thread/qsemaphore.h b/src/corelib/thread/qsemaphore.h index adb9d73e50..a92740c8ce 100644 --- a/src/corelib/thread/qsemaphore.h +++ b/src/corelib/thread/qsemaphore.h @@ -69,6 +69,45 @@ private: QSemaphorePrivate *d; }; +class QSemaphoreReleaser +{ + QSemaphore *m_sem = nullptr; + int m_n; +public: + QSemaphoreReleaser() = default; + explicit QSemaphoreReleaser(QSemaphore &sem, int n = 1) Q_DECL_NOTHROW + : m_sem(&sem), m_n(n) {} + explicit QSemaphoreReleaser(QSemaphore *sem, int n = 1) Q_DECL_NOTHROW + : m_sem(sem), m_n(n) {} + QSemaphoreReleaser(QSemaphoreReleaser &&other) Q_DECL_NOTHROW + : m_sem(other.m_sem), m_n(other.m_n) + { other.m_sem = nullptr; } + QSemaphoreReleaser &operator=(QSemaphoreReleaser &&other) Q_DECL_NOTHROW + { QSemaphoreReleaser moved(std::move(other)); swap(moved); return *this; } + + ~QSemaphoreReleaser() + { + if (m_sem) + m_sem->release(m_n); + } + + void swap(QSemaphoreReleaser &other) Q_DECL_NOTHROW + { + qSwap(m_sem, other.m_sem); + qSwap(m_n, other.m_n); + } + + QSemaphore *semaphore() const Q_DECL_NOTHROW + { return m_sem; } + + QSemaphore *cancel() Q_DECL_NOTHROW + { + QSemaphore *old = m_sem; + m_sem = nullptr; + return old; + } +}; + #endif // QT_NO_THREAD QT_END_NAMESPACE diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 1d3293e85e..085adb1859 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -608,6 +608,24 @@ QT_BEGIN_NAMESPACE */ /*! + \fn QChar::QChar(char16_t ch) + \since 5.10 + + Constructs a QChar corresponding to the UTF-16 character \a ch. + + \note This constructor is not available on MSVC 2013. +*/ + +/*! + \fn QChar::QChar(wchar_t ch) + \since 5.10 + + Constructs a QChar corresponding to the wide character \a ch. + + \note This constructor is only available on Windows. +*/ + +/*! \fn QChar::QChar(char ch) Constructs a QChar corresponding to ASCII/Latin-1 character \a ch. diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index 81ef67d116..a1d31f6a68 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -86,6 +86,13 @@ public: Q_DECL_CONSTEXPR QChar(int rc) Q_DECL_NOTHROW : ucs(ushort(rc & 0xffff)) {} Q_DECL_CONSTEXPR QChar(SpecialCharacter s) Q_DECL_NOTHROW : ucs(ushort(s)) {} // implicit Q_DECL_CONSTEXPR QChar(QLatin1Char ch) Q_DECL_NOTHROW : ucs(ch.unicode()) {} // implicit +#if !defined(Q_OS_WIN) || defined(Q_COMPILER_UNICODE_STRINGS) + Q_DECL_CONSTEXPR QChar(char16_t ch) Q_DECL_NOTHROW : ucs(ushort(ch)) {} // implicit +#endif +#if defined(Q_OS_WIN) + Q_STATIC_ASSERT(sizeof(wchar_t) == sizeof(ushort)); + Q_DECL_CONSTEXPR QChar(wchar_t ch) Q_DECL_NOTHROW : ucs(ushort(ch)) {} // implicit +#endif #ifndef QT_NO_CAST_FROM_ASCII QT_ASCII_CAST_WARN Q_DECL_CONSTEXPR explicit QChar(char c) Q_DECL_NOTHROW : ucs(uchar(c)) { } diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 59952bd107..da534908d4 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -89,8 +89,9 @@ QT_BEGIN_INCLUDE_NAMESPACE #include "qlocale_data_p.h" QT_END_INCLUDE_NAMESPACE -QLocale::Language QLocalePrivate::codeToLanguage(const QChar *code, int len) Q_DECL_NOTHROW +QLocale::Language QLocalePrivate::codeToLanguage(QStringView code) Q_DECL_NOTHROW { + const auto len = code.size(); if (len != 2 && len != 3) return QLocale::C; ushort uc1 = code[0].toLower().unicode(); @@ -131,8 +132,9 @@ QLocale::Language QLocalePrivate::codeToLanguage(const QChar *code, int len) Q_D return QLocale::C; } -QLocale::Script QLocalePrivate::codeToScript(const QChar *code, int len) Q_DECL_NOTHROW +QLocale::Script QLocalePrivate::codeToScript(QStringView code) Q_DECL_NOTHROW { + const auto len = code.size(); if (len != 4) return QLocale::AnyScript; @@ -150,10 +152,12 @@ QLocale::Script QLocalePrivate::codeToScript(const QChar *code, int len) Q_DECL_ return QLocale::AnyScript; } -QLocale::Country QLocalePrivate::codeToCountry(const QChar *code, int len) Q_DECL_NOTHROW +QLocale::Country QLocalePrivate::codeToCountry(QStringView code) Q_DECL_NOTHROW { + const auto len = code.size(); if (len != 2 && len != 3) return QLocale::AnyCountry; + ushort uc1 = code[0].toUpper().unicode(); ushort uc2 = code[1].toUpper().unicode(); ushort uc3 = len > 2 ? code[2].toUpper().unicode() : 0; @@ -167,48 +171,35 @@ QLocale::Country QLocalePrivate::codeToCountry(const QChar *code, int len) Q_DEC return QLocale::AnyCountry; } -QString QLocalePrivate::languageToCode(QLocale::Language language) +QLatin1String QLocalePrivate::languageToCode(QLocale::Language language) { if (language == QLocale::AnyLanguage) - return QString(); + return QLatin1String(); if (language == QLocale::C) return QLatin1String("C"); const unsigned char *c = language_code_list + 3*(uint(language)); - QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized); + return QLatin1String(reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3); - code[0] = ushort(c[0]); - code[1] = ushort(c[1]); - if (c[2] != 0) - code[2] = ushort(c[2]); - - return code; } -QString QLocalePrivate::scriptToCode(QLocale::Script script) +QLatin1String QLocalePrivate::scriptToCode(QLocale::Script script) { if (script == QLocale::AnyScript || script > QLocale::LastScript) - return QString(); + return QLatin1String(); const unsigned char *c = script_code_list + 4*(uint(script)); - return QString::fromLatin1((const char *)c, 4); + return QLatin1String(reinterpret_cast<const char *>(c), 4); } -QString QLocalePrivate::countryToCode(QLocale::Country country) +QLatin1String QLocalePrivate::countryToCode(QLocale::Country country) { if (country == QLocale::AnyCountry) - return QString(); + return QLatin1String(); const unsigned char *c = country_code_list + 3*(uint(country)); - QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized); - - code[0] = ushort(c[0]); - code[1] = ushort(c[1]); - if (c[2] != 0) - code[2] = ushort(c[2]); - - return code; + return QLatin1String(reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3); } // http://www.unicode.org/reports/tr35/#Likely_Subtags diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index f7adb021b6..2b3c6a07cc 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -349,23 +349,16 @@ public: QByteArray bcp47Name(char separator = '-') const; - // ### QByteArray::fromRawData would be more optimal - inline QString languageCode() const { return QLocalePrivate::languageToCode(QLocale::Language(m_data->m_language_id)); } - inline QString scriptCode() const { return QLocalePrivate::scriptToCode(QLocale::Script(m_data->m_script_id)); } - inline QString countryCode() const { return QLocalePrivate::countryToCode(QLocale::Country(m_data->m_country_id)); } - - static QString languageToCode(QLocale::Language language); - static QString scriptToCode(QLocale::Script script); - static QString countryToCode(QLocale::Country country); - static QLocale::Language codeToLanguage(const QChar *code, int len) Q_DECL_NOTHROW; - static QLocale::Language codeToLanguage(const QString &code) Q_DECL_NOTHROW { return codeToLanguage(code.data(), code.size()); } - static QLocale::Language codeToLanguage(const QStringRef &code) Q_DECL_NOTHROW { return codeToLanguage(code.data(), code.size()); } - static QLocale::Script codeToScript(const QChar *code, int len) Q_DECL_NOTHROW; - static QLocale::Script codeToScript(const QString &code) Q_DECL_NOTHROW { return codeToScript(code.data(), code.size()); } - static QLocale::Script codeToScript(const QStringRef &code) Q_DECL_NOTHROW { return codeToScript(code.data(), code.size()); } - static QLocale::Country codeToCountry(const QChar *code, int len) Q_DECL_NOTHROW; - static QLocale::Country codeToCountry(const QString &code) Q_DECL_NOTHROW { return codeToCountry(code.data(), code.size()); } - static QLocale::Country codeToCountry(const QStringRef &code) Q_DECL_NOTHROW { return codeToCountry(code.data(), code.size()); } + inline QLatin1String languageCode() const { return QLocalePrivate::languageToCode(QLocale::Language(m_data->m_language_id)); } + inline QLatin1String scriptCode() const { return QLocalePrivate::scriptToCode(QLocale::Script(m_data->m_script_id)); } + inline QLatin1String countryCode() const { return QLocalePrivate::countryToCode(QLocale::Country(m_data->m_country_id)); } + + static QLatin1String languageToCode(QLocale::Language language); + static QLatin1String scriptToCode(QLocale::Script script); + static QLatin1String countryToCode(QLocale::Country country); + static QLocale::Language codeToLanguage(QStringView code) Q_DECL_NOTHROW; + static QLocale::Script codeToScript(QStringView code) Q_DECL_NOTHROW; + static QLocale::Country codeToCountry(QStringView code) Q_DECL_NOTHROW; static void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Script &script, QLocale::Country &cntry); diff --git a/src/corelib/tools/qpodlist_p.h b/src/corelib/tools/qpodlist_p.h deleted file mode 100644 index 95990e0bb6..0000000000 --- a/src/corelib/tools/qpodlist_p.h +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPODLIST_P_H -#define QPODLIST_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/private/qglobal_p.h> -#include <QtCore/qvarlengtharray.h> - -QT_BEGIN_NAMESPACE - - -template <typename T, int Prealloc> -class QPodList : public QVarLengthArray<T, Prealloc> -{ - using QVarLengthArray<T, Prealloc>::s; - using QVarLengthArray<T, Prealloc>::a; - using QVarLengthArray<T, Prealloc>::ptr; - using QVarLengthArray<T, Prealloc>::realloc; -public: - inline explicit QPodList(int size = 0) - : QVarLengthArray<T, Prealloc>(size) - {} - - inline void insert(int idx, const T &t) - { - const int sz = s++; - if (s == a) - realloc(s, s << 1); - ::memmove(ptr + idx + 1, ptr + idx, (sz - idx) * sizeof(T)); - ptr[idx] = t; - } - - inline void removeAll(const T &t) - { - int i = 0; - for (int j = 0; j < s; ++j) { - if (ptr[j] != t) - ptr[i++] = ptr[j]; - } - s = i; - } - - inline void removeAt(int idx) - { - Q_ASSERT(idx >= 0 && idx < s); - ::memmove(ptr + idx, ptr + idx + 1, (s - idx - 1) * sizeof(T)); - --s; - } - - inline T takeFirst() - { - Q_ASSERT(s > 0); - T tmp = ptr[0]; - removeAt(0); - return tmp; - } -}; - -QT_END_NAMESPACE - -#endif // QPODLIST_P_H diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index 325b71f267..558a456515 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -159,6 +159,8 @@ private: qint64 bufferSize; }; +Q_DECLARE_TYPEINFO(QRingBuffer, Q_MOVABLE_TYPE); + QT_END_NAMESPACE #endif // QRINGBUFFER_P_H diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index f6164e2297..59a8dd9d0c 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -261,7 +261,7 @@ # endif #endif -#if defined(__AES__) || defined(__PCLMUL__) +#if defined(__AES__) || defined(__PCLMUL__) || (defined(QT_COMPILER_SUPPORTS_AES) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) # include <wmmintrin.h> #endif diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 48f3d64c4a..68f5605598 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -165,8 +165,8 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen, namespace { template <uint MaxCount> struct UnrollTailLoop { - template <typename RetType, typename Functor1, typename Functor2> - static inline RetType exec(int count, RetType returnIfExited, Functor1 loopCheck, Functor2 returnIfFailed, int i = 0) + template <typename RetType, typename Functor1, typename Functor2, typename Number> + static inline RetType exec(Number count, RetType returnIfExited, Functor1 loopCheck, Functor2 returnIfFailed, Number i = 0) { /* equivalent to: * while (count--) { @@ -188,18 +188,18 @@ template <uint MaxCount> struct UnrollTailLoop return UnrollTailLoop<MaxCount - 1>::exec(count - 1, returnIfExited, loopCheck, returnIfFailed, i + 1); } - template <typename Functor> - static inline void exec(int count, Functor code) + template <typename Functor, typename Number> + static inline void exec(Number count, Functor code) { /* equivalent to: - * for (int i = 0; i < count; ++i) + * for (Number i = 0; i < count; ++i) * code(i); */ - exec(count, 0, [=](int i) -> bool { code(i); return false; }, [](int) { return 0; }); + exec(count, 0, [=](Number i) -> bool { code(i); return false; }, [](Number) { return 0; }); } }; -template <> template <typename RetType, typename Functor1, typename Functor2> -inline RetType UnrollTailLoop<0>::exec(int, RetType returnIfExited, Functor1, Functor2, int) +template <> template <typename RetType, typename Functor1, typename Functor2, typename Number> +inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1, Functor2, Number) { return returnIfExited; } @@ -379,9 +379,9 @@ static int ucstricmp(const ushort *a, const ushort *ae, const ushort *b, const u if (a == b) return (ae - be); if (a == 0) - return 1; + return be - b; if (b == 0) - return -1; + return a - ae; const ushort *e = ae; if (be - b < ae - a) @@ -410,13 +410,10 @@ static int ucstricmp(const ushort *a, const ushort *ae, const ushort *b, const u // Case-insensitive comparison between a Unicode string and a QLatin1String static int ucstricmp(const ushort *a, const ushort *ae, const uchar *b, const uchar *be) { - if (a == 0) { - if (b == 0) - return 0; - return 1; - } - if (b == 0) - return -1; + if (!a) + return be - b; + if (!b) + return a - ae; const ushort *e = ae; if (be - b < ae - a) @@ -445,7 +442,7 @@ extern "C" int qt_ucstrncmp_mips_dsp_asm(const ushort *a, #endif // Unicode case-sensitive compare two same-sized strings -static int ucstrncmp(const QChar *a, const QChar *b, int l) +static int ucstrncmp(const QChar *a, const QChar *b, size_t l) { #ifdef __OPTIMIZE_SIZE__ const QChar *end = a + l; @@ -458,6 +455,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l) return 0; #else #if defined(__mips_dsp) + Q_STATIC_ASSERT(sizeof(uint) == sizeof(size_t)); if (l >= 8) { return qt_ucstrncmp_mips_dsp_asm(reinterpret_cast<const ushort*>(a), reinterpret_cast<const ushort*>(b), @@ -484,13 +482,11 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l) - reinterpret_cast<const QChar *>(ptr + distance + idx)->unicode(); } } -# if defined(Q_COMPILER_LAMBDA) - const auto &lambda = [=](int i) -> int { + const auto lambda = [=](size_t i) -> int { return reinterpret_cast<const QChar *>(ptr)[i].unicode() - reinterpret_cast<const QChar *>(ptr + distance)[i].unicode(); }; return UnrollTailLoop<7>::exec(l, 0, lambda, lambda); -# endif #endif #if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64 if (l >= 8) { @@ -511,7 +507,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l) } l &= 7; } - const auto &lambda = [=](int i) -> int { + const auto lambda = [=](size_t i) -> int { return a[i].unicode() - b[i].unicode(); }; return UnrollTailLoop<7>::exec(l, 0, lambda, lambda); @@ -640,8 +636,8 @@ static int ucstrncmp(const QChar *a, const uchar *c, int l) uc += offset; c += offset; -# if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__) - const auto &lambda = [=](int i) { return uc[i] - ushort(c[i]); }; +# if !defined(__OPTIMIZE_SIZE__) + const auto lambda = [=](size_t i) { return uc[i] - ushort(c[i]); }; return UnrollTailLoop<MaxTailLength>::exec(e - uc, 0, lambda, lambda); # endif #endif @@ -672,7 +668,7 @@ static int ucstrnicmp(const ushort *a, const ushort *b, int l) return ucstricmp(a, a + l, b, b + l); } -static bool qMemEquals(const quint16 *a, const quint16 *b, int length) +static bool qMemEquals(const quint16 *a, const quint16 *b, size_t length) { if (a == b || !length) return true; @@ -8316,6 +8312,76 @@ QString &QString::setRawData(const QChar *unicode, int size) \sa QString, QLatin1Char, {QStringLiteral()}{QStringLiteral} */ +/*! + \typedef QLatin1String::value_type + \since 5.10 + + Alias for \c{const char}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QLatin1String::difference_type + \since 5.10 + + Alias for \c{int}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QLatin1String::size_type + \since 5.10 + + Alias for \c{int}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QLatin1String::reference + \since 5.10 + + Alias for \c{value_type &}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QLatin1String::iterator + \since 5.10 + + This typedef provides an STL-style const iterator for QLatin1String. + + QLatin1String does not support mutable iterators, so this is the same + as const_iterator. + + \sa const_iterator, reverse_iterator +*/ + +/*! + \typedef QLatin1String::const_iterator + \since 5.10 + + This typedef provides an STL-style const iterator for QLatin1String. + + \sa iterator, const_reverse_iterator +*/ + +/*! + \typedef QLatin1String::reverse_iterator + \since 5.10 + + This typedef provides an STL-style const reverse iterator for QLatin1String. + + QLatin1String does not support mutable reverse iterators, so this is the + same as const_reverse_iterator. + + \sa const_reverse_iterator, iterator +*/ + +/*! + \typedef QLatin1String::const_reverse_iterator + \since 5.10 + + This typedef provides an STL-style const reverse iterator for QLatin1String. + + \sa reverse_iterator, const_iterator +*/ + /*! \fn QLatin1String::QLatin1String() \since 5.6 @@ -8370,6 +8436,24 @@ QString &QString::setRawData(const QChar *unicode, int size) Returns the size of the Latin-1 string stored in this object. */ +/*! \fn bool QLatin1String::isNull() const + \since 5.10 + + Returns whether the Latin-1 string stored in this object is null + (\c{data() == nullptr}) or not. + + \sa isEmpty(), data() +*/ + +/*! \fn bool QLatin1String::isEmpty() const + \since 5.10 + + Returns whether the Latin-1 string stored in this object is empty + (\c{size() == 0}) or not. + + \sa isNull(), size() +*/ + /*! \fn QLatin1Char QLatin1String::at(int pos) const \since 5.8 @@ -8392,6 +8476,97 @@ QString &QString::setRawData(const QChar *unicode, int size) \sa at() */ +/*! + \fn QLatin1String::const_iterator QLatin1String::begin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in + the string. + + This function is provided for STL compatibility. + + \sa end(), cbegin(), rbegin(), data() +*/ + +/*! + \fn QLatin1String::const_iterator QLatin1String::cbegin() const + \since 5.10 + + Same as begin(). + + This function is provided for STL compatibility. + + \sa cend(), begin(), crbegin(), data() +*/ + +/*! + \fn QLatin1String::const_iterator QLatin1String::end() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + character after the last character in the list. + + This function is provided for STL compatibility. + + \sa begin(), cend(), rend() +*/ + +/*! \fn QLatin1String::const_iterator QLatin1String::cend() const + \since 5.10 + + Same as end(). + + This function is provided for STL compatibility. + + \sa cbegin(), end(), crend() +*/ + +/*! + \fn QLatin1String::const_reverse_iterator QLatin1String::rbegin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first + character in the string, in reverse order. + + This function is provided for STL compatibility. + + \sa rend(), crbegin(), begin() +*/ + +/*! + \fn QLatin1String::const_reverse_iterator QLatin1String::crbegin() const + \since 5.10 + + Same as rbegin(). + + This function is provided for STL compatibility. + + \sa crend(), rbegin(), cbegin() +*/ + +/*! + \fn QLatin1String::const_reverse_iterator QLatin1String::rend() const + \since 5.10 + + Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past + the last character in the string, in reverse order. + + This function is provided for STL compatibility. + + \sa rbegin(), crend(), end() +*/ + +/*! + \fn QLatin1String::const_reverse_iterator QLatin1String::crend() const + \since 5.10 + + Same as rend(). + + This function is provided for STL compatibility. + + \sa crbegin(), rend(), cend() +*/ + /*! \fn QLatin1String QLatin1String::mid(int start) const \since 5.8 diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 1bd436c387..2b7118e960 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -73,6 +73,10 @@ Q_FORWARD_DECLARE_CF_TYPE(CFString); Q_FORWARD_DECLARE_OBJC_CLASS(NSString); #endif +#ifndef QT_STRINGVIEW_LEVEL +# define QT_STRINGVIEW_LEVEL 1 +#endif + QT_BEGIN_NAMESPACE class QCharRef; @@ -83,6 +87,7 @@ class QString; class QStringList; class QTextCodec; class QStringRef; +class QStringView; template <typename T> class QVector; class QLatin1String @@ -97,17 +102,42 @@ public: Q_DECL_CONSTEXPR int size() const Q_DECL_NOTHROW { return m_size; } Q_DECL_CONSTEXPR const char *data() const Q_DECL_NOTHROW { return m_data; } - Q_DECL_CONSTEXPR QLatin1Char at(int i) const { return QLatin1Char(m_data[i]); } + Q_DECL_CONSTEXPR bool isNull() const Q_DECL_NOTHROW { return !data(); } + Q_DECL_CONSTEXPR bool isEmpty() const Q_DECL_NOTHROW { return !size(); } + + Q_DECL_CONSTEXPR QLatin1Char at(int i) const + { return Q_ASSERT(i >= 0), Q_ASSERT(i < size()), QLatin1Char(m_data[i]); } Q_DECL_CONSTEXPR QLatin1Char operator[](int i) const { return at(i); } + using value_type = const char; + using reference = value_type&; + using const_reference = reference; + using iterator = value_type*; + using const_iterator = iterator; + using difference_type = int; // violates Container concept requirements + using size_type = int; // violates Container concept requirements + + Q_DECL_CONSTEXPR const_iterator begin() const Q_DECL_NOTHROW { return data(); } + Q_DECL_CONSTEXPR const_iterator cbegin() const Q_DECL_NOTHROW { return data(); } + Q_DECL_CONSTEXPR const_iterator end() const Q_DECL_NOTHROW { return data() + size(); } + Q_DECL_CONSTEXPR const_iterator cend() const Q_DECL_NOTHROW { return data() + size(); } + + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = reverse_iterator; + + const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } + Q_DECL_CONSTEXPR QLatin1String mid(int pos) const - { return QLatin1String(m_data + pos, m_size - pos); } + { return Q_ASSERT(pos >= 0), Q_ASSERT(pos <= size()), QLatin1String(m_data + pos, m_size - pos); } Q_DECL_CONSTEXPR QLatin1String mid(int pos, int n) const - { return QLatin1String(m_data + pos, n); } + { return Q_ASSERT(pos >= 0), Q_ASSERT(n >= 0), Q_ASSERT(pos + n <= size()), QLatin1String(m_data + pos, n); } Q_DECL_CONSTEXPR QLatin1String left(int n) const - { return QLatin1String(m_data, n); } + { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QLatin1String(m_data, n); } Q_DECL_CONSTEXPR QLatin1String right(int n) const - { return QLatin1String(m_data + m_size - n, n); } + { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QLatin1String(m_data + m_size - n, n); } inline bool operator==(const QString &s) const Q_DECL_NOTHROW; inline bool operator!=(const QString &s) const Q_DECL_NOTHROW; @@ -652,7 +682,7 @@ public: {} template <int N> inline QString &operator=(const char (&ch)[N]) - { return (*this = fromLatin1(ch, N - 1)); } + { return (*this = fromUtf8(ch, N - 1)); } #endif #if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline QT_ASCII_CAST_WARN QString(const char *ch) @@ -850,6 +880,7 @@ private: friend class QCharRef; friend class QTextCodec; friend class QStringRef; + friend class QStringView; friend class QByteArray; friend class QCollator; friend struct QAbstractConcatenable; @@ -1549,6 +1580,10 @@ inline QStringRef::QStringRef(const QString *aString, int aPosition, int aSize) inline QStringRef::QStringRef(const QString *aString) :m_string(aString), m_position(0), m_size(aString?aString->size() : 0){} +QT_BEGIN_INCLUDE_NAMESPACE +#include <QtCore/qstringview.h> +QT_END_INCLUDE_NAMESPACE + // QStringRef <> QStringRef Q_CORE_EXPORT bool operator==(const QStringRef &s1, const QStringRef &s2) Q_DECL_NOTHROW; inline bool operator!=(const QStringRef &s1, const QStringRef &s2) Q_DECL_NOTHROW diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp index 75ff934f15..d65563f76d 100644 --- a/src/corelib/tools/qstringlist.cpp +++ b/src/corelib/tools/qstringlist.cpp @@ -299,6 +299,16 @@ QStringList QtPrivate::QStringList_filter(const QStringList *that, const QString return res; } +template<typename T> +static bool stringList_contains(const QStringList &stringList, const T &str, Qt::CaseSensitivity cs) +{ + for (const auto &string : stringList) { + if (string.size() == str.size() && string.compare(str, cs) == 0) + return true; + } + return false; +} + /*! \fn bool QStringList::contains(const QString &str, Qt::CaseSensitivity cs) const @@ -312,12 +322,24 @@ QStringList QtPrivate::QStringList_filter(const QStringList *that, const QString bool QtPrivate::QStringList_contains(const QStringList *that, const QString &str, Qt::CaseSensitivity cs) { - for (int i = 0; i < that->size(); ++i) { - const QString & string = that->at(i); - if (string.length() == str.length() && str.compare(string, cs) == 0) - return true; - } - return false; + return stringList_contains(*that, str, cs); +} + +/*! + \fn bool QStringList::contains(QLatin1String str, Qt::CaseSensitivity cs) const + \overload + \since 5.10 + + Returns \c true if the list contains the string \a str; otherwise + returns \c false. The search is case insensitive if \a cs is + Qt::CaseInsensitive; the search is case sensitive by default. + + \sa indexOf(), lastIndexOf(), QString::contains() + */ +bool QtPrivate::QStringList_contains(const QStringList *that, QLatin1String str, + Qt::CaseSensitivity cs) +{ + return stringList_contains(*that, str, cs); } #ifndef QT_NO_REGEXP diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h index 720d7d7419..b11856d9be 100644 --- a/src/corelib/tools/qstringlist.h +++ b/src/corelib/tools/qstringlist.h @@ -120,6 +120,7 @@ public: #endif inline bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + inline bool contains(QLatin1String str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; inline QStringList operator+(const QStringList &other) const { QStringList n = *this; n += other; return n; } @@ -165,6 +166,7 @@ namespace QtPrivate { Qt::CaseSensitivity cs); bool Q_CORE_EXPORT QStringList_contains(const QStringList *that, const QString &str, Qt::CaseSensitivity cs); + bool Q_CORE_EXPORT QStringList_contains(const QStringList *that, QLatin1String str, Qt::CaseSensitivity cs); void Q_CORE_EXPORT QStringList_replaceInStrings(QStringList *that, const QString &before, const QString &after, Qt::CaseSensitivity cs); @@ -222,6 +224,11 @@ inline bool QStringList::contains(const QString &str, Qt::CaseSensitivity cs) co return QtPrivate::QStringList_contains(this, str, cs); } +inline bool QStringList::contains(QLatin1String str, Qt::CaseSensitivity cs) const +{ + return QtPrivate::QStringList_contains(this, str, cs); +} + inline QStringList &QListSpecialMethods<QString>::replaceInStrings(const QString &before, const QString &after, Qt::CaseSensitivity cs) { QtPrivate::QStringList_replaceInStrings(self(), before, after, cs); diff --git a/src/corelib/tools/qstringview.cpp b/src/corelib/tools/qstringview.cpp new file mode 100644 index 0000000000..8504b941b3 --- /dev/null +++ b/src/corelib/tools/qstringview.cpp @@ -0,0 +1,533 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstringview.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QStringView + \inmodule QtCore + \since 5.10 + \brief The QStringView class provides a unified view on UTF-16 strings + \reentrant + \ingroup tools + \ingroup string-processing + + QStringView provides a read-only subset of the QString API. + + A string view explicitly stores a portion of a UTF-16 string it does + not own. It acts as an interface type to all kinds of UTF-16 string, + without the need to construct a QString first. + + The UTF-16 string may be represented as an array (or an array-compatible + data-structure such as QString, + std::basic_string, etc.) of \c QChar, \c ushort, \c char16_t (on compilers that + support C++11 Unicode strings) or (on platforms, such as Windows, + where it is a 16-bit type) \c wchar_t. + + QStringView is designed as an interface type; its main use-case is + as a function parameter type. When QStringViews are used as automatic + variables or data members, care must be taken to ensure that the referenced + string data (for example, owned by a QString) outlives the QStringView on all code paths, + lest the string view ends up referencing deleted data. + + When used as an interface type, QStringView allows a single function to accept + a wide variety of UTF-16 string data sources. One function accepting QStringView + thus replaces three function overloads (taking QString, QStringRef, and + \c{(const QChar*, int)}), while at the same time enabling even more string data + sources to be passed to the function, such as \c{u"Hello World"}, a \c char16_t + string literal. + + QStringViews should be passed by value, not by reference-to-const: + \code + void myfun1(QStringView sv); // preferred + void myfun2(const QStringView &sv); // compiles and works, but slower + \endcode + + If you want to give your users maximum freedom in what strings they can pass + to your function, accompany the QStringView overload with overloads for + + \list + \li \e QChar: this overload can delegate to the QStringView version: + \code + void fun(QChar ch) { fun(QStringView(&ch, 1)); } + \endcode + even though, for technical reasons, QStringView cannot provide a + QChar constructor by itself. + \li \e QString: if you store an unmodified copy of the string and thus would + like to take advantage of QString's implicit sharing. + \li QLatin1String: if you can implement the function without converting the + QLatin1String to UTF-16 first; users expect a function overloaded on + QLatin1String to perform strictly less memory allocations than the + semantically equivalent call of the QStringView version, involving + construction of a QString from the QLatin1String. + \endlist + + QStringView can also be used as the return value of a function. If you call a + function returning QStringView, take extra care to not keep the QStringView + around longer than the function promises to keep the referenced string data alive. + If in doubt, obtain a strong reference to the data by calling toString() to convert + the QStringView into a QString. + + QStringView is a \e{Literal Type}. + + \note We strongly discourage the use of QList<QStringView>, + because QList is a very inefficient container for QStringViews (it would heap-allocate + every element). Use QVector (or std::vector) to hold QStringViews instead. + + \sa QString, QStringRef +*/ + +/*! + \typedef QStringView::value_type + + Alias for \c{const QChar}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QStringView::difference_type + + Alias for \c{std::ptrdiff_t}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QStringView::size_type + + Alias for \c{std::ptrdiff_t}. Provided for compatibility with the STL. + + Unlike other Qt classes, QStringView uses \c ptrdiff_t as its \c size_type, to allow + accepting data from \c{std::basic_string} without truncation. The Qt API functions, + for example length(), return \c int, while the STL-compatible functions, for example + size(), return \c size_type. +*/ + +/*! + \typedef QStringView::reference + + Alias for \c{value_type &}. Provided for compatibility with the STL. + + QStringView does not support mutable references, so this is the same + as const_reference. +*/ + +/*! + \typedef QStringView::const_reference + + Alias for \c{value_type &}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QStringView::pointer + + Alias for \c{value_type *}. Provided for compatibility with the STL. + + QStringView does not support mutable pointers, so this is the same + as const_pointer. +*/ + +/*! + \typedef QStringView::const_pointer + + Alias for \c{value_type *}. Provided for compatibility with the STL. +*/ + +/*! + \typedef QStringView::iterator + + This typedef provides an STL-style const iterator for QStringView. + + QStringView does not support mutable iterators, so this is the same + as const_iterator. + + \sa const_iterator, reverse_iterator +*/ + +/*! + \typedef QStringView::const_iterator + + This typedef provides an STL-style const iterator for QStringView. + + \sa iterator, const_reverse_iterator +*/ + +/*! + \typedef QStringView::reverse_iterator + + This typedef provides an STL-style const reverse iterator for QStringView. + + QStringView does not support mutable reverse iterators, so this is the + same as const_reverse_iterator. + + \sa const_reverse_iterator, iterator +*/ + +/*! + \typedef QStringView::const_reverse_iterator + + This typedef provides an STL-style const reverse iterator for QStringView. + + \sa reverse_iterator, const_iterator +*/ + +/*! + \fn QStringView::QStringView() + + Constructs a null string view. + + \sa isNull() +*/ + +/*! + \fn QStringView::QStringView(std::nullptr_t) + + Constructs a null string view. + + \sa isNull() +*/ + +/*! + \fn QStringView::QStringView(QString::Null) + \internal + + Constructs a null string view. + + \sa isNull() +*/ + +/*! + \fn QStringView::QStringView(const Char *str, size_type len) + + Constructs a string view on \a str with length \a len. + + The range \c{[str,len)} must remain valid for the lifetime of this string view object. + + Passing \c nullptr as \a str is safe if \a len is 0, too, and results in a null string view. + + The behavior is undefined if \a len is negative or, when positive, if \a str is \c nullptr. + + This constructor only participates in overload resolution if \c Char is a compatible + character type. The compatible character types are: \c QChar, \c ushort, \c char16_t and + (on platforms, such as Windows, where it is a 16-bit type) \c wchar_t. +*/ + +/*! + \fn QStringView::QStringView(const Char *str) + + Constructs a string view on \a str. The length is determined + by scanning for the first \c{char16_t(0)}. + + \a str must remain valid for the lifetime of this string view object. + + Passing \c nullptr as \a str is safe and results in a null string view. + + This constructor only participates in overload resolution if \c Char is a compatible + character type. The compatible character types are: \c QChar, \c ushort, \c char16_t and + (on platforms, such as Windows, where it is a 16-bit type) \c wchar_t. +*/ + +/*! + \fn QStringView::QStringView(const QString &str) + + Constructs a string view on \a str. + + \c{str.data()} must remain valid for the lifetime of this string view object. + + The string view will be null if and only if \c{str.isNull()}. +*/ + +/*! + \fn QStringView::QStringView(const QStringRef &str) + + Constructs a string view on \a str. + + \c{str.data()} must remain valid for the lifetime of this string view object. + + The string view will be null if and only if \c{str.isNull()}. +*/ + +/*! + \fn QStringView::QStringView(const StdBasicString &str) + + Constructs a string view on \a str. The length is taken from \c{str.size()}. + + \c{str.data()} must remain valid for the lifetime of this string view object. + + This constructor only participates in overload resolution if \c StdBasicString is an + instantiation of \c std::basic_string with a compatible character type. The + compatible character types are: \c QChar, \c ushort, \c char16_t and + (on platforms, such as Windows, where it is a 16-bit type) \c wchar_t. + + The string view will be empty if and only if \c{str.empty()}. It is unspecified + whether this constructor can result in a null string view (\c{str.data()} would + have to return \c nullptr for this). + + \sa isNull(), isEmpty() +*/ + +/*! + \fn QString QStringView::toString() const + + Returns a deep copy of this string view's data as a QString. + + The return value will be the null QString if and only if this string view is null. + + \warning QStringView can store strings with more than 2\sup{30} characters + while QString cannot. Calling this function on a string view for which size() + returns a value greater than \c{INT_MAX / 2} constitutes undefined behavior. +*/ + +/*! + \fn const QChar *QStringView::data() const + + Returns a const pointer to the first character in the string. + + \sa begin(), end() +*/ + +/*! + \fn QStringView::const_iterator QStringView::begin() const + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in + the string. + + This function is provided for STL compatibility. + + \sa end(), cbegin(), rbegin(), data() +*/ + +/*! + \fn QStringView::const_iterator QStringView::cbegin() const + + Same as begin(). + + This function is provided for STL compatibility. + + \sa cend(), begin(), crbegin(), data() +*/ + +/*! + \fn QStringView::const_iterator QStringView::end() const + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + character after the last character in the list. + + This function is provided for STL compatibility. + + \sa begin(), cend(), rend() +*/ + +/*! \fn QStringView::const_iterator QStringView::cend() const + + Same as end(). + + This function is provided for STL compatibility. + + \sa cbegin(), end(), crend() +*/ + +/*! + \fn QStringView::const_reverse_iterator QStringView::rbegin() const + + Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first + character in the string, in reverse order. + + This function is provided for STL compatibility. + + \sa rend(), crbegin(), begin() +*/ + +/*! + \fn QStringView::const_reverse_iterator QStringView::crbegin() const + + Same as rbegin(). + + This function is provided for STL compatibility. + + \sa crend(), rbegin(), cbegin() +*/ + +/*! + \fn QStringView::const_reverse_iterator QStringView::rend() const + + Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past + the last character in the string, in reverse order. + + This function is provided for STL compatibility. + + \sa rbegin(), crend(), end() +*/ + +/*! + \fn QStringView::const_reverse_iterator QStringView::crend() const + + Same as rend(). + + This function is provided for STL compatibility. + + \sa crbegin(), rend(), cend() +*/ + +/*! + \fn bool QStringView::empty() const + + Returns whether this string view is empty - that is, whether \c{size() == 0}. + + This function is provided for STL compatibility. + + \sa isEmpty(), isNull(), size(), length() +*/ + +/*! + \fn bool QStringView::isEmpty() const + + Returns whether this string view is empty - that is, whether \c{size() == 0}. + + This function is provided for compatibility with other Qt containers. + + \sa empty(), isNull(), size(), length() +*/ + +/*! + \fn bool QStringView::isNull() const + + Returns whether this string view is null - that is, whether \c{data() == nullptr}. + + This functions is provided for compatibility with other Qt containers. + + \sa empty(), isEmpty(), size(), length() +*/ + +/*! + \fn QStringView::size_type QStringView::size() const + + Returns the size of this string view, in UTF-16 code points (that is, + surrogate pairs count as two for the purposes of this function, the same + as in QString and QStringRef). + + \sa empty(), isEmpty(), isNull(), length() +*/ + +/*! + \fn int QStringView::length() const + + Same as size(), except returns the result as an \c int. + + This function is provided for compatibility with other Qt containers. + + \warning QStringView can represent strings with more than 2\sup{31} characters. + Calling this function on a string view for which size() returns a value greater + than \c{INT_MAX} constitutes undefined behavior. + + \sa empty(), isEmpty(), isNull(), size() +*/ + +/*! + \fn QChar QStringView::operator[](size_type n) const + + Returns the character at position \a n in this string view. + + The behavior is undefined if \a n is negative or not less than size(). + + \sa at(), front(), back() +*/ + +/*! + \fn QChar QStringView::at(size_type n) const + + Returns the character at position \a n in this string view. + + The behavior is undefined if \a n is negative or not less than size(). + + \sa operator[](), front(), back() +*/ + +/*! + \fn QChar QStringView::front() const + + Returns the first character in the string. Same as first(). + + This function is provided for STL compatibility. + + \warning Calling this function on an empty string view constitutes + undefined behavior. + + \sa back(), first(), last() +*/ + +/*! + \fn QChar QStringView::back() const + + Returns the last character in the string. Same as last(). + + This function is provided for STL compatibility. + + \warning Calling this function on an empty string view constitutes + undefined behavior. + + \sa front(), first(), last() +*/ + +/*! + \fn QChar QStringView::first() const + + Returns the first character in the string. Same as front(). + + This function is provided for compatibility with other Qt containers. + + \warning Calling this function on an empty string view constitutes + undefined behavior. + + \sa front(), back(), last() +*/ + +/*! + \fn QChar QStringView::last() const + + Returns the last character in the string. Same as back(). + + This function is provided for compatibility with other Qt containers. + + \warning Calling this function on an empty string view constitutes + undefined behavior. + + \sa back(), front(), first() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qstringview.h b/src/corelib/tools/qstringview.h new file mode 100644 index 0000000000..5384e73039 --- /dev/null +++ b/src/corelib/tools/qstringview.h @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTRING_H +# include <QtCore/qstring.h> +#endif + +#ifndef QSTRINGVIEW_H +#define QSTRINGVIEW_H + +#include <string> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_UNICODE_LITERAL +# ifndef QT_UNICODE_LITERAL +# error "If you change QStringLiteral, please change QStringViewLiteral, too" +# endif +# define QStringViewLiteral(str) QStringView(QT_UNICODE_LITERAL(str), sizeof(str) - 1) +#endif + +namespace QtPrivate { +template <typename Char> +struct IsCompatibleCharTypeHelper + : std::integral_constant<bool, + std::is_same<Char, QChar>::value || + std::is_same<Char, ushort>::value || +#if !defined(Q_OS_WIN) || defined(Q_COMPILER_UNICODE_STRINGS) + std::is_same<Char, char16_t>::value || +#endif + (std::is_same<Char, wchar_t>::value && sizeof(wchar_t) == sizeof(QChar))> {}; +template <typename Char> +struct IsCompatibleCharType + : IsCompatibleCharTypeHelper<typename std::remove_cv<typename std::remove_reference<Char>::type>::type> {}; + +template <typename T> +struct IsCompatibleStdBasicStringHelper : std::false_type {}; +template <typename Char, typename...Args> +struct IsCompatibleStdBasicStringHelper<std::basic_string<Char, Args...> > + : IsCompatibleCharType<Char> {}; + +template <typename T> +struct IsCompatibleStdBasicString + : IsCompatibleStdBasicStringHelper< + typename std::remove_cv<typename std::remove_reference<T>::type>::type + > {}; + +} // namespace QtPrivate + +class QStringView +{ +#if defined(Q_OS_WIN) && !defined(Q_COMPILER_UNICODE_STRINGS) + typedef wchar_t storage_type; +#else + typedef char16_t storage_type; +#endif +public: + typedef const QChar value_type; + typedef std::ptrdiff_t difference_type; + typedef QIntegerForSizeof<size_t>::Signed size_type; + typedef value_type &reference; + typedef value_type &const_reference; + typedef value_type *pointer; + typedef value_type *const_pointer; + + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + +private: + template <typename Char> + using if_compatible_char = typename std::enable_if<QtPrivate::IsCompatibleCharType<Char>::value, bool>::type; + + template <typename T> + using if_compatible_string = typename std::enable_if<QtPrivate::IsCompatibleStdBasicString<T>::value, bool>::type; + + template <typename Char> + static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelper(const Char *str) Q_DECL_NOTHROW + { + size_type result = 0; + while (*str++) + ++result; + return result; + } + static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelper(const QChar *str) Q_DECL_NOTHROW + { + size_type result = 0; + while (!str++->isNull()) + ++result; + return result; + } + + template <typename Char> + static const storage_type *castHelper(const Char *str) Q_DECL_NOTHROW + { return reinterpret_cast<const storage_type*>(str); } + static Q_DECL_CONSTEXPR const storage_type *castHelper(const storage_type *str) Q_DECL_NOTHROW + { return str; } + + // prevent + // T t; QStringView sv(t), T \in {QChar, QLatin1String, QByteArray, const char*} + // from compiling as QStringView sv(QString(t)): + QStringView(QChar) = delete; + QStringView(QLatin1String) = delete; + QStringView(const QByteArray &) = delete; + QStringView(const char *) = delete; + +#ifdef Q_OS_WIN + // prevent QStringView(Char), Char compatible, from compiling due to: + // https://connect.microsoft.com/VisualStudio/feedback/details/2256407/c-two-user-defined-conversions-incorrectly-accepted-in-implicit-conversion-sequence + template <typename Char, if_compatible_char<Char> = true> + QStringView(Char) = delete; +#endif +public: + Q_DECL_CONSTEXPR QStringView() Q_DECL_NOTHROW + : m_size(0), m_data(nullptr) {} + Q_DECL_CONSTEXPR QStringView(std::nullptr_t) Q_DECL_NOTHROW + : QStringView() {} +#if QT_DEPRECATED_SINCE(5, 9) + Q_DECL_CONSTEXPR QStringView(QString::Null) Q_DECL_NOTHROW + : QStringView() {} +#endif + + template <typename Char, if_compatible_char<Char> = true> + Q_DECL_CONSTEXPR QStringView(const Char *str, size_type len) + : m_size((Q_ASSERT(len >= 0), Q_ASSERT(str || !len), len)), + m_data(castHelper(str)) {} + + template <typename Char, if_compatible_char<Char> = true> + Q_DECL_CONSTEXPR QStringView(const Char *str) + : QStringView(str, str ? lengthHelper(str) : 0) {} + + QStringView(const QString &str) Q_DECL_NOTHROW + : QStringView(str.isNull() ? nullptr : str.data(), size_type(str.size())) {} + QStringView(const QStringRef &str) Q_DECL_NOTHROW + : QStringView(str.isNull() ? nullptr : str.data(), size_type(str.size())) {} + + template <typename StdBasicString, if_compatible_string<StdBasicString> = true> + QStringView(const StdBasicString &str) Q_DECL_NOTHROW + : QStringView(str.data(), size_type(str.size())) {} + + QString toString() const { return Q_ASSERT(size() == length()), QString(data(), length()); } + + Q_DECL_CONSTEXPR size_type size() const Q_DECL_NOTHROW { return m_size; } + const_pointer data() const Q_DECL_NOTHROW { return reinterpret_cast<const_pointer>(m_data); } + Q_DECL_CONSTEXPR const storage_type *utf16() const Q_DECL_NOTHROW { return m_data; } + + Q_DECL_CONSTEXPR QChar operator[](size_type n) const + { return Q_ASSERT(n >= 0), Q_ASSERT(n < size()), QChar(m_data[n]); } + + // + // QString API + // + + Q_DECL_CONSTEXPR QChar at(size_type n) const { return (*this)[n]; } + + // + // STL compatibility API: + // + const_iterator begin() const Q_DECL_NOTHROW { return data(); } + const_iterator end() const Q_DECL_NOTHROW { return data() + size(); } + const_iterator cbegin() const Q_DECL_NOTHROW { return begin(); } + const_iterator cend() const Q_DECL_NOTHROW { return end(); } + const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } + const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return rbegin(); } + const_reverse_iterator crend() const Q_DECL_NOTHROW { return rend(); } + + Q_DECL_CONSTEXPR bool empty() const Q_DECL_NOTHROW { return size() == 0; } + Q_DECL_CONSTEXPR QChar front() const { return Q_ASSERT(!empty()), QChar(m_data[0]); } + Q_DECL_CONSTEXPR QChar back() const { return Q_ASSERT(!empty()), QChar(m_data[m_size - 1]); } + + // + // Qt compatibility API: + // + Q_DECL_CONSTEXPR bool isNull() const Q_DECL_NOTHROW { return !m_data; } + Q_DECL_CONSTEXPR bool isEmpty() const Q_DECL_NOTHROW { return empty(); } + Q_DECL_CONSTEXPR int length() const /* not nothrow! */ + { return Q_ASSERT(int(size()) == size()), int(size()); } + Q_DECL_CONSTEXPR QChar first() const { return front(); } + Q_DECL_CONSTEXPR QChar last() const { return back(); } +private: + size_type m_size; + const storage_type *m_data; +}; +Q_DECLARE_TYPEINFO(QStringView, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +#endif /* QSTRINGVIEW_H */ diff --git a/src/corelib/tools/qtimezoneprivate_icu.cpp b/src/corelib/tools/qtimezoneprivate_icu.cpp index 887486f567..a07b2593b9 100644 --- a/src/corelib/tools/qtimezoneprivate_icu.cpp +++ b/src/corelib/tools/qtimezoneprivate_icu.cpp @@ -477,9 +477,10 @@ QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds() const QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds(QLocale::Country country) const { - QByteArray regionCode = QLocalePrivate::countryToCode(country).toUtf8(); + const QLatin1String regionCode = QLocalePrivate::countryToCode(country); + const QByteArray regionCodeUtf8 = QString(regionCode).toUtf8(); UErrorCode status = U_ZERO_ERROR; - UEnumeration *uenum = ucal_openCountryTimeZones(regionCode, &status); + UEnumeration *uenum = ucal_openCountryTimeZones(regionCodeUtf8.data(), &status); QList<QByteArray> result; if (U_SUCCESS(status)) result = uenumToIdList(uenum); diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp index 16dfaefb74..c6d59be3d8 100644 --- a/src/corelib/tools/qtimezoneprivate_win.cpp +++ b/src/corelib/tools/qtimezoneprivate_win.cpp @@ -386,7 +386,7 @@ static QLocale::Country userCountry() const GEOID id = GetUserGeoID(GEOCLASS_NATION); wchar_t code[3]; const int size = GetGeoInfo(id, GEO_ISO2, code, 3, 0); - return (size == 3) ? QLocalePrivate::codeToCountry(reinterpret_cast<const QChar*>(code), size) + return (size == 3) ? QLocalePrivate::codeToCountry(QStringView(code, size)) : QLocale::AnyCountry; } diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index d99eebd4b9..9879d55967 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -56,9 +56,6 @@ QT_BEGIN_NAMESPACE -template<class T, int Prealloc> -class QPodList; - // Prealloc = 256 by default, specified in qcontainerfwd.h template<class T, int Prealloc> class QVarLengthArray @@ -236,7 +233,6 @@ public: inline const T &back() const { return last(); } private: - friend class QPodList<T, Prealloc>; void realloc(int size, int alloc); int a; // capacity diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index b93ec824ed..8dd3550617 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -39,7 +39,6 @@ HEADERS += \ tools/qmargins.h \ tools/qmessageauthenticationcode.h \ tools/qcontiguouscache.h \ - tools/qpodlist_p.h \ tools/qpair.h \ tools/qpoint.h \ tools/qqueue.h \ @@ -63,6 +62,7 @@ HEADERS += \ tools/qstringiterator_p.h \ tools/qstringlist.h \ tools/qstringmatcher.h \ + tools/qstringview.h \ tools/qtextboundaryfinder.h \ tools/qtimeline.h \ tools/qtools_p.h \ @@ -107,6 +107,7 @@ SOURCES += \ tools/qstring.cpp \ tools/qstringbuilder.cpp \ tools/qstringlist.cpp \ + tools/qstringview.cpp \ tools/qtextboundaryfinder.cpp \ tools/qtimeline.cpp \ tools/qunicodetools.cpp \ |