summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qlocale.cpp17
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp5
-rw-r--r--src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp16
-rw-r--r--src/corelib/doc/snippets/qstring/main.cpp6
-rw-r--r--src/corelib/doc/snippets/signalmapper/filereader.cpp117
-rw-r--r--src/corelib/doc/src/objectmodel/signalsandslots.qdoc22
-rw-r--r--src/corelib/global/qglobal.cpp22
-rw-r--r--src/corelib/global/qglobal.h21
-rw-r--r--src/corelib/global/qlogging.cpp28
-rw-r--r--src/corelib/global/qnamespace.h1
-rw-r--r--src/corelib/global/qnamespace.qdoc5
-rw-r--r--src/corelib/global/qtypeinfo.h10
-rw-r--r--src/corelib/io/qabstractfileengine.cpp13
-rw-r--r--src/corelib/io/qabstractfileengine_p.h1
-rw-r--r--src/corelib/io/qdatastream.cpp1
-rw-r--r--src/corelib/io/qdatastream.h5
-rw-r--r--src/corelib/io/qdebug.cpp15
-rw-r--r--src/corelib/io/qdebug.h3
-rw-r--r--src/corelib/io/qfile.cpp45
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp18
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp52
-rw-r--r--src/corelib/io/qfsfileengine.cpp13
-rw-r--r--src/corelib/io/qfsfileengine_p.h1
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp113
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp9
-rw-r--r--src/corelib/io/qprocess.cpp71
-rw-r--r--src/corelib/io/qprocess.h1
-rw-r--r--src/corelib/io/qprocess_p.h5
-rw-r--r--src/corelib/io/qprocess_unix.cpp105
-rw-r--r--src/corelib/io/qprocess_win.cpp41
-rw-r--r--src/corelib/io/qresource.cpp50
-rw-r--r--src/corelib/io/qsettings.cpp2
-rw-r--r--src/corelib/io/qsettings_p.h2
-rw-r--r--src/corelib/io/qtemporaryfile_p.h2
-rw-r--r--src/corelib/io/qtldurl.cpp42
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.cpp376
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.h4
-rw-r--r--src/corelib/itemmodels/qstringlistmodel.cpp2
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.h2
-rw-r--r--src/corelib/kernel/qcore_mac.cpp10
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm4
-rw-r--r--src/corelib/kernel/qcore_mac_p.h41
-rw-r--r--src/corelib/kernel/qcore_unix_p.h2
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix_p.h1
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp6
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h2
-rw-r--r--src/corelib/kernel/qmath.h2
-rw-r--r--src/corelib/kernel/qmath.qdoc19
-rw-r--r--src/corelib/kernel/qmetaobject.cpp83
-rw-r--r--src/corelib/kernel/qmetatype.h47
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/kernel/qobject_impl.h78
-rw-r--r--src/corelib/kernel/qobject_p.h1
-rw-r--r--src/corelib/kernel/qobjectdefs.h89
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h94
-rw-r--r--src/corelib/kernel/qsignalmapper.cpp8
-rw-r--r--src/corelib/kernel/qsignalmapper.h6
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp8
-rw-r--r--src/corelib/mimetypes/qmimeprovider_p.h2
-rw-r--r--src/corelib/mimetypes/qmimetypeparser.cpp1
-rw-r--r--src/corelib/plugin/qfactoryloader.cpp8
-rw-r--r--src/corelib/thread/qresultstore.h2
-rw-r--r--src/corelib/thread/qsemaphore.cpp153
-rw-r--r--src/corelib/thread/qsemaphore.h39
-rw-r--r--src/corelib/tools/qchar.cpp18
-rw-r--r--src/corelib/tools/qchar.h7
-rw-r--r--src/corelib/tools/qdatetimeparser.cpp84
-rw-r--r--src/corelib/tools/qdatetimeparser_p.h2
-rw-r--r--src/corelib/tools/qhash.cpp44
-rw-r--r--src/corelib/tools/qhashfunctions.h8
-rw-r--r--src/corelib/tools/qlocale.cpp275
-rw-r--r--src/corelib/tools/qlocale.h11
-rw-r--r--src/corelib/tools/qlocale_p.h41
-rw-r--r--src/corelib/tools/qpodlist_p.h109
-rw-r--r--src/corelib/tools/qringbuffer_p.h2
-rw-r--r--src/corelib/tools/qsimd_p.h2
-rw-r--r--src/corelib/tools/qstring.cpp579
-rw-r--r--src/corelib/tools/qstring.h91
-rw-r--r--src/corelib/tools/qstringiterator.qdoc8
-rw-r--r--src/corelib/tools/qstringiterator_p.h10
-rw-r--r--src/corelib/tools/qstringlist.cpp34
-rw-r--r--src/corelib/tools/qstringlist.h7
-rw-r--r--src/corelib/tools/qstringview.cpp621
-rw-r--r--src/corelib/tools/qstringview.h269
-rw-r--r--src/corelib/tools/qtimezoneprivate_icu.cpp5
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp2
-rw-r--r--src/corelib/tools/qvarlengtharray.h4
-rw-r--r--src/corelib/tools/tools.pri3
88 files changed, 3092 insertions, 1116 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qlocale.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qlocale.cpp
index 3794049f97..aed14c379f 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qlocale.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qlocale.cpp
@@ -103,3 +103,20 @@ d = german.toDouble( "1234.56", &ok ); // ok == false
d = german.toDouble( "1.234", &ok ); // ok == true, d == 1234.0
//! [3]
+
+//! [3-qstringview]
+bool ok;
+double d;
+
+QLocale c(QLocale::C);
+d = c.toDouble(u"1234.56", &ok); // ok == true, d == 1234.56
+d = c.toDouble(u"1,234.56", &ok); // ok == true, d == 1234.56
+d = c.toDouble(u"1234,56", &ok); // ok == false
+
+QLocale german(QLocale::German);
+d = german.toDouble(u"1234,56", &ok); // ok == true, d == 1234.56
+d = german.toDouble(u"1.234,56", &ok); // ok == true, d == 1234.56
+d = german.toDouble(u"1234.56", &ok); // ok == false
+
+d = german.toDouble(u"1.234", &ok); // ok == true, d == 1234.0
+//! [3-qstringview]
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp
index 1fcb7b9945..7a2b4812ef 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp
@@ -58,7 +58,7 @@ int main()
{
//! [0]
QString string(QStringLiteral("a string"));
-QStringIterator i(string);
+QStringIterator i(string); // implicitly converted to QStringView
//! [0]
//! [1]
@@ -71,8 +71,7 @@ while (i.hasNext())
{
//! [2]
-QString string(QStringLiteral("𝄞 is the G clef"));
-QStringIterator i(string);
+QStringIterator i(u"𝄞 is the G clef");
qDebug() << hex << i.next(); // will print 1d11e (U+1D11E, MUSICAL SYMBOL G CLEF)
qDebug() << hex << i.next(); // will print 20 (U+0020, SPACE)
qDebug() << hex << i.next(); // will print 69 (U+0069, LATIN SMALL LETTER I)
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/qstring/main.cpp b/src/corelib/doc/snippets/qstring/main.cpp
index 41ee5a9cef..dd65fad4e3 100644
--- a/src/corelib/doc/snippets/qstring/main.cpp
+++ b/src/corelib/doc/snippets/qstring/main.cpp
@@ -321,6 +321,12 @@ void Widget::compareSensitiveFunction()
int y = QString::compare("auto", "Car", Qt::CaseSensitive); // y > 0
int z = QString::compare("auto", "Car", Qt::CaseInsensitive); // z < 0
//! [16]
+
+ //! [qCompareStrings-QSV-QSV]
+ int x = qCompareStrings(u"aUtO", u"AuTo", Qt::CaseInsensitive); // x == 0
+ int y = qCompareStrings(u"auto", u"Car", Qt::CaseSensitive); // y > 0
+ int z = qCompareStrings(u"auto", u"Car", Qt::CaseInsensitive); // z < 0
+ //! [qCompareStrings-QSV-QSV]
}
void Widget::containsFunction()
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..4ff27f14a8 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -774,6 +774,21 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
*/
/*!
+ \typedef qssize_t
+ \relates <QtGlobal>
+ \since 5.10
+
+ Integral type providing Posix' \c ssize_t for all platforms.
+
+ This type is guaranteed to be the same size as a \c size_t on all
+ platforms supported by Qt.
+
+ Note that qssize_t is signed. Use \c size_t for unsigned values.
+
+ \sa qptrdiff
+*/
+
+/*!
\enum QtMsgType
\relates <QtGlobal>
@@ -4419,8 +4434,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..3dfbf2fb2d 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -451,6 +451,7 @@ typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Unsigned qregisteruint;
typedef QIntegerForSizeof<void*>::Unsigned quintptr;
typedef QIntegerForSizeof<void*>::Signed qptrdiff;
typedef qptrdiff qintptr;
+using qssize_t = QIntegerForSizeof<std::size_t>::Signed;
/* moc compats (signals/slots) */
#ifndef QT_MOC_COMPAT
@@ -612,6 +613,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 +717,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 +734,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..c19cb92715 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;
@@ -953,7 +956,9 @@ bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
qWarning("QFile::open: File access not specified");
return false;
}
- if (d->openExternalFile(mode, fh, handleFlags)) {
+
+ // QIODevice provides the buffering, so request unbuffered file engines
+ if (d->openExternalFile(mode | Unbuffered, fh, handleFlags)) {
QIODevice::open(mode);
if (!(mode & Append) && !isSequential()) {
qint64 pos = (qint64)QT_FTELL(fh);
@@ -1009,7 +1014,9 @@ bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
qWarning("QFile::open: File access not specified");
return false;
}
- if (d->openExternalFile(mode, fd, handleFlags)) {
+
+ // QIODevice provides the buffering, so request unbuffered file engines
+ if (d->openExternalFile(mode | Unbuffered, fd, handleFlags)) {
QIODevice::open(mode);
if (!(mode & Append) && !isSequential()) {
qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR);
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..e5f7e5b418 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -195,6 +195,9 @@ void QFSFileEngine::setFileName(const QString &file)
*/
bool QFSFileEngine::open(QIODevice::OpenMode openMode)
{
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
+
Q_D(QFSFileEngine);
if (d->fileEntry.isEmpty()) {
qWarning("QFSFileEngine::open: No file name specified");
@@ -230,6 +233,9 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh)
bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHandleFlags handleFlags)
{
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
+
Q_D(QFSFileEngine);
// Append implies WriteOnly.
@@ -255,6 +261,9 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHand
*/
bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
{
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
+
Q_Q(QFSFileEngine);
this->fh = fh;
fd = -1;
@@ -860,9 +869,9 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
/*! \fn bool QFSFileEngine::copy(const QString &copyName)
- 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..51938d6967 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -65,46 +65,6 @@ QT_BEGIN_NAMESPACE
/*!
\internal
- Returns the stdlib open string corresponding to a QIODevice::OpenMode.
-*/
-static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry,
- QFileSystemMetaData &metaData)
-{
- QByteArray mode;
- if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) {
- mode = "rb";
- if (flags & QIODevice::WriteOnly) {
- metaData.clearFlags(QFileSystemMetaData::FileType);
- if (!fileEntry.isEmpty()
- && QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::FileType)
- && metaData.isFile()) {
- mode += '+';
- } else {
- mode = "wb+";
- }
- }
- } else if (flags & QIODevice::WriteOnly) {
- mode = "wb";
- if (flags & QIODevice::ReadOnly)
- mode += '+';
- }
- if (flags & QIODevice::Append) {
- mode = "ab";
- if (flags & QIODevice::ReadOnly)
- mode += '+';
- }
-
-#if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207
- // must be glibc >= 2.7
- mode += 'e';
-#endif
-
- return mode;
-}
-
-/*!
- \internal
-
Returns the stdio open flags corresponding to a QIODevice::OpenMode.
*/
static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
@@ -130,17 +90,6 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
return oflags;
}
-/*!
- \internal
-
- Sets the file descriptor to close on exec. That is, the file
- descriptor is not inherited by child processes.
-*/
-static inline bool setCloseOnExec(int fd)
-{
- return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1;
-}
-
static inline QString msgOpenDirectory()
{
const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory");
@@ -158,6 +107,8 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
{
Q_Q(QFSFileEngine);
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
if (openMode & QIODevice::Unbuffered) {
int flags = openModeToOpenFlags(openMode);
@@ -199,49 +150,6 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
}
fh = 0;
- } else {
- QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData);
-
- // Try to open the file in buffered mode.
- do {
- fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData());
- } while (!fh && errno == EINTR);
-
- // On failure, return and report the error.
- if (!fh) {
- q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(int(errno)));
- return false;
- }
-
- if (!(openMode & QIODevice::WriteOnly)) {
- // we don't need this check if we tried to open for writing because then
- // we had received EISDIR anyway.
- if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData)
- && metaData.isDirectory()) {
- q->setError(QFile::OpenError, msgOpenDirectory());
- fclose(fh);
- return false;
- }
- }
-
- setCloseOnExec(fileno(fh)); // ignore failure
-
- // Seek to the end when in Append mode.
- if (openMode & QIODevice::Append) {
- int ret;
- do {
- ret = QT_FSEEK(fh, 0, SEEK_END);
- } while (ret == -1 && errno == EINTR);
-
- if (ret == -1) {
- q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(int(errno)));
- return false;
- }
- }
-
- fd = -1;
}
closeFileHandle = true;
@@ -793,6 +701,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/qprocess.cpp b/src/corelib/io/qprocess.cpp
index c0ec35ff32..a3343423db 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -2112,6 +2112,46 @@ void QProcess::start(OpenMode mode)
}
/*!
+ \since 5.10
+
+ Starts the program set by setProgram() with arguments set by setArguments()
+ in a new process, and detaches from it. Returns \c true on success;
+ otherwise returns \c false. If the calling process exits, the
+ detached process will continue to run unaffected.
+
+ \b{Unix:} The started process will run in its own session and act
+ like a daemon.
+
+ The process will be started in the directory set by setWorkingDirectory().
+ If workingDirectory() is empty, the working directory is inherited
+ from the calling process.
+
+ \note On QNX, this may cause all application threads to
+ temporarily freeze.
+
+ If the function is successful then *\a pid is set to the process
+ identifier of the started process.
+
+ \sa start()
+ \sa startDetached(const QString &program, const QStringList &arguments,
+ const QString &workingDirectory, qint64 *pid)
+ \sa startDetached(const QString &command)
+*/
+bool QProcess::startDetached(qint64 *pid)
+{
+ Q_D(QProcess);
+ if (d->processState != NotRunning) {
+ qWarning("QProcess::startDetached: Process is already running");
+ return false;
+ }
+ if (d->program.isEmpty()) {
+ d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
+ return false;
+ }
+ return d->startDetached(pid);
+}
+
+/*!
Starts the program set by setProgram() with arguments set by setArguments().
The OpenMode is set to \a mode.
@@ -2445,6 +2485,8 @@ int QProcess::execute(const QString &command)
}
/*!
+ \overload startDetached()
+
Starts the program \a program with the arguments \a arguments in a
new process, and detaches from it. Returns \c true on success;
otherwise returns \c false. If the calling process exits, the
@@ -2452,16 +2494,10 @@ int QProcess::execute(const QString &command)
Argument handling is identical to the respective start() overload.
- \b{Unix:} The started process will run in its own session and act
- like a daemon.
-
The process will be started in the directory \a workingDirectory.
If \a workingDirectory is empty, the working directory is inherited
from the calling process.
- \note On QNX, this may cause all application threads to
- temporarily freeze.
-
If the function is successful then *\a pid is set to the process
identifier of the started process.
@@ -2472,10 +2508,11 @@ bool QProcess::startDetached(const QString &program,
const QString &workingDirectory,
qint64 *pid)
{
- return QProcessPrivate::startDetached(program,
- arguments,
- workingDirectory,
- pid);
+ QProcess process;
+ process.setProgram(program);
+ process.setArguments(arguments);
+ process.setWorkingDirectory(workingDirectory);
+ return process.startDetached(pid);
}
/*!
@@ -2484,11 +2521,14 @@ bool QProcess::startDetached(const QString &program,
bool QProcess::startDetached(const QString &program,
const QStringList &arguments)
{
- return QProcessPrivate::startDetached(program, arguments);
+ QProcess process;
+ process.setProgram(program);
+ process.setArguments(arguments);
+ return process.startDetached();
}
/*!
- \overload
+ \overload startDetached()
Starts the command \a command in a new process, and detaches from it.
Returns \c true on success; otherwise returns \c false.
@@ -2506,9 +2546,10 @@ bool QProcess::startDetached(const QString &command)
if (args.isEmpty())
return false;
- const QString prog = args.takeFirst();
-
- return QProcessPrivate::startDetached(prog, args);
+ QProcess process;
+ process.setProgram(args.takeFirst());
+ process.setArguments(args);
+ return process.startDetached();
}
QT_BEGIN_INCLUDE_NAMESPACE
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 19157bdd02..c8aef2f0b1 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -163,6 +163,7 @@ public:
void start(const QString &command, OpenMode mode = ReadWrite);
#endif
void start(OpenMode mode = ReadWrite);
+ bool startDetached(qint64 *pid = nullptr);
bool open(OpenMode mode = ReadWrite) Q_DECL_OVERRIDE;
QString program() const;
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index 6e0630eb66..80ac631290 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -353,7 +353,7 @@ public:
void start(QIODevice::OpenMode mode);
void startProcess();
#if defined(Q_OS_UNIX)
- void execChild(const char *workingDirectory, char **path, char **argv, char **envp);
+ void execChild(const char *workingDirectory, char **argv, char **envp);
#endif
bool processStarted(QString *errorMessage = Q_NULLPTR);
void terminateProcess();
@@ -368,8 +368,7 @@ public:
qint64 pipeWriterBytesToWrite() const;
#endif
- static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(),
- qint64 *pid = 0);
+ bool startDetached(qint64 *pPid);
int exitCode;
QProcess::ExitStatus exitStatus;
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 795229419c..e72773d7a4 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -87,6 +87,7 @@ QT_END_NAMESPACE
#include "qprocess.h"
#include "qprocess_p.h"
+#include "qstandardpaths.h"
#include "private/qcore_unix_p.h"
#ifdef Q_OS_MAC
@@ -420,8 +421,16 @@ void QProcessPrivate::startProcess()
#endif
// Add the program name to the argument list.
- char *dupProgramName = ::strdup(encodedProgramName.constData());
- argv[0] = dupProgramName;
+ argv[0] = nullptr;
+ if (!program.contains(QLatin1Char('/'))) {
+ const QString &exeFilePath = QStandardPaths::findExecutable(program);
+ if (!exeFilePath.isEmpty()) {
+ const QByteArray &tmp = QFile::encodeName(exeFilePath);
+ argv[0] = ::strdup(tmp.constData());
+ }
+ }
+ if (!argv[0])
+ argv[0] = ::strdup(encodedProgramName.constData());
// Add every argument to the list
for (int i = 0; i < arguments.count(); ++i)
@@ -443,29 +452,6 @@ void QProcessPrivate::startProcess()
workingDirPtr = encodedWorkingDirectory.constData();
}
- // If the program does not specify a path, generate a list of possible
- // locations for the binary using the PATH environment variable.
- char **path = 0;
- int pathc = 0;
- if (!program.contains(QLatin1Char('/'))) {
- const QString pathEnv = QString::fromLocal8Bit(qgetenv("PATH"));
- if (!pathEnv.isEmpty()) {
- QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
- if (!pathEntries.isEmpty()) {
- pathc = pathEntries.size();
- path = new char *[pathc + 1];
- path[pathc] = 0;
-
- for (int k = 0; k < pathEntries.size(); ++k) {
- QByteArray tmp = QFile::encodeName(pathEntries.at(k));
- if (!tmp.endsWith('/')) tmp += '/';
- tmp += encodedProgramName;
- path[k] = ::strdup(tmp.constData());
- }
- }
- }
- }
-
// Start the process manager, and fork off the child process.
pid_t childPid;
forkfd = ::forkfd(FFD_CLOEXEC, &childPid);
@@ -473,16 +459,12 @@ void QProcessPrivate::startProcess()
if (forkfd != FFD_CHILD_PROCESS) {
// Parent process.
// Clean up duplicated memory.
- free(dupProgramName);
- for (int i = 1; i <= arguments.count(); ++i)
+ for (int i = 0; i <= arguments.count(); ++i)
free(argv[i]);
for (int i = 0; i < envc; ++i)
free(envp[i]);
- for (int i = 0; i < pathc; ++i)
- free(path[i]);
delete [] argv;
delete [] envp;
- delete [] path;
}
// On QNX, if spawnChild failed, childPid will be -1 but forkfd is still 0.
@@ -503,7 +485,7 @@ void QProcessPrivate::startProcess()
// Start the child.
if (forkfd == FFD_CHILD_PROCESS) {
- execChild(workingDirPtr, path, argv, envp);
+ execChild(workingDirPtr, argv, envp);
::_exit(-1);
}
@@ -544,7 +526,7 @@ void QProcessPrivate::startProcess()
}
}
-void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp)
+void QProcessPrivate::execChild(const char *workingDir, char **argv, char **envp)
{
::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
@@ -567,7 +549,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
}
}
- // make sure this fd is closed if execvp() succeeds
+ // make sure this fd is closed if execv() succeeds
qt_safe_close(childStartedPipe[0]);
// enter the working directory
@@ -582,25 +564,13 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
// execute the process
if (!envp) {
- qt_safe_execvp(argv[0], argv);
- callthatfailed = "execvp: ";
+ qt_safe_execv(argv[0], argv);
+ callthatfailed = "execv: ";
} else {
- if (path) {
- char **arg = path;
- while (*arg) {
- argv[0] = *arg;
-#if defined (QPROCESS_DEBUG)
- fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);
-#endif
- qt_safe_execve(argv[0], argv, envp);
- ++arg;
- }
- } else {
#if defined (QPROCESS_DEBUG)
- fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
+ fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
#endif
- qt_safe_execve(argv[0], argv, envp);
- }
+ qt_safe_execve(argv[0], argv, envp);
callthatfailed = "execve: ";
}
@@ -925,7 +895,7 @@ bool QProcessPrivate::waitForDeadChild()
return true;
}
-bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
+bool QProcessPrivate::startDetached(qint64 *pid)
{
QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory);
@@ -967,23 +937,28 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
argv[arguments.size() + 1] = 0;
+ // Duplicate the environment.
+ int envc = 0;
+ char **envp = nullptr;
+ if (environment.d.constData()) {
+ QProcessEnvironmentPrivate::MutexLocker locker(environment.d);
+ envp = _q_dupEnvironment(environment.d.constData()->hash, &envc);
+ }
+
+ QByteArray tmp;
if (!program.contains(QLatin1Char('/'))) {
- const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
- if (!path.isEmpty()) {
- QStringList pathEntries = path.split(QLatin1Char(':'));
- for (int k = 0; k < pathEntries.size(); ++k) {
- QByteArray tmp = QFile::encodeName(pathEntries.at(k));
- if (!tmp.endsWith('/')) tmp += '/';
- tmp += QFile::encodeName(program);
- argv[0] = tmp.data();
- qt_safe_execv(argv[0], argv);
- }
- }
- } else {
- QByteArray tmp = QFile::encodeName(program);
- argv[0] = tmp.data();
- qt_safe_execv(argv[0], argv);
+ const QString &exeFilePath = QStandardPaths::findExecutable(program);
+ if (!exeFilePath.isEmpty())
+ tmp = QFile::encodeName(exeFilePath);
}
+ if (tmp.isEmpty())
+ tmp = QFile::encodeName(program);
+ argv[0] = tmp.data();
+
+ if (envp)
+ qt_safe_execve(argv[0], argv, envp);
+ else
+ qt_safe_execv(argv[0], argv);
struct sigaction noaction;
memset(&noaction, 0, sizeof(noaction));
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 329d1842f0..cca910bcc0 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -358,7 +358,8 @@ void QProcessPrivate::closeChannel(Channel *channel)
destroyPipe(channel->pipe);
}
-static QString qt_create_commandline(const QString &program, const QStringList &arguments)
+static QString qt_create_commandline(const QString &program, const QStringList &arguments,
+ const QString &nativeArguments)
{
QString args;
if (!program.isEmpty()) {
@@ -387,6 +388,13 @@ static QString qt_create_commandline(const QString &program, const QStringList &
}
args += QLatin1Char(' ') + tmp;
}
+
+ if (!nativeArguments.isEmpty()) {
+ if (!args.isEmpty())
+ args += QLatin1Char(' ');
+ args += nativeArguments;
+ }
+
return args;
}
@@ -472,15 +480,10 @@ void QProcessPrivate::startProcess()
!openChannel(stderrChannel))
return;
- QString args = qt_create_commandline(program, arguments);
+ const QString args = qt_create_commandline(program, arguments, nativeArguments);
QByteArray envlist;
if (environment.d.constData())
envlist = qt_create_environment(environment.d.constData()->hash);
- if (!nativeArguments.isEmpty()) {
- if (!args.isEmpty())
- args += QLatin1Char(' ');
- args += nativeArguments;
- }
#if defined QPROCESS_DEBUG
qDebug("Creating process");
@@ -826,6 +829,7 @@ bool QProcessPrivate::writeToStdin()
// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails
// with ERROR_ELEVATION_REQUIRED.
static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments,
+ const QString &nativeArguments,
const QString &workingDir, qint64 *pid)
{
typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *);
@@ -836,7 +840,8 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList &
if (!shellExecuteEx)
return false;
- const QString args = qt_create_commandline(QString(), arguments); // needs arguments only
+ const QString args = qt_create_commandline(QString(), // needs arguments only
+ arguments, nativeArguments);
SHELLEXECUTEINFOW shellExecuteExInfo;
memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW));
shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
@@ -859,14 +864,21 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList &
return true;
}
-bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid)
+bool QProcessPrivate::startDetached(qint64 *pid)
{
static const DWORD errorElevationRequired = 740;
- QString args = qt_create_commandline(program, arguments);
+ QString args = qt_create_commandline(program, arguments, nativeArguments);
bool success = false;
PROCESS_INFORMATION pinfo;
+ void *envPtr = nullptr;
+ QByteArray envlist;
+ if (environment.d.constData()) {
+ envlist = qt_create_environment(environment.d.constData()->hash);
+ envPtr = envlist.data();
+ }
+
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
@@ -875,8 +887,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
success = CreateProcess(0, (wchar_t*)args.utf16(),
- 0, 0, FALSE, dwCreationFlags, 0,
- workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(),
+ 0, 0, FALSE, dwCreationFlags, envPtr,
+ workingDirectory.isEmpty() ? 0 : (wchar_t*)workingDirectory.utf16(),
&startupInfo, &pinfo);
if (success) {
@@ -885,7 +897,10 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
if (pid)
*pid = pinfo.dwProcessId;
} else if (GetLastError() == errorElevationRequired) {
- success = startDetachedUacPrompt(program, arguments, workingDir, pid);
+ if (envPtr)
+ qWarning("QProcess: custom environment will be ignored for detached elevated process.");
+ success = startDetachedUacPrompt(program, arguments, nativeArguments,
+ workingDirectory, pid);
}
return success;
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index 32639759e4..984ed23812 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -66,10 +66,9 @@ QT_BEGIN_NAMESPACE
class QStringSplitter
{
public:
- QStringSplitter(const QString &s)
- : m_string(s), m_data(m_string.constData()), m_len(s.length()), m_pos(0)
+ explicit QStringSplitter(QStringView sv)
+ : m_data(sv.data()), m_len(sv.size())
{
- m_splitChar = QLatin1Char('/');
}
inline bool hasNext() {
@@ -78,18 +77,17 @@ public:
return m_pos < m_len;
}
- inline QStringRef next() {
+ inline QStringView next() {
int start = m_pos;
while (m_pos < m_len && m_data[m_pos] != m_splitChar)
++m_pos;
- return QStringRef(&m_string, start, m_pos - start);
+ return QStringView(m_data + start, m_pos - start);
}
- QString m_string;
const QChar *m_data;
- QChar m_splitChar;
- int m_len;
- int m_pos;
+ qssize_t m_len;
+ qssize_t m_pos = 0;
+ QChar m_splitChar = QLatin1Char('/');
};
@@ -678,7 +676,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
QStringSplitter splitter(path);
while (child_count && splitter.hasNext()) {
- QStringRef segment = splitter.next();
+ QStringView segment = splitter.next();
#ifdef DEBUG_RESOURCE_MATCH
qDebug() << " CHILDREN" << segment;
@@ -835,24 +833,24 @@ QStringList QResourceRoot::children(int node) const
bool QResourceRoot::mappingRootSubdir(const QString &path, QString *match) const
{
const QString root = mappingRoot();
- if(!root.isEmpty()) {
- const QVector<QStringRef> root_segments = root.splitRef(QLatin1Char('/'), QString::SkipEmptyParts),
- path_segments = path.splitRef(QLatin1Char('/'), QString::SkipEmptyParts);
- if(path_segments.size() <= root_segments.size()) {
- int matched = 0;
- for(int i = 0; i < path_segments.size(); ++i) {
- if(root_segments[i] != path_segments[i])
- break;
- ++matched;
- }
- if(matched == path_segments.size()) {
- if(match && root_segments.size() > matched)
- *match = root_segments.at(matched).toString();
- return true;
- }
+ if (root.isEmpty())
+ return false;
+
+ QStringSplitter rootIt(root);
+ QStringSplitter pathIt(path);
+ while (rootIt.hasNext()) {
+ if (pathIt.hasNext()) {
+ if (rootIt.next() != pathIt.next()) // mismatch
+ return false;
+ } else {
+ // end of path, but not of root:
+ if (match)
+ *match = rootIt.next().toString();
+ return true;
}
}
- return false;
+ // end of root
+ return !pathIt.hasNext();
}
Q_CORE_EXPORT bool qRegisterResourceData(int version, const unsigned char *tree,
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/io/qtldurl.cpp b/src/corelib/io/qtldurl.cpp
index 96543bbbfd..a934d19fa2 100644
--- a/src/corelib/io/qtldurl.cpp
+++ b/src/corelib/io/qtldurl.cpp
@@ -50,9 +50,21 @@
QT_BEGIN_NAMESPACE
-static bool containsTLDEntry(const QStringRef &entry)
+enum TLDMatchType {
+ ExactMatch,
+ SuffixMatch,
+ ExceptionMatch,
+};
+
+static bool containsTLDEntry(QStringView entry, TLDMatchType match)
{
- int index = qt_hash(entry) % tldCount;
+ const QStringView matchSymbols[] = {
+ QStringViewLiteral(""),
+ QStringViewLiteral("*"),
+ QStringViewLiteral("!"),
+ };
+ const auto symbol = matchSymbols[match];
+ int index = qt_hash(entry, qt_hash(symbol)) % tldCount;
// select the right chunk from the big table
short chunk = 0;
@@ -65,19 +77,14 @@ static bool containsTLDEntry(const QStringRef &entry)
// check all the entries from the given index
while (chunkIndex < tldIndices[index+1] - offset) {
- QString currentEntry = QString::fromUtf8(tldData[chunk] + chunkIndex);
- if (currentEntry == entry)
+ const auto utf8 = tldData[chunk] + chunkIndex;
+ if ((symbol.isEmpty() || QLatin1Char(*utf8) == symbol) && entry == QString::fromUtf8(utf8 + symbol.size()))
return true;
- chunkIndex += qstrlen(tldData[chunk] + chunkIndex) + 1; // +1 for the ending \0
+ chunkIndex += qstrlen(utf8) + 1; // +1 for the ending \0
}
return false;
}
-static inline bool containsTLDEntry(const QString &entry)
-{
- return containsTLDEntry(QStringRef(&entry));
-}
-
/*!
\internal
@@ -111,19 +118,16 @@ Q_CORE_EXPORT bool qIsEffectiveTLD(const QStringRef &domain)
{
// for domain 'foo.bar.com':
// 1. return if TLD table contains 'foo.bar.com'
- if (containsTLDEntry(domain))
+ // 2. else if table contains '*.bar.com',
+ // 3. test that table does not contain '!foo.bar.com'
+
+ if (containsTLDEntry(domain, ExactMatch)) // 1
return true;
const int dot = domain.indexOf(QLatin1Char('.'));
if (dot >= 0) {
- int count = domain.size() - dot;
- QString wildCardDomain = QLatin1Char('*') + domain.right(count);
- // 2. if table contains '*.bar.com',
- // test if table contains '!foo.bar.com'
- if (containsTLDEntry(wildCardDomain)) {
- QString exceptionDomain = QLatin1Char('!') + domain;
- return (! containsTLDEntry(exceptionDomain));
- }
+ if (containsTLDEntry(domain.mid(dot), SuffixMatch)) // 2
+ return !containsTLDEntry(domain, ExceptionMatch); // 3
}
return false;
}
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.cpp b/src/corelib/kernel/qcore_mac.cpp
index c689f47d8f..bfb3b2ff07 100644
--- a/src/corelib/kernel/qcore_mac.cpp
+++ b/src/corelib/kernel/qcore_mac.cpp
@@ -45,16 +45,16 @@ QT_BEGIN_NAMESPACE
QCFString::operator QString() const
{
- if (string.isEmpty() && type)
- const_cast<QCFString*>(this)->string = QString::fromCFString(type);
+ if (string.isEmpty() && value)
+ const_cast<QCFString*>(this)->string = QString::fromCFString(value);
return string;
}
QCFString::operator CFStringRef() const
{
- if (!type)
- const_cast<QCFString*>(this)->type = string.toCFString();
- return type;
+ if (!value)
+ const_cast<QCFString*>(this)->value = string.toCFString();
+ return value;
}
QT_END_NAMESPACE
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_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index d0edef33a2..c2c5a519aa 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -76,6 +76,25 @@
#endif
QT_BEGIN_NAMESPACE
+template <typename T, typename U, U (*RetainFunction)(U), void (*ReleaseFunction)(U)>
+class QAppleRefCounted
+{
+public:
+ QAppleRefCounted(const T &t = T()) : value(t) {}
+ QAppleRefCounted(QAppleRefCounted &&other) : value(other.value) { other.value = T(); }
+ QAppleRefCounted(const QAppleRefCounted &other) : value(other.value) { if (value) RetainFunction(value); }
+ ~QAppleRefCounted() { if (value) ReleaseFunction(value); }
+ operator T() { return value; }
+ void swap(QAppleRefCounted &other) Q_DECL_NOEXCEPT_EXPR(noexcept(qSwap(value, other.value)))
+ { qSwap(value, other.value); }
+ QAppleRefCounted &operator=(const QAppleRefCounted &other)
+ { QAppleRefCounted copy(other); swap(copy); return *this; }
+ QAppleRefCounted &operator=(QAppleRefCounted &&other)
+ { QAppleRefCounted moved(std::move(other)); swap(moved); return *this; }
+ T *operator&() { return &value; }
+protected:
+ T value;
+};
/*
Helper class that automates refernce counting for CFtypes.
@@ -90,32 +109,16 @@ QT_BEGIN_NAMESPACE
HIThemeGet*Shape functions, which in reality are "Copy" functions.
*/
template <typename T>
-class Q_CORE_EXPORT QCFType
+class QCFType : public QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>
{
public:
- inline QCFType(const T &t = 0) : type(t) {}
- inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); }
- inline ~QCFType() { if (type) CFRelease(type); }
- inline operator T() { return type; }
- inline QCFType operator =(const QCFType &helper)
- {
- if (helper.type)
- CFRetain(helper.type);
- CFTypeRef type2 = type;
- type = helper.type;
- if (type2)
- CFRelease(type2);
- return *this;
- }
- inline T *operator&() { return &type; }
- template <typename X> X as() const { return reinterpret_cast<X>(type); }
+ using QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>::QAppleRefCounted;
+ template <typename X> X as() const { return reinterpret_cast<X>(this->value); }
static QCFType constructFromGet(const T &t)
{
CFRetain(t);
return QCFType<T>(t);
}
-protected:
- T type;
};
class Q_CORE_EXPORT QCFString : public QCFType<CFStringRef>
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/qmath.h b/src/corelib/kernel/qmath.h
index 773884047a..68f6a65c87 100644
--- a/src/corelib/kernel/qmath.h
+++ b/src/corelib/kernel/qmath.h
@@ -149,6 +149,8 @@ inline qreal qPow(qreal x, qreal y)
return pow(x, y);
}
+// TODO: use template variables (e.g. Qt::pi<type>) for these once we have C++14 support:
+
#ifndef M_E
#define M_E (2.7182818284590452354)
#endif
diff --git a/src/corelib/kernel/qmath.qdoc b/src/corelib/kernel/qmath.qdoc
index 3a692d5935..a2e24e925b 100644
--- a/src/corelib/kernel/qmath.qdoc
+++ b/src/corelib/kernel/qmath.qdoc
@@ -35,7 +35,24 @@
These functions are partly convenience definitions for basic math operations
not available in the C or Standard Template Libraries.
- \pagekeywords math trigonometry qmath floor ceiling absolute sine cosine tangent inverse tan exponent power natural logarithm
+ The header also ensures some constants specified in POSIX, but not present
+ in C++ standards (so absent from <math.h> on some platforms), are defined:
+
+ \value M_E The base of the natural logarithms, e = exp(1)
+ \value M_LOG2E The base-two logarithm of e
+ \value M_LOG10E The base-ten logarithm of e
+ \value M_LN2 The natural logarithm of two
+ \value M_LN10 The natural logarithm of ten
+ \value M_PI The ratio of a circle's circumference to diameter, \unicode{0x3C0}
+ \value M_PI_2 Half M_PI, \unicode{0x3C0} / 2
+ \value M_PI_4 Quarter M_PI, \unicode{0x3C0} / 4
+ \value M_1_PI The inverse of M_PI, 1 / \unicode{0x3C0}
+ \value M_2_PI Twice the inverse of M_PI, 2 / \unicode{0x3C0}
+ \value M_2_SQRTPI Two divided by the square root of pi, 2 / \unicode{0x221A}\unicode{0x3C0}
+ \value M_SQRT2 The square root of two, \unicode{0x221A}2
+ \value M_SQRT1_2 The square roof of half, 1 / \unicode{0x221A}2
+
+ \pagekeywords math trigonometry qmath floor ceiling absolute sine cosine tangent inverse tan exponent power natural logarithm pi
*/
/*!
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 2e0dd8e5d2..68ee2bb241 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -1489,6 +1489,51 @@ bool QMetaObject::invokeMethod(QObject *obj,
val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
+bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret)
+{
+ if (! object)
+ return false;
+
+ QThread *currentThread = QThread::currentThread();
+ QThread *objectThread = object->thread();
+ if (type == Qt::AutoConnection)
+ type = (currentThread == objectThread) ? Qt::DirectConnection : Qt::QueuedConnection;
+
+ void *argv[] = { ret };
+
+ if (type == Qt::DirectConnection) {
+ slot->call(object, argv);
+ } else if (type == Qt::QueuedConnection) {
+ if (argv[0]) {
+ qWarning("QMetaObject::invokeMethod: Unable to invoke methods with return values in "
+ "queued connections");
+ return false;
+ }
+
+ // args and typesCopy will be deallocated by ~QMetaCallEvent() using free()
+ void **args = static_cast<void **>(calloc(1, sizeof(void *)));
+ Q_CHECK_PTR(args);
+
+ int *types = static_cast<int *>(calloc(1, sizeof(int)));
+ Q_CHECK_PTR(types);
+
+ QCoreApplication::postEvent(object, new QMetaCallEvent(slot, 0, -1, 1, types, args));
+ } else if (type == Qt::BlockingQueuedConnection) {
+#ifndef QT_NO_THREAD
+ if (currentThread == objectThread)
+ qWarning("QMetaObject::invokeMethod: Dead lock detected");
+
+ QSemaphore semaphore;
+ QCoreApplication::postEvent(object, new QMetaCallEvent(slot, 0, -1, 0, 0, argv, &semaphore));
+ semaphore.acquire();
+#endif // QT_NO_THREAD
+ } else {
+ qWarning("QMetaObject::invokeMethod: Unknown connection type");
+ return false;
+ }
+ return true;
+}
+
/*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member,
QGenericReturnArgument ret,
QGenericArgument val0 = QGenericArgument(0),
@@ -1544,6 +1589,44 @@ bool QMetaObject::invokeMethod(QObject *obj,
*/
/*!
+ \fn bool QMetaObject::invokeMethod(QObject *receiver, PointerToMemberFunction function, Qt::ConnectionType type = Qt::AutoConnection, MemberFunctionReturnType *ret = Q_NULLPTR)
+
+ \since 5.10
+
+ \overload
+*/
+
+/*!
+ \fn bool QMetaObject::invokeMethod(QObject *receiver, PointerToMemberFunction function, MemberFunctionReturnType *ret)
+
+ \since 5.10
+
+ \overload
+
+ This overload invokes the member function using the connection type Qt::AutoConnection.
+*/
+
+/*!
+ \fn bool QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = Q_NULLPTR)
+
+ \since 5.10
+
+ \overload
+
+ Call the functor in the event loop of \a context.
+*/
+
+/*!
+ \fn bool QMetaObject::invokeMethod(QObject *context, Functor function, FunctorReturnType *ret = Q_NULLPTR)
+
+ \since 5.10
+
+ \overload
+
+ Call the functor in the event loop of \a context using the connection type Qt::AutoConnection.
+*/
+
+/*!
\fn QMetaObject::Connection::Connection(const Connection &other)
Constructs a copy of \a other.
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_impl.h b/src/corelib/kernel/qobject_impl.h
index d7ae63a98c..c775d807b1 100644
--- a/src/corelib/kernel/qobject_impl.h
+++ b/src/corelib/kernel/qobject_impl.h
@@ -74,60 +74,6 @@ namespace QtPrivate {
template <typename... Args> struct ConnectionTypes<List<Args...>, true>
{ static const int *types() { static const int t[sizeof...(Args) + 1] = { (QtPrivate::QMetaTypeIdHelper<Args>::qt_metatype_id())..., 0 }; return t; } };
- // internal base class (interface) containing functions required to call a slot managed by a pointer to function.
- class QSlotObjectBase {
- QAtomicInt m_ref;
- // don't use virtual functions here; we don't want the
- // compiler to create tons of per-polymorphic-class stuff that
- // we'll never need. We just use one function pointer.
- typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret);
- const ImplFn m_impl;
- protected:
- enum Operation {
- Destroy,
- Call,
- Compare,
-
- NumOperations
- };
- public:
- explicit QSlotObjectBase(ImplFn fn) : m_ref(1), m_impl(fn) {}
-
- inline int ref() Q_DECL_NOTHROW { return m_ref.ref(); }
- inline void destroyIfLastRef() Q_DECL_NOTHROW
- { if (!m_ref.deref()) m_impl(Destroy, this, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR); }
-
- inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, Q_NULLPTR, a, &ret); return ret; }
- inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, Q_NULLPTR); }
- protected:
- ~QSlotObjectBase() {}
- private:
- Q_DISABLE_COPY(QSlotObjectBase)
- };
- // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
- // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
- template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase
- {
- typedef QtPrivate::FunctionPointer<Func> FuncType;
- Func function;
- static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
- {
- switch (which) {
- case Destroy:
- delete static_cast<QSlotObject*>(this_);
- break;
- case Call:
- FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
- break;
- case Compare:
- *ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function;
- break;
- case NumOperations: ;
- }
- }
- public:
- explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
- };
// implementation of QSlotObjectBase for which the slot is a static function
// Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
template<typename Func, typename Args, typename R> class QStaticSlotObject : public QSlotObjectBase
@@ -151,30 +97,6 @@ namespace QtPrivate {
public:
explicit QStaticSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
};
- // implementation of QSlotObjectBase for which the slot is a functor (or lambda)
- // N is the number of arguments
- // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
- template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase
- {
- typedef QtPrivate::Functor<Func, N> FuncType;
- Func function;
- static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
- {
- switch (which) {
- case Destroy:
- delete static_cast<QFunctorSlotObject*>(this_);
- break;
- case Call:
- FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
- break;
- case Compare: // not implemented
- case NumOperations:
- Q_UNUSED(ret);
- }
- }
- public:
- explicit QFunctorSlotObject(const Func &f) : QSlotObjectBase(&impl), function(f) {}
- };
}
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/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index ea4046df55..b6307fcfcf 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -57,7 +57,6 @@ struct QArrayData;
typedef QArrayData QByteArrayData;
class QString;
-
#ifndef Q_MOC_OUTPUT_REVISION
#define Q_MOC_OUTPUT_REVISION 67
#endif
@@ -466,6 +465,91 @@ struct Q_CORE_EXPORT QMetaObject
val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
+#ifdef Q_QDOC
+ template<typename PointerToMemberFunction, typename MemberFunctionReturnType>
+ static bool invokeMethod(QObject *receiver, PointerToMemberFunction function, Qt::ConnectionType type = Qt::AutoConnection, MemberFunctionReturnType *ret = nullptr);
+ template<typename PointerToMemberFunction, typename MemberFunctionReturnType>
+ static bool invokeMethod(QObject *receiver, PointerToMemberFunction function, MemberFunctionReturnType *ret);
+ template<typename Functor, typename FunctorReturnType>
+ static bool invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr);
+ template<typename Functor, typename FunctorReturnType>
+ static bool invokeMethod(QObject *context, Functor function, FunctorReturnType *ret);
+#else
+
+ // invokeMethod() for member function pointer
+ template <typename Func>
+ static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
+ && !std::is_convertible<Func, const char*>::value
+ && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
+ invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
+ Func function,
+ Qt::ConnectionType type = Qt::AutoConnection,
+ typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
+ {
+ return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), type, ret);
+ }
+
+ template <typename Func>
+ static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
+ && !std::is_convertible<Func, const char*>::value
+ && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
+ invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
+ Func function,
+ typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
+ {
+ return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), Qt::AutoConnection, ret);
+ }
+
+ // invokeMethod() for function pointer (not member)
+ template <typename Func>
+ static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
+ && !std::is_convertible<Func, const char*>::value
+ && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
+ invokeMethod(QObject *context, Func function,
+ Qt::ConnectionType type = Qt::AutoConnection,
+ typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
+ {
+ return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), type, ret);
+ }
+
+ template <typename Func>
+ static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
+ && !std::is_convertible<Func, const char*>::value
+ && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
+ invokeMethod(QObject *context, Func function,
+ typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
+ {
+ return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), Qt::AutoConnection, ret);
+ }
+
+ // invokeMethod() for Functor
+ template <typename Func>
+ static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
+ && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
+ && !std::is_convertible<Func, const char*>::value, bool>::type
+ invokeMethod(QObject *context, Func function,
+ Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr)
+ {
+ return invokeMethodImpl(context,
+ new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function),
+ type,
+ ret);
+ }
+
+ template <typename Func>
+ static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
+ && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
+ && !std::is_convertible<Func, const char*>::value, bool>::type
+ invokeMethod(QObject *context, Func function, typename std::result_of<Func()>::type *ret)
+ {
+ return invokeMethodImpl(context,
+ new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function),
+ Qt::AutoConnection,
+ ret);
+ }
+
+#endif
+
QObject *newInstance(QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
@@ -505,6 +589,9 @@ struct Q_CORE_EXPORT QMetaObject
const QMetaObject * const *relatedMetaObjects;
void *extradata; //reserved for future use
} d;
+
+private:
+ static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret);
};
class Q_CORE_EXPORT QMetaObject::Connection {
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index 3f5f2e78bb..ef68050529 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -51,7 +51,7 @@
#endif
QT_BEGIN_NAMESPACE
-
+class QObject;
namespace QtPrivate {
template <typename T> struct RemoveRef { typedef T Type; };
@@ -352,6 +352,98 @@ namespace QtPrivate {
template <typename D> static D dummy();
typedef decltype(dummy<Functor>().operator()((dummy<ArgList>())...)) Value;
};
+
+ // internal base class (interface) containing functions required to call a slot managed by a pointer to function.
+ class QSlotObjectBase {
+ QAtomicInt m_ref;
+ // don't use virtual functions here; we don't want the
+ // compiler to create tons of per-polymorphic-class stuff that
+ // we'll never need. We just use one function pointer.
+ typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret);
+ const ImplFn m_impl;
+ protected:
+ enum Operation {
+ Destroy,
+ Call,
+ Compare,
+
+ NumOperations
+ };
+ public:
+ explicit QSlotObjectBase(ImplFn fn) : m_ref(1), m_impl(fn) {}
+
+ inline int ref() Q_DECL_NOTHROW { return m_ref.ref(); }
+ inline void destroyIfLastRef() Q_DECL_NOTHROW
+ { if (!m_ref.deref()) m_impl(Destroy, this, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR); }
+
+ inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, Q_NULLPTR, a, &ret); return ret; }
+ inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, Q_NULLPTR); }
+ protected:
+ ~QSlotObjectBase() {}
+ private:
+ Q_DISABLE_COPY(QSlotObjectBase)
+ };
+
+ // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
+ // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
+ template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase
+ {
+ typedef QtPrivate::FunctionPointer<Func> FuncType;
+ Func function;
+ static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
+ {
+ switch (which) {
+ case Destroy:
+ delete static_cast<QSlotObject*>(this_);
+ break;
+ case Call:
+ FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
+ break;
+ case Compare:
+ *ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function;
+ break;
+ case NumOperations: ;
+ }
+ }
+ public:
+ explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
+ };
+ // implementation of QSlotObjectBase for which the slot is a functor (or lambda)
+ // N is the number of arguments
+ // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
+ template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase
+ {
+ typedef QtPrivate::Functor<Func, N> FuncType;
+ Func function;
+ static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
+ {
+ switch (which) {
+ case Destroy:
+ delete static_cast<QFunctorSlotObject*>(this_);
+ break;
+ case Call:
+ FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
+ break;
+ case Compare: // not implemented
+ case NumOperations:
+ Q_UNUSED(ret);
+ }
+ }
+ public:
+ explicit QFunctorSlotObject(const Func &f) : QSlotObjectBase(&impl), function(f) {}
+ };
+
+ // typedefs for readability for when there are no parameters
+ template <typename Func>
+ using QSlotObjectWithNoArgs = QSlotObject<Func,
+ QtPrivate::List<>,
+ typename QtPrivate::FunctionPointer<Func>::ReturnType>;
+
+ template <typename Func, typename R>
+ using QFunctorSlotObjectWithNoArgs = QFunctorSlotObject<Func, 0, QtPrivate::List<>, R>;
+
+ template <typename Func>
+ using QFunctorSlotObjectWithNoArgsImplicitReturn = QFunctorSlotObjectWithNoArgs<Func, typename QtPrivate::FunctionPointer<Func>::ReturnType>;
}
QT_END_NAMESPACE
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/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp
index 62dd25e072..1e1a9962f8 100644
--- a/src/corelib/tools/qdatetimeparser.cpp
+++ b/src/corelib/tools/qdatetimeparser.cpp
@@ -713,7 +713,6 @@ int QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionInde
const int sectionmaxsize = sectionMaxSize(sectionIndex);
QStringRef sectionTextRef = text.midRef(index, sectionmaxsize);
- int sectiontextSize = sectionTextRef.size();
QDTPDEBUG << "sectionValue for" << sn.name()
<< "with text" << text << "and st" << sectionTextRef
@@ -784,26 +783,25 @@ int QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionInde
case MinuteSection:
case SecondSection:
case MSecSection: {
+ int sectiontextSize = sectionTextRef.size();
if (sectiontextSize == 0) {
num = 0;
used = 0;
state = Intermediate;
} else {
+ for (int i = 0; i < sectiontextSize; ++i) {
+ if (sectionTextRef.at(i).isSpace())
+ sectiontextSize = i; // which exits the loop
+ }
+
const int absMax = absoluteMax(sectionIndex);
QLocale loc;
bool ok = true;
int last = -1;
used = -1;
- QStringRef digitsStr = sectionTextRef;
- for (int i = 0; i < sectiontextSize; ++i) {
- if (digitsStr.at(i).isSpace()) {
- sectiontextSize = i;
- break;
- }
- }
-
const int max = qMin(sectionmaxsize, sectiontextSize);
+ QStringRef digitsStr = sectionTextRef.left(max);
for (int digits = max; digits >= 1; --digits) {
digitsStr.truncate(digits);
int tmp = (int)loc.toUInt(digitsStr, &ok);
@@ -884,14 +882,14 @@ int QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionInde
*/
QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPosition,
- const QDateTime &currentValue, bool fixup) const
+ const QDateTime &defaultValue, bool fixup) const
{
const QDateTime minimum = getMinimum();
const QDateTime maximum = getMaximum();
State state = Acceptable;
- QDateTime newCurrentValue;
+ QDateTime finalValue;
bool conflicts = false;
const int sectionNodesCount = sectionNodes.size();
@@ -899,16 +897,16 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos
{
int pos = 0;
int year, month, day;
- const QDate currentDate = currentValue.date();
- const QTime currentTime = currentValue.time();
- currentDate.getDate(&year, &month, &day);
+ const QDate defaultDate = defaultValue.date();
+ const QTime defaultTime = defaultValue.time();
+ defaultDate.getDate(&year, &month, &day);
int year2digits = year % 100;
- int hour = currentTime.hour();
+ int hour = defaultTime.hour();
int hour12 = -1;
- int minute = currentTime.minute();
- int second = currentTime.second();
- int msec = currentTime.msec();
- int dayofweek = currentDate.dayOfWeek();
+ int minute = defaultTime.minute();
+ int second = defaultTime.second();
+ int msec = defaultTime.msec();
+ int dayofweek = defaultDate.dayOfWeek();
int ampm = -1;
Sections isSet = NoSection;
@@ -929,7 +927,7 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos
const SectionNode sn = sectionNodes.at(index);
int used;
- num = parseSection(currentValue, index, input, cursorPosition, pos, tmpstate, &used);
+ num = parseSection(defaultValue, index, input, cursorPosition, pos, tmpstate, &used);
QDTPDEBUG << "sectionValue" << sn.name() << input
<< "pos" << pos << "used" << used << stateName(tmpstate);
if (fixup && tmpstate == Intermediate && used < sn.count) {
@@ -1099,20 +1097,22 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos
}
- newCurrentValue = QDateTime(QDate(year, month, day), QTime(hour, minute, second, msec), spec);
+ finalValue = QDateTime(QDate(year, month, day),
+ QTime(hour, minute, second, msec),
+ spec);
QDTPDEBUG << year << month << day << hour << minute << second << msec;
}
QDTPDEBUGN("'%s' => '%s'(%s)", input.toLatin1().constData(),
- newCurrentValue.toString(QLatin1String("yyyy/MM/dd hh:mm:ss.zzz")).toLatin1().constData(),
+ finalValue.toString(QLatin1String("yyyy/MM/dd hh:mm:ss.zzz")).toLatin1().constData(),
stateName(state).toLatin1().constData());
}
end:
- if (newCurrentValue.isValid()) {
- if (context != FromString && state != Invalid && newCurrentValue < minimum) {
+ if (finalValue.isValid()) {
+ if (context != FromString && state != Invalid && finalValue < minimum) {
const QLatin1Char space(' ');
- if (newCurrentValue >= minimum)
+ if (finalValue >= minimum)
qWarning("QDateTimeParser::parse Internal error 3 (%s %s)",
- qPrintable(newCurrentValue.toString()), qPrintable(minimum.toString()));
+ qPrintable(finalValue.toString()), qPrintable(minimum.toString()));
bool done = false;
state = Invalid;
@@ -1136,7 +1136,7 @@ end:
case PossibleAM:
case PossiblePM:
case PossibleBoth: {
- const QDateTime copy(newCurrentValue.addSecs(12 * 60 * 60));
+ const QDateTime copy(finalValue.addSecs(12 * 60 * 60));
if (copy >= minimum && copy <= maximum) {
state = Intermediate;
done = true;
@@ -1146,11 +1146,11 @@ end:
Q_FALLTHROUGH();
case MonthSection:
if (sn.count >= 3) {
- const int currentMonth = newCurrentValue.date().month();
- int tmp = currentMonth;
+ const int finalMonth = finalValue.date().month();
+ int tmp = finalMonth;
// I know the first possible month makes the date too early
while ((tmp = findMonth(t, tmp + 1, i)) != -1) {
- const QDateTime copy(newCurrentValue.addMonths(tmp - currentMonth));
+ const QDateTime copy(finalValue.addMonths(tmp - finalMonth));
if (copy >= minimum && copy <= maximum)
break; // break out of while
}
@@ -1167,24 +1167,24 @@ end:
int toMax;
if (sn.type & TimeSectionMask) {
- if (newCurrentValue.daysTo(minimum) != 0) {
+ if (finalValue.daysTo(minimum) != 0) {
break;
}
- const QTime time = newCurrentValue.time();
+ const QTime time = finalValue.time();
toMin = time.msecsTo(minimum.time());
- if (newCurrentValue.daysTo(maximum) > 0) {
+ if (finalValue.daysTo(maximum) > 0) {
toMax = -1; // can't get to max
} else {
toMax = time.msecsTo(maximum.time());
}
} else {
- toMin = newCurrentValue.daysTo(minimum);
- toMax = newCurrentValue.daysTo(maximum);
+ toMin = finalValue.daysTo(minimum);
+ toMax = finalValue.daysTo(maximum);
}
const int maxChange = sn.maxChange();
if (toMin > maxChange) {
QDTPDEBUG << "invalid because toMin > maxChange" << toMin
- << maxChange << t << newCurrentValue << minimum;
+ << maxChange << t << finalValue << minimum;
state = Invalid;
done = true;
break;
@@ -1201,11 +1201,11 @@ end:
break;
}
- int max = toMax != -1 ? getDigit(maximum, i) : absoluteMax(i, newCurrentValue);
+ int max = toMax != -1 ? getDigit(maximum, i) : absoluteMax(i, finalValue);
int pos = cursorPosition - sn.pos;
if (pos < 0 || pos >= t.size())
pos = -1;
- if (!potentialValue(t.simplified(), min, max, i, newCurrentValue, pos)) {
+ if (!potentialValue(t.simplified(), min, max, i, finalValue, pos)) {
QDTPDEBUG << "invalid because potentialValue(" << t.simplified() << min << max
<< sn.name() << "returned" << toMax << toMin << pos;
state = Invalid;
@@ -1222,21 +1222,21 @@ end:
if (context == FromString) {
// optimization
Q_ASSERT(maximum.date().toJulianDay() == 4642999);
- if (newCurrentValue.date().toJulianDay() > 4642999)
+ if (finalValue.date().toJulianDay() > 4642999)
state = Invalid;
} else {
- if (newCurrentValue > maximum)
+ if (finalValue > maximum)
state = Invalid;
}
- QDTPDEBUG << "not checking intermediate because newCurrentValue is" << newCurrentValue << minimum << maximum;
+ QDTPDEBUG << "not checking intermediate because finalValue is" << finalValue << minimum << maximum;
}
}
StateNode node;
node.input = input;
node.state = state;
node.conflicts = conflicts;
- node.value = newCurrentValue.toTimeSpec(spec);
+ node.value = finalValue.toTimeSpec(spec);
text = input;
return node;
}
diff --git a/src/corelib/tools/qdatetimeparser_p.h b/src/corelib/tools/qdatetimeparser_p.h
index b50c88b4c1..1efc6696ce 100644
--- a/src/corelib/tools/qdatetimeparser_p.h
+++ b/src/corelib/tools/qdatetimeparser_p.h
@@ -177,7 +177,7 @@ public:
};
#ifndef QT_NO_DATESTRING
- StateNode parse(QString &input, int &cursorPosition, const QDateTime &currentValue, bool fixup) const;
+ StateNode parse(QString &input, int &cursorPosition, const QDateTime &defaultValue, bool fixup) const;
#endif
bool parseFormat(const QString &format);
#ifndef QT_NO_DATESTRING
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 334bd52f1e..662c304a2e 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -235,6 +235,7 @@ uint qHash(const QByteArray &key, uint seed) Q_DECL_NOTHROW
return hash(reinterpret_cast<const uchar *>(key.constData()), size_t(key.size()), seed);
}
+#if QT_STRINGVIEW_LEVEL < 2
uint qHash(const QString &key, uint seed) Q_DECL_NOTHROW
{
return hash(key.unicode(), size_t(key.size()), seed);
@@ -244,6 +245,12 @@ uint qHash(const QStringRef &key, uint seed) Q_DECL_NOTHROW
{
return hash(key.unicode(), size_t(key.size()), seed);
}
+#endif
+
+uint qHash(QStringView key, uint seed) Q_DECL_NOTHROW
+{
+ return hash(key.data(), key.size(), seed);
+}
uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW
{
@@ -405,37 +412,25 @@ void qSetGlobalQHashSeed(int newSeed)
results.
The qt_hash functions must *never* change their results.
+
+ This function can hash discontiguous memory by invoking it on each chunk,
+ passing the previous's result in the next call's \a chained argument.
*/
-static uint qt_hash(const QChar *p, int n) Q_DECL_NOTHROW
+uint qt_hash(QStringView key, uint chained) Q_DECL_NOTHROW
{
- uint h = 0;
+ auto n = key.size();
+ auto p = key.utf16();
+
+ uint h = chained;
while (n--) {
- h = (h << 4) + (*p++).unicode();
+ h = (h << 4) + *p++;
h ^= (h & 0xf0000000) >> 23;
h &= 0x0fffffff;
}
return h;
}
-/*!
- \internal
- \overload
-*/
-uint qt_hash(const QString &key) Q_DECL_NOTHROW
-{
- return qt_hash(key.unicode(), key.size());
-}
-
-/*!
- \internal
- \overload
-*/
-uint qt_hash(const QStringRef &key) Q_DECL_NOTHROW
-{
- return qt_hash(key.unicode(), key.size());
-}
-
/*
The prime_deltas array contains the difference between a power
of two and the next prime number:
@@ -1033,6 +1028,13 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
+/*! \fn uint qHash(QStringView key, uint seed = 0)
+ \relates QStringView
+ \since 5.10
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+
/*! \fn uint qHash(QLatin1String key, uint seed = 0)
\relates QHash
\since 5.0
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index 0eb6c1b5ce..f75b310e4e 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -41,7 +41,7 @@
#ifndef QHASHFUNCTIONS_H
#define QHASHFUNCTIONS_H
-#include <QtCore/qchar.h>
+#include <QtCore/qstring.h>
#include <QtCore/qpair.h>
#include <numeric> // for std::accumulate
@@ -95,12 +95,14 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(long double key, uint seed = 0) Q
#endif
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(const QChar key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.unicode(), seed); }
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QByteArray &key, uint seed = 0) Q_DECL_NOTHROW;
+#if QT_STRINGVIEW_LEVEL < 2
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QString &key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QStringRef &key, uint seed = 0) Q_DECL_NOTHROW;
+#endif
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QStringView key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QBitArray &key, uint seed = 0) Q_DECL_NOTHROW;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QLatin1String key, uint seed = 0) Q_DECL_NOTHROW;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(const QString &key) Q_DECL_NOTHROW;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(const QStringRef &key) Q_DECL_NOTHROW;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) Q_DECL_NOTHROW;
template <class T> inline uint qHash(const T *key, uint seed = 0) Q_DECL_NOTHROW
{
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index bde4bf553e..9be20e6676 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);
-
- code[0] = ushort(c[0]);
- code[1] = ushort(c[1]);
- if (c[2] != 0)
- code[2] = ushort(c[2]);
+ return QLatin1String(reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3);
- 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
@@ -1122,27 +1113,27 @@ QString QLocale::name() const
return d->languageCode() + QLatin1Char('_') + d->countryCode();
}
-static qlonglong toIntegral_helper(const QLocaleData *d, const QChar *data, int len, bool *ok,
+static qlonglong toIntegral_helper(const QLocaleData *d, QStringView str, bool *ok,
QLocale::NumberOptions mode, qlonglong)
{
- return d->stringToLongLong(data, len, 10, ok, mode);
+ return d->stringToLongLong(str, 10, ok, mode);
}
-static qulonglong toIntegral_helper(const QLocaleData *d, const QChar *data, int len, bool *ok,
+static qulonglong toIntegral_helper(const QLocaleData *d, QStringView str, bool *ok,
QLocale::NumberOptions mode, qulonglong)
{
- return d->stringToUnsLongLong(data, len, 10, ok, mode);
+ return d->stringToUnsLongLong(str, 10, ok, mode);
}
template <typename T> static inline
-T toIntegral_helper(const QLocalePrivate *d, const QChar *data, int len, bool *ok)
+T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
{
// ### Qt6: use std::conditional<std::is_unsigned<T>::value, qulonglong, qlonglong>::type
const bool isUnsigned = T(0) < T(-1);
typedef typename QtPrivate::QConditional<isUnsigned, qulonglong, qlonglong>::Type Int64;
// we select the right overload by the last, unused parameter
- Int64 val = toIntegral_helper(d->m_data, data, len, ok, d->m_numberOptions, Int64());
+ Int64 val = toIntegral_helper(d->m_data, str, ok, d->m_numberOptions, Int64());
if (T(val) != val) {
if (ok)
*ok = false;
@@ -1211,6 +1202,7 @@ QString QLocale::scriptToString(QLocale::Script script)
return QLatin1String(script_name_list + script_name_index[script]);
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns the short int represented by the localized string \a s.
@@ -1226,7 +1218,7 @@ QString QLocale::scriptToString(QLocale::Script script)
short QLocale::toShort(const QString &s, bool *ok) const
{
- return toIntegral_helper<short>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<short>(d, s, ok);
}
/*!
@@ -1244,7 +1236,7 @@ short QLocale::toShort(const QString &s, bool *ok) const
ushort QLocale::toUShort(const QString &s, bool *ok) const
{
- return toIntegral_helper<ushort>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<ushort>(d, s, ok);
}
/*!
@@ -1262,7 +1254,7 @@ ushort QLocale::toUShort(const QString &s, bool *ok) const
int QLocale::toInt(const QString &s, bool *ok) const
{
- return toIntegral_helper<int>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<int>(d, s, ok);
}
/*!
@@ -1280,7 +1272,7 @@ int QLocale::toInt(const QString &s, bool *ok) const
uint QLocale::toUInt(const QString &s, bool *ok) const
{
- return toIntegral_helper<uint>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<uint>(d, s, ok);
}
/*!
@@ -1299,7 +1291,7 @@ uint QLocale::toUInt(const QString &s, bool *ok) const
qlonglong QLocale::toLongLong(const QString &s, bool *ok) const
{
- return toIntegral_helper<qlonglong>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<qlonglong>(d, s, ok);
}
/*!
@@ -1318,7 +1310,7 @@ qlonglong QLocale::toLongLong(const QString &s, bool *ok) const
qulonglong QLocale::toULongLong(const QString &s, bool *ok) const
{
- return toIntegral_helper<qulonglong>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<qulonglong>(d, s, ok);
}
/*!
@@ -1361,7 +1353,7 @@ float QLocale::toFloat(const QString &s, bool *ok) const
double QLocale::toDouble(const QString &s, bool *ok) const
{
- return d->m_data->stringToDouble(s.constData(), s.size(), ok, d->m_numberOptions);
+ return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
}
/*!
@@ -1381,7 +1373,7 @@ double QLocale::toDouble(const QString &s, bool *ok) const
short QLocale::toShort(const QStringRef &s, bool *ok) const
{
- return toIntegral_helper<short>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<short>(d, s, ok);
}
/*!
@@ -1401,7 +1393,7 @@ short QLocale::toShort(const QStringRef &s, bool *ok) const
ushort QLocale::toUShort(const QStringRef &s, bool *ok) const
{
- return toIntegral_helper<ushort>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<ushort>(d, s, ok);
}
/*!
@@ -1421,7 +1413,7 @@ ushort QLocale::toUShort(const QStringRef &s, bool *ok) const
int QLocale::toInt(const QStringRef &s, bool *ok) const
{
- return toIntegral_helper<int>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<int>(d, s, ok);
}
/*!
@@ -1441,7 +1433,7 @@ int QLocale::toInt(const QStringRef &s, bool *ok) const
uint QLocale::toUInt(const QStringRef &s, bool *ok) const
{
- return toIntegral_helper<uint>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<uint>(d, s, ok);
}
/*!
@@ -1462,7 +1454,7 @@ uint QLocale::toUInt(const QStringRef &s, bool *ok) const
qlonglong QLocale::toLongLong(const QStringRef &s, bool *ok) const
{
- return toIntegral_helper<qlonglong>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<qlonglong>(d, s, ok);
}
/*!
@@ -1483,7 +1475,7 @@ qlonglong QLocale::toLongLong(const QStringRef &s, bool *ok) const
qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const
{
- return toIntegral_helper<qulonglong>(d, s.constData(), s.size(), ok);
+ return toIntegral_helper<qulonglong>(d, s, ok);
}
/*!
@@ -1530,9 +1522,178 @@ float QLocale::toFloat(const QStringRef &s, bool *ok) const
double QLocale::toDouble(const QStringRef &s, bool *ok) const
{
- return d->m_data->stringToDouble(s.constData(), s.size(), ok, d->m_numberOptions);
+ return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
}
+#endif // QT_STRINGVIEW_LEVEL < 2
+
+/*!
+ Returns the short int represented by the localized string \a s.
+ If the conversion fails, the function returns 0.
+
+ If \a ok is not null, failure is reported by setting *ok to false, and
+ success by setting *ok to true.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toUShort(), toString()
+
+ \since 5.10
+*/
+
+short QLocale::toShort(QStringView s, bool *ok) const
+{
+ return toIntegral_helper<short>(d, s, ok);
+}
+
+/*!
+ Returns the unsigned short int represented by the localized string \a s.
+
+ If the conversion fails, the function returns 0.
+
+ If \a ok is not null, failure is reported by setting *ok to false, and
+ success by setting *ok to true.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toShort(), toString()
+
+ \since 5.10
+*/
+
+ushort QLocale::toUShort(QStringView s, bool *ok) const
+{
+ return toIntegral_helper<ushort>(d, s, ok);
+}
+
+/*!
+ Returns the int represented by the localized string \a s.
+
+ If the conversion fails, the function returns 0.
+
+ If \a ok is not null, failure is reported by setting *ok to false, and
+ success by setting *ok to true.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toUInt(), toString()
+
+ \since 5.10
+*/
+
+int QLocale::toInt(QStringView s, bool *ok) const
+{
+ return toIntegral_helper<int>(d, s, ok);
+}
+
+/*!
+ Returns the unsigned int represented by the localized string \a s.
+
+ If the conversion fails, the function returns 0.
+
+ If \a ok is not null, failure is reported by setting *ok to false, and
+ success by setting *ok to true.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toInt(), toString()
+
+ \since 5.10
+*/
+
+uint QLocale::toUInt(QStringView s, bool *ok) const
+{
+ return toIntegral_helper<uint>(d, s, ok);
+}
+
+/*!
+ Returns the long long int represented by the localized string \a s.
+
+ If the conversion fails, the function returns 0.
+
+ If \a ok is not null, failure is reported by setting *ok to false, and
+ success by setting *ok to true.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toInt(), toULongLong(), toDouble(), toString()
+
+ \since 5.10
+*/
+
+
+qlonglong QLocale::toLongLong(QStringView s, bool *ok) const
+{
+ return toIntegral_helper<qlonglong>(d, s, ok);
+}
+
+/*!
+ Returns the unsigned long long int represented by the localized
+ string \a s.
+
+ If the conversion fails, the function returns 0.
+
+ If \a ok is not null, failure is reported by setting *ok to false, and
+ success by setting *ok to true.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toLongLong(), toInt(), toDouble(), toString()
+
+ \since 5.10
+*/
+
+qulonglong QLocale::toULongLong(QStringView s, bool *ok) const
+{
+ return toIntegral_helper<qulonglong>(d, s, ok);
+}
+
+/*!
+ Returns the float represented by the localized string \a s, or 0.0
+ if the conversion failed.
+
+ If \a ok is not null, reports failure by setting
+ *ok to false and success by setting *ok to true.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toDouble(), toInt(), toString()
+
+ \since 5.10
+*/
+
+float QLocale::toFloat(QStringView s, bool *ok) const
+{
+ return QLocaleData::convertDoubleToFloat(toDouble(s, ok), ok);
+}
+
+/*!
+ Returns the double represented by the localized string \a s, or
+ 0.0 if the conversion failed.
+
+ If \a ok is not null, reports failure by setting
+ *ok to false and success by setting *ok to true.
+
+ Unlike QString::toDouble(), this function does not fall back to
+ the "C" locale if the string cannot be interpreted in this
+ locale.
+
+ \snippet code/src_corelib_tools_qlocale.cpp 3-qstringview
+
+ Notice that the last conversion returns 1234.0, because '.' is the
+ thousands group separator in the German locale.
+
+ This function ignores leading and trailing whitespace.
+
+ \sa toFloat(), toInt(), toString()
+
+ \since 5.10
+*/
+
+double QLocale::toDouble(QStringView s, bool *ok) const
+{
+ return d->m_data->stringToDouble(s, ok, d->m_numberOptions);
+}
/*!
Returns a localized string representation of \a i.
@@ -3076,12 +3237,12 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
number. We can't detect junk here, since we don't even know the base
of the number.
*/
-bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOptions number_options,
+bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
CharBuff *result) const
{
- const QChar *uc = str;
- int l = len;
- int idx = 0;
+ const QChar *uc = s.data();
+ auto l = s.size();
+ decltype(l) idx = 0;
// Skip whitespace
while (idx < l && uc[idx].isSpace())
@@ -3199,7 +3360,7 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
return idx == l;
}
-bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArray *buff,
+bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray *buff,
int decDigits, QLocale::NumberOptions number_options) const
{
buff->clear();
@@ -3213,7 +3374,7 @@ bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArr
bool dec = false;
int decDigitCnt = 0;
- for (int i = 0; i < str.length(); ++i) {
+ for (QStringView::size_type i = 0; i < str.size(); ++i) {
char c = digitToCLocale(str.at(i));
if (c >= '0' && c <= '9') {
@@ -3300,11 +3461,11 @@ bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArr
return true;
}
-double QLocaleData::stringToDouble(const QChar *begin, int len, bool *ok,
+double QLocaleData::stringToDouble(QStringView str, bool *ok,
QLocale::NumberOptions number_options) const
{
CharBuff buff;
- if (!numberToCLocale(begin, len, number_options, &buff)) {
+ if (!numberToCLocale(str, number_options, &buff)) {
if (ok != 0)
*ok = false;
return 0.0;
@@ -3317,11 +3478,11 @@ double QLocaleData::stringToDouble(const QChar *begin, int len, bool *ok,
return d;
}
-qlonglong QLocaleData::stringToLongLong(const QChar *begin, int len, int base, bool *ok,
+qlonglong QLocaleData::stringToLongLong(QStringView str, int base, bool *ok,
QLocale::NumberOptions number_options) const
{
CharBuff buff;
- if (!numberToCLocale(begin, len, number_options, &buff)) {
+ if (!numberToCLocale(str, number_options, &buff)) {
if (ok != 0)
*ok = false;
return 0;
@@ -3330,11 +3491,11 @@ qlonglong QLocaleData::stringToLongLong(const QChar *begin, int len, int base, b
return bytearrayToLongLong(buff.constData(), base, ok);
}
-qulonglong QLocaleData::stringToUnsLongLong(const QChar *begin, int len, int base, bool *ok,
+qulonglong QLocaleData::stringToUnsLongLong(QStringView str, int base, bool *ok,
QLocale::NumberOptions number_options) const
{
CharBuff buff;
- if (!numberToCLocale(begin, len, number_options, &buff)) {
+ if (!numberToCLocale(str, number_options, &buff)) {
if (ok != 0)
*ok = false;
return 0;
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index bd89e48234..1f20bcd241 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -935,6 +935,7 @@ public:
QString nativeLanguageName() const;
QString nativeCountryName() const;
+#if QT_STRINGVIEW_LEVEL < 2
short toShort(const QString &s, bool *ok = Q_NULLPTR) const;
ushort toUShort(const QString &s, bool *ok = Q_NULLPTR) const;
int toInt(const QString &s, bool *ok = Q_NULLPTR) const;
@@ -952,6 +953,16 @@ public:
qulonglong toULongLong(const QStringRef &s, bool *ok = Q_NULLPTR) const;
float toFloat(const QStringRef &s, bool *ok = Q_NULLPTR) const;
double toDouble(const QStringRef &s, bool *ok = Q_NULLPTR) const;
+#endif
+
+ short toShort(QStringView s, bool *ok = nullptr) const;
+ ushort toUShort(QStringView s, bool *ok = nullptr) const;
+ int toInt(QStringView s, bool *ok = nullptr) const;
+ uint toUInt(QStringView s, bool *ok = nullptr) const;
+ qlonglong toLongLong(QStringView s, bool *ok = nullptr) const;
+ qulonglong toULongLong(QStringView s, bool *ok = nullptr) const;
+ float toFloat(QStringView s, bool *ok = nullptr) const;
+ double toDouble(QStringView s, bool *ok = nullptr) const;
QString toString(qlonglong i) const;
QString toString(qulonglong i) const;
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index f7adb021b6..589eae3cfb 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -254,25 +254,21 @@ public:
return float(d);
}
- double stringToDouble(const QChar *begin, int len, bool *ok,
- QLocale::NumberOptions number_options) const;
- qint64 stringToLongLong(const QChar *begin, int len, int base, bool *ok,
- QLocale::NumberOptions number_options) const;
- quint64 stringToUnsLongLong(const QChar *begin, int len, int base, bool *ok,
- QLocale::NumberOptions number_options) const;
+ double stringToDouble(QStringView str, bool *ok, QLocale::NumberOptions options) const;
+ qint64 stringToLongLong(QStringView str, int base, bool *ok, QLocale::NumberOptions options) const;
+ quint64 stringToUnsLongLong(QStringView str, int base, bool *ok, QLocale::NumberOptions options) const;
// these functions are used in QIntValidator (QtGui)
Q_CORE_EXPORT static double bytearrayToDouble(const char *num, bool *ok, bool *overflow = 0);
Q_CORE_EXPORT static qint64 bytearrayToLongLong(const char *num, int base, bool *ok, bool *overflow = 0);
Q_CORE_EXPORT static quint64 bytearrayToUnsLongLong(const char *num, int base, bool *ok);
- bool numberToCLocale(const QChar *str, int len, QLocale::NumberOptions number_options,
+ bool numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
CharBuff *result) const;
inline char digitToCLocale(QChar c) const;
// this function is used in QIntValidator (QtGui)
- Q_CORE_EXPORT bool validateChars(
- const QString &str, NumberMode numMode, QByteArray *buff, int decDigits = -1,
+ Q_CORE_EXPORT bool validateChars(QStringView str, NumberMode numMode, QByteArray *buff, int decDigits = -1,
QLocale::NumberOptions number_options = QLocale::DefaultNumberOptions) const;
public:
@@ -349,23 +345,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..53784dd570 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;
}
@@ -374,16 +374,16 @@ static void qt_to_latin1(uchar *dst, const ushort *src, int length)
}
// Unicode case-insensitive comparison
-static int ucstricmp(const ushort *a, const ushort *ae, const ushort *b, const ushort *be)
+static int ucstricmp(const QChar *a, const QChar *ae, const QChar *b, const QChar *be)
{
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;
+ const QChar *e = ae;
if (be - b < ae - a)
e = a + (be - b);
@@ -393,7 +393,7 @@ static int ucstricmp(const ushort *a, const ushort *ae, const ushort *b, const u
// qDebug() << hex << alast << blast;
// qDebug() << hex << "*a=" << *a << "alast=" << alast << "folded=" << foldCase (*a, alast);
// qDebug() << hex << "*b=" << *b << "blast=" << blast << "folded=" << foldCase (*b, blast);
- int diff = foldCase(*a, alast) - foldCase(*b, blast);
+ int diff = foldCase(a->unicode(), alast) - foldCase(b->unicode(), blast);
if ((diff))
return diff;
++a;
@@ -408,22 +408,19 @@ 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)
+static int ucstricmp(const QChar *a, const QChar *ae, const char *b, const char *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;
+ auto e = ae;
if (be - b < ae - a)
e = a + (be - b);
while (a < e) {
- int diff = foldCase(*a) - foldCase(*b);
+ int diff = foldCase(a->unicode()) - foldCase(uchar(*b));
if ((diff))
return diff;
++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);
@@ -565,7 +561,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l)
#endif
}
-static int ucstrncmp(const QChar *a, const uchar *c, int l)
+static int ucstrncmp(const QChar *a, const uchar *c, size_t l)
{
const ushort *uc = reinterpret_cast<const ushort *>(a);
const ushort *e = uc + l;
@@ -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
@@ -656,35 +652,133 @@ static int ucstrncmp(const QChar *a, const uchar *c, int l)
return 0;
}
+template <typename Number>
+Q_DECL_CONSTEXPR int lencmp(Number lhs, Number rhs) Q_DECL_NOTHROW
+{
+ return lhs == rhs ? 0 :
+ lhs > rhs ? 1 :
+ /* else */ -1 ;
+}
+
// Unicode case-sensitive comparison
-static int ucstrcmp(const QChar *a, int alen, const QChar *b, int blen)
+static int ucstrcmp(const QChar *a, size_t alen, const QChar *b, size_t blen)
{
if (a == b && alen == blen)
return 0;
- int l = qMin(alen, blen);
+ const size_t l = qMin(alen, blen);
int cmp = ucstrncmp(a, b, l);
- return cmp ? cmp : (alen-blen);
+ return cmp ? cmp : lencmp(alen, blen);
}
-// Unicode case-insensitive compare two same-sized strings
-static int ucstrnicmp(const ushort *a, const ushort *b, int l)
+static int ucstrcmp(const QChar *a, size_t alen, const char *b, size_t blen)
{
- return ucstricmp(a, a + l, b, b + l);
+ const size_t l = qMin(alen, blen);
+ const int cmp = ucstrncmp(a, reinterpret_cast<const uchar*>(b), l);
+ return cmp ? cmp : lencmp(alen, blen);
}
-static bool qMemEquals(const quint16 *a, const quint16 *b, int length)
+static int qt_compare_strings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
- if (a == b || !length)
- return true;
+ if (cs == Qt::CaseSensitive)
+ return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size());
+ else
+ return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
- return ucstrncmp(reinterpret_cast<const QChar *>(a), reinterpret_cast<const QChar *>(b), length) == 0;
+static int qt_compare_strings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ if (cs == Qt::CaseSensitive)
+ return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size());
+ else
+ return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
-static int ucstrcmp(const QChar *a, int alen, const uchar *b, int blen)
+static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
- int l = qMin(alen, blen);
- int cmp = ucstrncmp(a, b, l);
- return cmp ? cmp : (alen-blen);
+ const auto l = std::min(lhs.size(), rhs.size());
+ int r;
+ if (cs == Qt::CaseSensitive)
+ r = qstrncmp(lhs.data(), rhs.data(), l);
+ else
+ r = qstrnicmp(lhs.data(), rhs.data(), l);
+ return r ? r : lencmp(lhs.size(), rhs.size());
+}
+
+/*!
+ \relates QStringView
+ \since 5.10
+
+ Returns an integer that compares to 0 as \a lhs compares to \a rhs.
+
+ If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
+ otherwise the comparison is case-insensitive.
+
+ Case-sensitive comparison is based exclusively on the numeric Unicode values
+ of the characters and is very fast, but is not what a human would expect.
+ Consider sorting user-visible strings with QString::localeAwareCompare().
+
+ \snippet qstring/main.cpp qCompareStrings-QSV-QSV
+*/
+int qCompareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_compare_strings(lhs, rhs, cs);
+}
+
+/*!
+ \relates QStringView
+ \since 5.10
+ \overload
+
+ Returns an integer that compares to 0 as \a lhs compares to \a rhs.
+
+ If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
+ otherwise the comparison is case-insensitive.
+
+ Case-sensitive comparison is based exclusively on the numeric Unicode values
+ of the characters and is very fast, but is not what a human would expect.
+ Consider sorting user-visible strings with QString::localeAwareCompare().
+*/
+int qCompareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_compare_strings(lhs, rhs, cs);
+}
+
+/*!
+ \relates QStringView
+ \since 5.10
+ \overload
+
+ Returns an integer that compares to 0 as \a lhs compares to \a rhs.
+
+ If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
+ otherwise the comparison is case-insensitive.
+
+ Case-sensitive comparison is based exclusively on the numeric Unicode values
+ of the characters and is very fast, but is not what a human would expect.
+ Consider sorting user-visible strings with QString::localeAwareCompare().
+*/
+int qCompareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return -qt_compare_strings(rhs, lhs, cs);
+}
+
+/*!
+ \relates QStringView
+ \since 5.10
+ \overload
+
+ Returns an integer that compares to 0 as \a lhs compares to \a rhs.
+
+ If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
+ otherwise the comparison is case-insensitive.
+
+ Case-sensitive comparison is based exclusively on the numeric Latin-1 values
+ of the characters and is very fast, but is not what a human would expect.
+ Consider sorting user-visible strings with QString::localeAwareCompare().
+*/
+int qCompareStrings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_compare_strings(lhs, rhs, cs);
}
/*!
@@ -2789,7 +2883,7 @@ bool operator==(const QString &s1, const QString &s2) Q_DECL_NOTHROW
if (s1.d->size != s2.d->size)
return false;
- return qMemEquals(s1.d->data(), s2.d->data(), s1.d->size);
+ return qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0;
}
/*!
@@ -2802,10 +2896,7 @@ bool QString::operator==(QLatin1String other) const Q_DECL_NOTHROW
if (d->size != other.size())
return false;
- if (!other.size())
- return isEmpty();
-
- return compare_helper(data(), size(), other, Qt::CaseSensitive) == 0;
+ return qt_compare_strings(*this, other, Qt::CaseSensitive) == 0;
}
/*! \fn bool QString::operator==(const QByteArray &other) const
@@ -2850,8 +2941,9 @@ bool QString::operator==(QLatin1String other) const Q_DECL_NOTHROW
*/
bool operator<(const QString &s1, const QString &s2) Q_DECL_NOTHROW
{
- return ucstrcmp(s1.constData(), s1.length(), s2.constData(), s2.length()) < 0;
+ return qt_compare_strings(s1, s2, Qt::CaseSensitive) < 0;
}
+
/*!
\overload operator<()
@@ -2860,11 +2952,7 @@ bool operator<(const QString &s1, const QString &s2) Q_DECL_NOTHROW
*/
bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW
{
- const uchar *c = (const uchar *) other.latin1();
- if (!c || *c == 0)
- return false;
-
- return compare_helper(data(), size(), other, Qt::CaseSensitive) < 0;
+ return qt_compare_strings(*this, other, Qt::CaseSensitive) < 0;
}
/*! \fn bool QString::operator<(const QByteArray &other) const
@@ -2965,11 +3053,7 @@ bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW
*/
bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW
{
- const uchar *c = (const uchar *) other.latin1();
- if (!c || *c == '\0')
- return !isEmpty();
-
- return compare_helper(data(), size(), other, Qt::CaseSensitive) > 0;
+ return qt_compare_strings(*this, other, Qt::CaseSensitive) > 0;
}
/*! \fn bool QString::operator>(const QByteArray &other) const
@@ -3166,11 +3250,12 @@ int qFindString(
return qFindStringBoyerMoore(haystack0, haystackLen, from,
needle0, needleLen, cs);
+ auto sv = [sl](const ushort *v) { return QStringView(v, sl); };
/*
We use some hashing for efficiency's sake. Instead of
comparing strings, we compare the hash value of str with that
of a part of this QString. Only if that matches, we call
- ucstrncmp() or ucstrnicmp().
+ qt_string_compare().
*/
const ushort *needle = (const ushort *)needle0;
const ushort *haystack = (const ushort *)haystack0 + from;
@@ -3189,7 +3274,7 @@ int qFindString(
while (haystack <= end) {
hashHaystack += haystack[sl_minus_1];
if (hashHaystack == hashNeedle
- && ucstrncmp((const QChar *)needle, (const QChar *)haystack, sl) == 0)
+ && qt_compare_strings(sv(needle), sv(haystack), Qt::CaseSensitive) == 0)
return haystack - (const ushort *)haystack0;
REHASH(*haystack);
@@ -3205,7 +3290,8 @@ int qFindString(
while (haystack <= end) {
hashHaystack += foldCase(haystack + sl_minus_1, haystack_start);
- if (hashHaystack == hashNeedle && ucstrnicmp(needle, haystack, sl) == 0)
+ if (hashHaystack == hashNeedle
+ && qt_compare_strings(sv(needle), sv(haystack), Qt::CaseInsensitive) == 0)
return haystack - (const ushort *)haystack0;
REHASH(foldCase(haystack, haystack_start));
@@ -3250,6 +3336,8 @@ static int lastIndexOfHelper(const ushort *haystack, int from, const ushort *nee
See indexOf() for explanations.
*/
+ auto sv = [sl](const ushort *v) { return QStringView(v, sl); };
+
const ushort *end = haystack;
haystack += from;
const uint sl_minus_1 = sl - 1;
@@ -3268,7 +3356,7 @@ static int lastIndexOfHelper(const ushort *haystack, int from, const ushort *nee
while (haystack >= end) {
hashHaystack += *haystack;
if (hashHaystack == hashNeedle
- && ucstrncmp((const QChar *)needle, (const QChar *)haystack, sl) == 0)
+ && qt_compare_strings(sv(needle), sv(haystack), Qt::CaseSensitive) == 0)
return haystack - end;
--haystack;
REHASH(haystack[sl]);
@@ -3282,7 +3370,8 @@ static int lastIndexOfHelper(const ushort *haystack, int from, const ushort *nee
while (haystack >= end) {
hashHaystack += foldCase(haystack, end);
- if (hashHaystack == hashNeedle && ucstrnicmp(needle, haystack, sl) == 0)
+ if (hashHaystack == hashNeedle
+ && qt_compare_strings(sv(haystack), sv(needle), Qt::CaseInsensitive) == 0)
return haystack - end;
--haystack;
REHASH(foldCase(haystack + sl, end));
@@ -5277,7 +5366,7 @@ QString& QString::fill(QChar ch, int size)
Equivalent to \c {s1 != 0 && compare(s1, s2) == 0}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -5290,7 +5379,7 @@ QString& QString::fill(QChar ch, int size)
For \a s1 != 0, this is equivalent to \c {compare(} \a s1, \a s2
\c {) != 0}. Note that no string is equal to \a s1 being 0.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -5306,7 +5395,7 @@ QString& QString::fill(QChar ch, int size)
expect. Consider sorting user-interface strings using the
QString::localeAwareCompare() function.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -5322,7 +5411,7 @@ QString& QString::fill(QChar ch, int size)
expect. Consider sorting user-interface strings with
QString::localeAwareCompare().
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -5337,7 +5426,7 @@ QString& QString::fill(QChar ch, int size)
expect. Consider sorting user-interface strings using the
QString::localeAwareCompare() function.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -5418,7 +5507,7 @@ QString& QString::fill(QChar ch, int size)
\snippet qstring/main.cpp 16
- \sa operator==(), operator<(), operator>()
+ \sa qCompareStrings(), operator==(), operator<(), operator>()
*/
/*!
@@ -5428,6 +5517,8 @@ QString& QString::fill(QChar ch, int size)
Performs a comparison of \a s1 and \a s2, using the case
sensitivity setting \a cs.
+
+ \sa qCompareStrings()
*/
/*!
@@ -5438,6 +5529,8 @@ QString& QString::fill(QChar ch, int size)
Performs a comparison of \a s1 and \a s2, using the case
sensitivity setting \a cs.
+
+ \sa qCompareStrings()
*/
@@ -5451,12 +5544,12 @@ QString& QString::fill(QChar ch, int size)
string.
Same as compare(*this, \a other, \a cs).
+
+ \sa qCompareStrings()
*/
int QString::compare(const QString &other, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
{
- if (cs == Qt::CaseSensitive)
- return ucstrcmp(constData(), length(), other.constData(), other.length());
- return ucstricmp(d->data(), d->data() + d->size, other.d->data(), other.d->data() + other.d->size);
+ return qt_compare_strings(*this, other, cs);
}
/*!
@@ -5466,11 +5559,11 @@ int QString::compare(const QString &other, Qt::CaseSensitivity cs) const Q_DECL_
int QString::compare_helper(const QChar *data1, int length1, const QChar *data2, int length2,
Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
- if (cs == Qt::CaseSensitive)
- return ucstrcmp(data1, length1, data2, length2);
- const ushort *s1 = reinterpret_cast<const ushort *>(data1);
- const ushort *s2 = reinterpret_cast<const ushort *>(data2);
- return ucstricmp(s1, s1 + length1, s2, s2 + length2);
+ Q_ASSERT(length1 >= 0);
+ Q_ASSERT(length2 >= 0);
+ Q_ASSERT(data1 || length1 == 0);
+ Q_ASSERT(data2 || length2 == 0);
+ return qt_compare_strings(QStringView(data1, length1), QStringView(data2, length2), cs);
}
/*!
@@ -5478,10 +5571,12 @@ int QString::compare_helper(const QChar *data1, int length1, const QChar *data2,
\since 4.2
Same as compare(*this, \a other, \a cs).
+
+ \sa qCompareStrings()
*/
int QString::compare(QLatin1String other, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
{
- return compare_helper(unicode(), length(), other, cs);
+ return qt_compare_strings(*this, other, cs);
}
/*!
@@ -5491,6 +5586,8 @@ int QString::compare(QLatin1String other, Qt::CaseSensitivity cs) const Q_DECL_N
Compares the string reference, \a ref, with the string and returns
an integer less than, equal to, or greater than zero if the string
is less than, equal to, or greater than \a ref.
+
+ \sa qCompareStrings()
*/
/*!
@@ -5500,6 +5597,8 @@ int QString::compare(QLatin1String other, Qt::CaseSensitivity cs) const Q_DECL_N
int QString::compare_helper(const QChar *data1, int length1, const char *data2, int length2,
Qt::CaseSensitivity cs)
{
+ Q_ASSERT(length1 >= 0);
+ Q_ASSERT(data1 || length1 == 0);
if (!data2)
return length1;
if (Q_UNLIKELY(length2 < 0))
@@ -5508,12 +5607,14 @@ int QString::compare_helper(const QChar *data1, int length1, const char *data2,
QVarLengthArray<ushort> s2(length2);
const auto beg = reinterpret_cast<QChar *>(s2.data());
const auto end = QUtf8::convertToUnicode(beg, data2, length2);
- return compare_helper(data1, length1, beg, end - beg, cs);
+ return qt_compare_strings(QStringView(data1, length1), QStringView(beg, end - beg), cs);
}
/*!
\fn int QString::compare(const QString &s1, const QStringRef &s2, Qt::CaseSensitivity cs = Qt::CaseSensitive)
\overload compare()
+
+ \sa qCompareStrings()
*/
/*!
@@ -5523,18 +5624,9 @@ int QString::compare_helper(const QChar *data1, int length1, const char *data2,
int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2,
Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
- const ushort *uc = reinterpret_cast<const ushort *>(data1);
- const ushort *uce = uc + length1;
- const uchar *c = (const uchar *)s2.latin1();
-
- if (!c)
- return length1;
-
- if (cs == Qt::CaseSensitive) {
- return ucstrcmp(data1, length1, c, s2.size());
- } else {
- return ucstricmp(uc, uce, c, c + s2.size());
- }
+ Q_ASSERT(length1 >= 0);
+ Q_ASSERT(data1 || length1 == 0);
+ return qt_compare_strings(QStringView(data1, length1), s2, cs);
}
/*!
@@ -5620,9 +5712,15 @@ Q_GLOBAL_STATIC(QThreadStorage<QCollator>, defaultCollator)
int QString::localeAwareCompare_helper(const QChar *data1, int length1,
const QChar *data2, int length2)
{
+ Q_ASSERT(length1 >= 0);
+ Q_ASSERT(data1 || length1 == 0);
+ Q_ASSERT(length2 >= 0);
+ Q_ASSERT(data2 || length2 == 0);
+
// do the right thing for null and empty
if (length1 == 0 || length2 == 0)
- return ucstrcmp(data1, length1, data2, length2);
+ return qt_compare_strings(QStringView(data1, length1), QStringView(data2, length2),
+ Qt::CaseSensitive);
#if defined(Q_OS_WIN)
# ifndef Q_OS_WINRT
@@ -5663,10 +5761,12 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
// declared in <string.h>
int delta = strcoll(toLocal8Bit_helper(data1, length1).constData(), toLocal8Bit_helper(data2, length2).constData());
if (delta == 0)
- delta = ucstrcmp(data1, length1, data2, length2);
+ delta = qt_compare_strings(QStringView(data1, length1), QStringView(data2, length2),
+ Qt::CaseSensitive);
return delta;
#else
- return ucstrcmp(data1, length1, data2, length2);
+ return qt_compare_strings(QStringView(data1, length1), QStringView(data2, length2),
+ Qt::CaseSensitive);
#endif
}
@@ -6363,7 +6463,7 @@ qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int b
}
#endif
- return QLocaleData::c()->stringToLongLong(data, len, base, ok, QLocale::RejectGroupSeparator);
+ return QLocaleData::c()->stringToLongLong(QStringView(data, len), base, ok, QLocale::RejectGroupSeparator);
}
@@ -6403,7 +6503,7 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int
}
#endif
- return QLocaleData::c()->stringToUnsLongLong(data, len, base, ok,
+ return QLocaleData::c()->stringToUnsLongLong(QStringView(data, len), base, ok,
QLocale::RejectGroupSeparator);
}
@@ -6605,7 +6705,7 @@ ushort QString::toUShort(bool *ok, int base) const
double QString::toDouble(bool *ok) const
{
- return QLocaleData::c()->stringToDouble(constData(), size(), ok, QLocale::RejectGroupSeparator);
+ return QLocaleData::c()->stringToDouble(*this, ok, QLocale::RejectGroupSeparator);
}
/*!
@@ -8316,6 +8416,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 +8540,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 +8580,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
@@ -9137,8 +9416,8 @@ QString QStringRef::toString() const {
returns \c false.
*/
bool operator==(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW
-{ return (s1.size() == s2.size() &&
- qMemEquals((const ushort *)s1.unicode(), (const ushort *)s2.unicode(), s1.size()));
+{
+ return s1.size() == s2.size() && qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0;
}
/*! \relates QStringRef
@@ -9147,8 +9426,8 @@ bool operator==(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW
returns \c false.
*/
bool operator==(const QString &s1,const QStringRef &s2) Q_DECL_NOTHROW
-{ return (s1.size() == s2.size() &&
- qMemEquals((const ushort *)s1.unicode(), (const ushort *)s2.unicode(), s1.size()));
+{
+ return s1.size() == s2.size() && qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0;
}
/*! \relates QStringRef
@@ -9161,10 +9440,7 @@ bool operator==(QLatin1String s1, const QStringRef &s2) Q_DECL_NOTHROW
if (s1.size() != s2.size())
return false;
- const uchar *c = reinterpret_cast<const uchar *>(s1.latin1());
- if (!c)
- return s2.isEmpty();
- return ucstrncmp(s2.unicode(), c, s2.size()) == 0;
+ return qt_compare_strings(s2, s1, Qt::CaseSensitive) == 0;
}
/*!
@@ -9180,7 +9456,7 @@ bool operator==(QLatin1String s1, const QStringRef &s2) Q_DECL_NOTHROW
*/
bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW
{
- return ucstrcmp(s1.constData(), s1.length(), s2.constData(), s2.length()) < 0;
+ return qt_compare_strings(s1, s2, Qt::CaseSensitive) < 0;
}
/*!\fn bool operator<=(const QStringRef &s1,const QStringRef &s2)
@@ -9411,6 +9687,8 @@ QStringRef QStringRef::appendTo(QString *string) const
If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
otherwise the comparison is case insensitive.
+
+ \sa qCompareStrings()
*/
/*!
@@ -9424,6 +9702,8 @@ QStringRef QStringRef::appendTo(QString *string) const
If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
otherwise the comparison is case insensitive.
+
+ \sa qCompareStrings()
*/
/*!
@@ -9437,6 +9717,8 @@ QStringRef QStringRef::appendTo(QString *string) const
If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
otherwise the comparison is case insensitive.
+
+ \sa qCompareStrings()
*/
/*!
@@ -9453,7 +9735,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -9470,7 +9752,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -9487,7 +9769,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -9505,7 +9787,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -10257,6 +10539,11 @@ static inline int qt_find_latin1_string(const QChar *haystack, int size,
static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
const QChar *needle, int needleLen, Qt::CaseSensitivity cs)
{
+ Q_ASSERT(haystackLen >= 0);
+ Q_ASSERT(haystack || !haystackLen);
+ Q_ASSERT(needleLen >= 0);
+ Q_ASSERT(needle || !needleLen);
+
if (!haystack)
return !needle;
if (haystackLen == 0)
@@ -10264,24 +10551,15 @@ static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
if (needleLen > haystackLen)
return false;
- const ushort *h = reinterpret_cast<const ushort*>(haystack);
- const ushort *n = reinterpret_cast<const ushort*>(needle);
-
- if (cs == Qt::CaseSensitive) {
- return qMemEquals(h, n, needleLen);
- } else {
- uint last = 0;
- uint olast = 0;
- for (int i = 0; i < needleLen; ++i)
- if (foldCase(h[i], last) != foldCase(n[i], olast))
- return false;
- }
- return true;
+ return qt_compare_strings(QStringView(haystack, needleLen), QStringView(needle, needleLen), cs) == 0;
}
static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
QLatin1String needle, Qt::CaseSensitivity cs)
{
+ Q_ASSERT(haystackLen >= 0);
+ Q_ASSERT(haystack || !haystackLen);
+
if (!haystack)
return !needle.latin1();
if (haystackLen == 0)
@@ -10289,21 +10567,18 @@ static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
const int slen = needle.size();
if (slen > haystackLen)
return false;
- const ushort *data = reinterpret_cast<const ushort*>(haystack);
- const uchar *latin = reinterpret_cast<const uchar*>(needle.latin1());
- if (cs == Qt::CaseSensitive) {
- return ucstrncmp(haystack, latin, slen) == 0;
- } else {
- for (int i = 0; i < slen; ++i)
- if (foldCase(data[i]) != foldCase((ushort)latin[i]))
- return false;
- }
- return true;
+
+ return qt_compare_strings(QStringView(haystack, slen), needle, cs) == 0;
}
static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
const QChar *needle, int needleLen, Qt::CaseSensitivity cs)
{
+ Q_ASSERT(haystackLen >= 0);
+ Q_ASSERT(haystack || !haystackLen);
+ Q_ASSERT(needleLen >= 0);
+ Q_ASSERT(needle || !needleLen);
+
if (!haystack)
return !needle;
if (haystackLen == 0)
@@ -10312,25 +10587,17 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
if (pos < 0)
return false;
- const ushort *h = reinterpret_cast<const ushort*>(haystack);
- const ushort *n = reinterpret_cast<const ushort*>(needle);
-
- if (cs == Qt::CaseSensitive) {
- return qMemEquals(h + pos, n, needleLen);
- } else {
- uint last = 0;
- uint olast = 0;
- for (int i = 0; i < needleLen; i++)
- if (foldCase(h[pos+i], last) != foldCase(n[i], olast))
- return false;
- }
- return true;
+ return qt_compare_strings(QStringView(haystack + pos, needleLen),
+ QStringView(needle, needleLen), cs) == 0;
}
static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
QLatin1String needle, Qt::CaseSensitivity cs)
{
+ Q_ASSERT(haystackLen >= 0);
+ Q_ASSERT(haystack || !haystackLen);
+
if (!haystack)
return !needle.latin1();
if (haystackLen == 0)
@@ -10339,16 +10606,8 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
int pos = haystackLen - slen;
if (pos < 0)
return false;
- const uchar *latin = reinterpret_cast<const uchar*>(needle.latin1());
- const ushort *data = reinterpret_cast<const ushort*>(haystack);
- if (cs == Qt::CaseSensitive) {
- return ucstrncmp(haystack + pos, latin, slen) == 0;
- } else {
- for (int i = 0; i < slen; i++)
- if (foldCase(data[pos+i]) != foldCase((ushort)latin[i]))
- return false;
- }
- return true;
+
+ return qt_compare_strings(QStringView(haystack + pos, slen), needle, cs) == 0;
}
/*!
@@ -10709,7 +10968,7 @@ ushort QStringRef::toUShort(bool *ok, int base) const
double QStringRef::toDouble(bool *ok) const
{
- return QLocaleData::c()->stringToDouble(constData(), size(), ok, QLocale::RejectGroupSeparator);
+ return QLocaleData::c()->stringToDouble(*this, ok, QLocale::RejectGroupSeparator);
}
/*!
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 1bd436c387..5110487889 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,8 +87,15 @@ class QString;
class QStringList;
class QTextCodec;
class QStringRef;
+class QStringView;
+class QLatin1String;
template <typename T> class QVector;
+Q_CORE_EXPORT int qCompareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+Q_CORE_EXPORT int qCompareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+Q_CORE_EXPORT int qCompareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+Q_CORE_EXPORT int qCompareStrings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+
class QLatin1String
{
public:
@@ -97,17 +108,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 +688,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 +886,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 +1586,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
@@ -1665,6 +1706,44 @@ inline bool operator> (QLatin1String lhs, QChar rhs) Q_DECL_NOTHROW { return r
inline bool operator<=(QLatin1String lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs < lhs); }
inline bool operator>=(QLatin1String lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs > lhs); }
+// QStringView <> QStringView
+inline bool operator==(QStringView lhs, QStringView rhs) Q_DECL_NOTHROW { return lhs.size() == rhs.size() && qCompareStrings(lhs, rhs) == 0; }
+inline bool operator!=(QStringView lhs, QStringView rhs) Q_DECL_NOTHROW { return !(lhs == rhs); }
+inline bool operator< (QStringView lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) < 0; }
+inline bool operator<=(QStringView lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) <= 0; }
+inline bool operator> (QStringView lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) > 0; }
+inline bool operator>=(QStringView lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) >= 0; }
+
+// QStringView <> QChar
+inline bool operator==(QStringView lhs, QChar rhs) Q_DECL_NOTHROW { return lhs == QStringView(&rhs, 1); }
+inline bool operator!=(QStringView lhs, QChar rhs) Q_DECL_NOTHROW { return lhs != QStringView(&rhs, 1); }
+inline bool operator< (QStringView lhs, QChar rhs) Q_DECL_NOTHROW { return lhs < QStringView(&rhs, 1); }
+inline bool operator<=(QStringView lhs, QChar rhs) Q_DECL_NOTHROW { return lhs <= QStringView(&rhs, 1); }
+inline bool operator> (QStringView lhs, QChar rhs) Q_DECL_NOTHROW { return lhs > QStringView(&rhs, 1); }
+inline bool operator>=(QStringView lhs, QChar rhs) Q_DECL_NOTHROW { return lhs >= QStringView(&rhs, 1); }
+
+inline bool operator==(QChar lhs, QStringView rhs) Q_DECL_NOTHROW { return QStringView(&lhs, 1) == rhs; }
+inline bool operator!=(QChar lhs, QStringView rhs) Q_DECL_NOTHROW { return QStringView(&lhs, 1) != rhs; }
+inline bool operator< (QChar lhs, QStringView rhs) Q_DECL_NOTHROW { return QStringView(&lhs, 1) < rhs; }
+inline bool operator<=(QChar lhs, QStringView rhs) Q_DECL_NOTHROW { return QStringView(&lhs, 1) <= rhs; }
+inline bool operator> (QChar lhs, QStringView rhs) Q_DECL_NOTHROW { return QStringView(&lhs, 1) > rhs; }
+inline bool operator>=(QChar lhs, QStringView rhs) Q_DECL_NOTHROW { return QStringView(&lhs, 1) >= rhs; }
+
+// QStringView <> QLatin1String
+inline bool operator==(QStringView lhs, QLatin1String rhs) Q_DECL_NOTHROW { return lhs.size() == rhs.size() && qCompareStrings(lhs, rhs) == 0; }
+inline bool operator!=(QStringView lhs, QLatin1String rhs) Q_DECL_NOTHROW { return !(lhs == rhs); }
+inline bool operator< (QStringView lhs, QLatin1String rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) < 0; }
+inline bool operator<=(QStringView lhs, QLatin1String rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) <= 0; }
+inline bool operator> (QStringView lhs, QLatin1String rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) > 0; }
+inline bool operator>=(QStringView lhs, QLatin1String rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) >= 0; }
+
+inline bool operator==(QLatin1String lhs, QStringView rhs) Q_DECL_NOTHROW { return lhs.size() == rhs.size() && qCompareStrings(lhs, rhs) == 0; }
+inline bool operator!=(QLatin1String lhs, QStringView rhs) Q_DECL_NOTHROW { return !(lhs == rhs); }
+inline bool operator< (QLatin1String lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) < 0; }
+inline bool operator<=(QLatin1String lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) <= 0; }
+inline bool operator> (QLatin1String lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) > 0; }
+inline bool operator>=(QLatin1String lhs, QStringView rhs) Q_DECL_NOTHROW { return qCompareStrings(lhs, rhs) >= 0; }
+
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
// QStringRef <> QByteArray
inline QT_ASCII_CAST_WARN bool operator==(const QStringRef &lhs, const QByteArray &rhs) { return lhs.compare(rhs) == 0; }
diff --git a/src/corelib/tools/qstringiterator.qdoc b/src/corelib/tools/qstringiterator.qdoc
index ff759b6f0e..ae3ad53653 100644
--- a/src/corelib/tools/qstringiterator.qdoc
+++ b/src/corelib/tools/qstringiterator.qdoc
@@ -55,7 +55,7 @@
that may be present in a QString, and return the individual Unicode code points.
You can create a QStringIterator that iterates over a given
- QString by passing the string to the QStringIterator's constructor:
+ QStringView by passing the string to the QStringIterator's constructor:
\snippet code/src_corelib_tools_qstringiterator.cpp 0
@@ -120,12 +120,12 @@
*/
/*!
- \fn QStringIterator::QStringIterator(const QString &string)
+ \fn QStringIterator::QStringIterator(QStringView string, QStringView::size_type idx)
Constructs an iterator over the contents of \a string. The iterator will point
- before the first position in the string.
+ before position \a idx in the string.
- The string \a string must remain valid while the iterator is being used.
+ The string view \a string must remain valid while the iterator is being used.
*/
/*!
diff --git a/src/corelib/tools/qstringiterator_p.h b/src/corelib/tools/qstringiterator_p.h
index 7cf59ae42f..749ba0e62d 100644
--- a/src/corelib/tools/qstringiterator_p.h
+++ b/src/corelib/tools/qstringiterator_p.h
@@ -60,12 +60,12 @@ QT_BEGIN_NAMESPACE
class QStringIterator
{
QString::const_iterator i, pos, e;
-
+ Q_STATIC_ASSERT((std::is_same<QString::const_iterator, const QChar *>::value));
public:
- inline explicit QStringIterator(const QString &string)
- : i(string.constBegin()),
- pos(string.constBegin()),
- e(string.constEnd())
+ explicit QStringIterator(QStringView string, QStringView::size_type idx = 0)
+ : i(string.begin()),
+ pos(i + idx),
+ e(string.end())
{
}
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..341746e80a
--- /dev/null
+++ b/src/corelib/tools/qstringview.cpp
@@ -0,0 +1,621 @@
+/****************************************************************************
+**
+** 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}, but since it stores data as \c{char16_t}, iteration
+ is not \c constexpr (casts from \c{const char16_t*} to \c{const QChar*}, which is not
+ allowed in \c constexpr functions). You can use an indexed loop and/or utf16() in
+ \c constexpr contexts instead.
+
+ \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 \a
+ str is not an array and 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 (&string)[N])
+
+ Constructs a string view on the character string literal \a string.
+ The length is set to \c{N-1}, excluding the trailing \{Char(0)}.
+ If you need the full array, use the constructor from pointer and
+ size instead:
+
+ \code
+ auto sv = QStringView(array, std::size(array)); // using C++17 std::size()
+ \endcode
+
+ \a string must remain valid for the lifetime of this string view
+ object.
+
+ This constructor only participates in overload resolution if \a
+ string is an actual array and \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.
+
+ \note The character array represented by the return value is \e not null-terminated.
+
+ \sa begin(), end(), utf16()
+*/
+
+/*!
+ \fn const storage_type *QStringView::utf16() const
+
+ Returns a const pointer to the first character in the string.
+
+ \c{storage_type} is \c{char16_t}, except on MSVC 2013 (which lacks \c char16_t support),
+ where it is \c{wchar_t} instead.
+
+ \note The character array represented by the return value is \e not null-terminated.
+
+ \sa begin(), end(), data()
+*/
+
+/*!
+ \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()
+*/
+
+/*!
+ \fn QStringView QStringView::mid(size_type start) const
+
+ Returns the substring starting at position \a start in this object,
+ and extending to the end of the string.
+
+ \note The behavior is undefined when \a start < 0 or \a start > size().
+
+ \sa left(), right()
+*/
+
+/*!
+ \fn QStringView QStringView::mid(size_type start, size_type length) const
+ \overload
+
+ Returns the substring of length \a length starting at position
+ \a start in this object.
+
+ \note The behavior is undefined when \a start < 0, \a length < 0,
+ or \a start + \a length > size().
+
+ \sa left(), right()
+*/
+
+/*!
+ \fn QStringView QStringView::left(size_type length) const
+
+ Returns the substring of length \a length starting at position
+ 0 in this object.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), right()
+*/
+
+/*!
+ \fn QStringView QStringView::right(size_type length) const
+
+ Returns the substring of length \a length starting at position
+ size() - \a length in this object.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), left()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qstringview.h b/src/corelib/tools/qstringview.h
new file mode 100644
index 0000000000..acf05a909c
--- /dev/null
+++ b/src/corelib/tools/qstringview.h
@@ -0,0 +1,269 @@
+/****************************************************************************
+**
+** 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))
+#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 Array>
+struct IsCompatibleArrayHelper : std::false_type {};
+template <typename Char, size_t N>
+struct IsCompatibleArrayHelper<Char[N]>
+ : IsCompatibleCharType<Char> {};
+template <typename Array>
+struct IsCompatibleArray
+ : IsCompatibleArrayHelper<typename std::remove_cv<typename std::remove_reference<Array>::type>::type> {};
+
+template <typename Pointer>
+struct IsCompatiblePointerHelper : std::false_type {};
+template <typename Char>
+struct IsCompatiblePointerHelper<Char*>
+ : IsCompatibleCharType<Char> {};
+template <typename Pointer>
+struct IsCompatiblePointer
+ : IsCompatiblePointerHelper<typename std::remove_cv<typename std::remove_reference<Pointer>::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 Array>
+ using if_compatible_array = typename std::enable_if<QtPrivate::IsCompatibleArray<Array>::value, bool>::type;
+
+ template <typename Pointer>
+ using if_compatible_pointer = typename std::enable_if<QtPrivate::IsCompatiblePointer<Pointer>::value, bool>::type;
+
+ template <typename T>
+ using if_compatible_string = typename std::enable_if<QtPrivate::IsCompatibleStdBasicString<T>::value, bool>::type;
+
+ template <typename T>
+ using if_compatible_qstring_like = typename std::enable_if<std::is_same<T, QString>::value || std::is_same<T, QStringRef>::value, bool>::type;
+
+ template <typename Char, size_t N>
+ static Q_DECL_CONSTEXPR size_type lengthHelperArray(const Char (&)[N]) Q_DECL_NOTHROW
+ {
+ return size_type(N - 1);
+ }
+ template <typename Char>
+ static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelperPointer(const Char *str) Q_DECL_NOTHROW
+ {
+ size_type result = 0;
+ while (*str++)
+ ++result;
+ return result;
+ }
+ static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelperPointer(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; }
+
+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)) {}
+
+#ifdef Q_QDOC
+ template <typename Char, size_t N>
+ Q_DECL_CONSTEXPR QStringView(const Char (&array)[N]) Q_DECL_NOTHROW;
+
+ template <typename Char>
+ Q_DECL_CONSTEXPR QStringView(const Char *str) Q_DECL_NOTHROW;
+#else
+ template <typename Array, if_compatible_array<Array> = true>
+ Q_DECL_CONSTEXPR QStringView(const Array &str) Q_DECL_NOTHROW
+ : QStringView(str, lengthHelperArray(str)) {}
+
+ template <typename Pointer, if_compatible_pointer<Pointer> = true>
+ Q_DECL_CONSTEXPR QStringView(const Pointer &str) Q_DECL_NOTHROW
+ : QStringView(str, str ? lengthHelperPointer(str) : 0) {}
+#endif
+
+#ifdef Q_QDOC
+ QStringView(const QString &str) Q_DECL_NOTHROW;
+ QStringView(const QStringRef &str) Q_DECL_NOTHROW;
+#else
+ template <typename String, if_compatible_qstring_like<String> = true>
+ QStringView(const String &str) Q_DECL_NOTHROW
+ : QStringView(str.isNull() ? nullptr : str.data(), size_type(str.size())) {}
+#endif
+
+ 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]; }
+
+ Q_DECL_CONSTEXPR QStringView mid(size_type pos) const
+ { return Q_ASSERT(pos >= 0), Q_ASSERT(pos <= size()), QStringView(m_data + pos, m_size - pos); }
+ Q_DECL_CONSTEXPR QStringView mid(size_type pos, size_type n) const
+ { return Q_ASSERT(pos >= 0), Q_ASSERT(n >= 0), Q_ASSERT(pos + n <= size()), QStringView(m_data + pos, n); }
+ Q_DECL_CONSTEXPR QStringView left(size_type n) const
+ { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QStringView(m_data, n); }
+ Q_DECL_CONSTEXPR QStringView right(size_type n) const
+ { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QStringView(m_data + m_size - n, 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 a7226f2720..5570ce7571 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 f963e10333..a50227d3cc 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 \