summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/codecs/qtextcodec.cpp49
-rw-r--r--src/corelib/codecs/qtextcodec.h13
-rw-r--r--src/corelib/configure.json30
-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.cpp17
-rw-r--r--src/corelib/doc/snippets/qversionnumber/main.cpp8
-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/qconfig-bootstrapped.h3
-rw-r--r--src/corelib/global/qfloat16.cpp24
-rw-r--r--src/corelib/global/qglobal.cpp56
-rw-r--r--src/corelib/global/qglobal.h34
-rw-r--r--src/corelib/global/qlogging.cpp28
-rw-r--r--src/corelib/global/qnamespace.h2
-rw-r--r--src/corelib/global/qnamespace.qdoc14
-rw-r--r--src/corelib/global/qnumeric.h18
-rw-r--r--src/corelib/global/qnumeric_p.h54
-rw-r--r--src/corelib/global/qtypeinfo.h10
-rw-r--r--src/corelib/io/qabstractfileengine.cpp25
-rw-r--r--src/corelib/io/qabstractfileengine_p.h2
-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/qfiledevice.cpp76
-rw-r--r--src/corelib/io/qfiledevice.h10
-rw-r--r--src/corelib/io/qfileinfo.cpp59
-rw-r--r--src/corelib/io/qfileinfo.h11
-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.cpp17
-rw-r--r--src/corelib/io/qfsfileengine_p.h2
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp228
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp105
-rw-r--r--src/corelib/io/qprocess.cpp71
-rw-r--r--src/corelib/io/qprocess.h1
-rw-r--r--src/corelib/io/qprocess_p.h6
-rw-r--r--src/corelib/io/qprocess_unix.cpp105
-rw-r--r--src/corelib/io/qprocess_win.cpp75
-rw-r--r--src/corelib/io/qresource.cpp57
-rw-r--r--src/corelib/io/qresource_p.h1
-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/qtextstream.cpp3
-rw-r--r--src/corelib/io/qtldurl.cpp42
-rw-r--r--src/corelib/io/qwindowspipereader.cpp13
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.cpp383
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.h4
-rw-r--r--src/corelib/itemmodels/qstringlistmodel.cpp2
-rw-r--r--src/corelib/json/qjsonarray.cpp21
-rw-r--r--src/corelib/json/qjsonarray.h22
-rw-r--r--src/corelib/json/qjsondocument.cpp22
-rw-r--r--src/corelib/json/qjsondocument.h19
-rw-r--r--src/corelib/json/qjsonobject.cpp22
-rw-r--r--src/corelib/json/qjsonobject.h21
-rw-r--r--src/corelib/json/qjsonvalue.cpp26
-rw-r--r--src/corelib/json/qjsonvalue.h25
-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.mm43
-rw-r--r--src/corelib/kernel/qcore_mac_p.h54
-rw-r--r--src/corelib/kernel/qcore_unix_p.h2
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp15
-rw-r--r--src/corelib/kernel/qcoreapplication.h1
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h8
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix_p.h1
-rw-r--r--src/corelib/kernel/qfunctions_fake_env_p.h2
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp6
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h2
-rw-r--r--src/corelib/kernel/qmath.h24
-rw-r--r--src/corelib/kernel/qmath.qdoc19
-rw-r--r--src/corelib/kernel/qmetaobject.cpp99
-rw-r--r--src/corelib/kernel/qmetaobject_p.h3
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp36
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h3
-rw-r--r--src/corelib/kernel/qmetatype.cpp1
-rw-r--r--src/corelib/kernel/qmetatype.h47
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/kernel/qobject.h4
-rw-r--r--src/corelib/kernel/qobject_impl.h78
-rw-r--r--src/corelib/kernel/qobject_p.h3
-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/kernel/qtimer.h8
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp8
-rw-r--r--src/corelib/mimetypes/qmimeprovider_p.h2
-rw-r--r--src/corelib/mimetypes/qmimetype.cpp90
-rw-r--r--src/corelib/mimetypes/qmimetype.h18
-rw-r--r--src/corelib/mimetypes/qmimetypeparser.cpp1
-rw-r--r--src/corelib/plugin/qfactoryloader.cpp8
-rw-r--r--src/corelib/plugin/quuid.cpp215
-rw-r--r--src/corelib/plugin/quuid.h2
-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/thread/qthread.cpp45
-rw-r--r--src/corelib/thread/qthread.h120
-rw-r--r--src/corelib/thread/qthread_p.h4
-rw-r--r--src/corelib/thread/qthread_unix.cpp151
-rw-r--r--src/corelib/thread/qthread_win.cpp4
-rw-r--r--src/corelib/tools/qbytearray.cpp85
-rw-r--r--src/corelib/tools/qbytearray.h85
-rw-r--r--src/corelib/tools/qchar.cpp23
-rw-r--r--src/corelib/tools/qchar.h7
-rw-r--r--src/corelib/tools/qdatetime.cpp51
-rw-r--r--src/corelib/tools/qdatetime.h9
-rw-r--r--src/corelib/tools/qdatetimeparser.cpp306
-rw-r--r--src/corelib/tools/qdatetimeparser_p.h2
-rw-r--r--src/corelib/tools/qhash.cpp142
-rw-r--r--src/corelib/tools/qhash.h11
-rw-r--r--src/corelib/tools/qhashfunctions.h8
-rw-r--r--src/corelib/tools/qiterator.h151
-rw-r--r--src/corelib/tools/qlinkedlist.h4
-rw-r--r--src/corelib/tools/qlist.h6
-rw-r--r--src/corelib/tools/qlocale.cpp372
-rw-r--r--src/corelib/tools/qlocale.h21
-rw-r--r--src/corelib/tools/qlocale_mac.mm4
-rw-r--r--src/corelib/tools/qlocale_p.h59
-rw-r--r--src/corelib/tools/qlocale_win.cpp6
-rw-r--r--src/corelib/tools/qmap.cpp67
-rw-r--r--src/corelib/tools/qmap.h10
-rw-r--r--src/corelib/tools/qpodlist_p.h109
-rw-r--r--src/corelib/tools/qregularexpression.cpp172
-rw-r--r--src/corelib/tools/qregularexpression.h15
-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.cpp1410
-rw-r--r--src/corelib/tools/qstring.h243
-rw-r--r--src/corelib/tools/qstringalgorithms.h82
-rw-r--r--src/corelib/tools/qstringalgorithms_p.h8
-rw-r--r--src/corelib/tools/qstringbuilder.h7
-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/qstringliteral.h128
-rw-r--r--src/corelib/tools/qstringview.cpp777
-rw-r--r--src/corelib/tools/qstringview.h305
-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.h5
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc6
-rw-r--r--src/corelib/tools/qvector.h9
-rw-r--r--src/corelib/tools/qvector.qdoc7
-rw-r--r--src/corelib/tools/qversionnumber.cpp53
-rw-r--r--src/corelib/tools/qversionnumber.h4
-rw-r--r--src/corelib/tools/tools.pri5
-rw-r--r--src/corelib/xml/qxmlstream.cpp17
-rw-r--r--src/corelib/xml/qxmlstream.g62
-rw-r--r--src/corelib/xml/qxmlstream_p.h30
-rw-r--r--src/corelib/xml/qxmlutils.cpp37
-rw-r--r--src/corelib/xml/qxmlutils_p.h7
158 files changed, 6806 insertions, 1881 deletions
diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp
index aed3532024..4f0cd914ca 100644
--- a/src/corelib/codecs/qtextcodec.cpp
+++ b/src/corelib/codecs/qtextcodec.cpp
@@ -43,6 +43,7 @@
#ifndef QT_NO_TEXTCODEC
+#include "qbytearraymatcher.h"
#include "qlist.h"
#include "qfile.h"
#include "qstringlist.h"
@@ -803,6 +804,7 @@ QTextEncoder* QTextCodec::makeEncoder(QTextCodec::ConversionFlags flags) const
The \a state of the convertor used is updated.
*/
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Converts \a str from Unicode to the encoding of this codec, and
returns the result in a QByteArray.
@@ -811,6 +813,19 @@ QByteArray QTextCodec::fromUnicode(const QString& str) const
{
return convertFromUnicode(str.constData(), str.length(), 0);
}
+#endif
+
+/*!
+ \overload
+ \since 5.10
+
+ Converts \a str from Unicode to the encoding of this codec, and
+ returns the result in a QByteArray.
+*/
+QByteArray QTextCodec::fromUnicode(QStringView str) const
+{
+ return convertFromUnicode(str.data(), str.length(), nullptr);
+}
/*!
\fn QString QTextCodec::toUnicode(const char *input, int size,
@@ -844,6 +859,7 @@ bool QTextCodec::canEncode(QChar ch) const
return (state.invalidChars == 0);
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
\overload
@@ -856,7 +872,22 @@ bool QTextCodec::canEncode(const QString& s) const
convertFromUnicode(s.constData(), s.length(), &state);
return (state.invalidChars == 0);
}
+#endif
+
+/*!
+ \overload
+ \since 5.10
+ Returns \c true if the Unicode string \a s can be fully encoded
+ with this codec; otherwise returns \c false.
+*/
+bool QTextCodec::canEncode(QStringView s) const
+{
+ ConverterState state;
+ state.flags = ConvertInvalidToNull;
+ convertFromUnicode(s.data(), s.length(), &state);
+ return !state.invalidChars;
+}
/*!
\overload
@@ -921,6 +952,7 @@ bool QTextEncoder::hasFailure() const
return state.invalidChars != 0;
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Converts the Unicode string \a str into an encoded QByteArray.
*/
@@ -929,6 +961,17 @@ QByteArray QTextEncoder::fromUnicode(const QString& str)
QByteArray result = c->fromUnicode(str.constData(), str.length(), &state);
return result;
}
+#endif
+
+/*!
+ \overload
+ \since 5.10
+ Converts the Unicode string \a str into an encoded QByteArray.
+*/
+QByteArray QTextEncoder::fromUnicode(QStringView str)
+{
+ return c->fromUnicode(str.data(), str.length(), &state);
+}
/*!
\overload
@@ -1050,10 +1093,12 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo
// determine charset
QTextCodec *c = QTextCodec::codecForUtfText(ba, 0);
if (!c) {
+ static Q_RELAXED_CONSTEXPR auto matcher = qMakeStaticByteArrayMatcher("meta ");
QByteArray header = ba.left(1024).toLower();
- int pos = header.indexOf("meta ");
+ int pos = matcher.indexIn(header);
if (pos != -1) {
- pos = header.indexOf("charset=", pos);
+ static Q_RELAXED_CONSTEXPR auto matcher = qMakeStaticByteArrayMatcher("charset=");
+ pos = matcher.indexIn(header, pos);
if (pos != -1) {
pos += qstrlen("charset=");
diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h
index 47b2fe6eed..5163d37238 100644
--- a/src/corelib/codecs/qtextcodec.h
+++ b/src/corelib/codecs/qtextcodec.h
@@ -79,11 +79,17 @@ public:
static QTextCodec *codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec);
bool canEncode(QChar) const;
+#if QT_STRINGVIEW_LEVEL < 2
bool canEncode(const QString&) const;
+#endif
+ bool canEncode(QStringView) const;
QString toUnicode(const QByteArray&) const;
QString toUnicode(const char* chars) const;
+#if QT_STRINGVIEW_LEVEL < 2
QByteArray fromUnicode(const QString& uc) const;
+#endif
+ QByteArray fromUnicode(QStringView uc) const;
enum ConversionFlag {
DefaultConversion,
ConvertInvalidToNull = 0x80000000,
@@ -133,9 +139,12 @@ class Q_CORE_EXPORT QTextEncoder {
Q_DISABLE_COPY(QTextEncoder)
public:
explicit QTextEncoder(const QTextCodec *codec) : c(codec), state() {}
- QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags);
+ explicit QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags);
~QTextEncoder();
+#if QT_STRINGVIEW_LEVEL < 2
QByteArray fromUnicode(const QString& str);
+#endif
+ QByteArray fromUnicode(QStringView str);
QByteArray fromUnicode(const QChar *uc, int len);
bool hasFailure() const;
private:
@@ -147,7 +156,7 @@ class Q_CORE_EXPORT QTextDecoder {
Q_DISABLE_COPY(QTextDecoder)
public:
explicit QTextDecoder(const QTextCodec *codec) : c(codec), state() {}
- QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags);
+ explicit QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags);
~QTextDecoder();
QString toUnicode(const char* chars, int len);
QString toUnicode(const QByteArray &ba);
diff --git a/src/corelib/configure.json b/src/corelib/configure.json
index c6c5c93ddb..0e9830c5e2 100644
--- a/src/corelib/configure.json
+++ b/src/corelib/configure.json
@@ -139,6 +139,21 @@
"type": "compile",
"test": "unix/eventfd"
},
+ "futimens": {
+ "label": "futimens()",
+ "type": "compile",
+ "test": "unix/futimens"
+ },
+ "futimes": {
+ "label": "futimes()",
+ "type": "compile",
+ "test": "unix/futimes"
+ },
+ "futimesat": {
+ "label": "futimesat()",
+ "type": "compile",
+ "test": "unix/futimesat"
+ },
"posix-iconv": {
"label": "POSIX iconv",
"type": "compile",
@@ -228,6 +243,21 @@
"condition": "tests.eventfd",
"output": [ "feature" ]
},
+ "futimens": {
+ "label": "futimens()",
+ "condition": "!config.win32 && tests.futimens",
+ "output": [ "privateFeature" ]
+ },
+ "futimes": {
+ "label": "futimes()",
+ "condition": "!config.win32 && !features.futimens && tests.futimes",
+ "output": [ "privateFeature" ]
+ },
+ "futimesat": {
+ "label": "futimesat()",
+ "condition": "!config.win32 && !features.futimens && !features.futimes && tests.futimesat",
+ "output": [ "privateFeature" ]
+ },
"glib": {
"label": "GLib",
"autoDetect": "!config.win32",
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..3a6f6483fb 100644
--- a/src/corelib/doc/snippets/qstring/main.cpp
+++ b/src/corelib/doc/snippets/qstring/main.cpp
@@ -262,6 +262,17 @@ void Widget::argFunction()
.arg(i).arg(total).arg(fileName);
//! [11]
+ {
+ //! [11]
+ int i; // current file's number
+ int total; // number of files to process
+ QStringView fileName; // current file's name
+
+ QString status = QString("Processing file %1 of %2: %3")
+ .arg(i).arg(total).arg(fileName);
+ //! [11]
+ }
+
//! [12] //! [13]
QString str;
//! [12]
@@ -321,6 +332,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/qversionnumber/main.cpp b/src/corelib/doc/snippets/qversionnumber/main.cpp
index 0e9997b6dc..27b7b1a7ef 100644
--- a/src/corelib/doc/snippets/qversionnumber/main.cpp
+++ b/src/corelib/doc/snippets/qversionnumber/main.cpp
@@ -95,6 +95,14 @@ void QObject::parse()
// version is 5.4.0
// suffixIndex is 5
//! [3]
+
+ //! [3-latin1-1]
+ QLatin1String string("5.4.0-alpha");
+ int suffixIndex;
+ auto version = QVersionNumber::fromString(string, &suffixIndex);
+ // version is 5.4.0
+ // suffixIndex is 5
+ //! [3-latin1-1]
}
void Object::equivalent()
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/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h
index 0b02ecc8ec..374b53a9b5 100644
--- a/src/corelib/global/qconfig-bootstrapped.h
+++ b/src/corelib/global/qconfig-bootstrapped.h
@@ -78,6 +78,9 @@
#define QT_FEATURE_iconv -1
#define QT_FEATURE_icu -1
#define QT_FEATURE_journald -1
+#define QT_FEATURE_futimens -1
+#define QT_FEATURE_futimes -1
+#define QT_FEATURE_futimesat -1
#define QT_FEATURE_library -1
#define QT_NO_QOBJECT
#define QT_FEATURE_process -1
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
index 1de1ae65fb..89edfc8787 100644
--- a/src/corelib/global/qfloat16.cpp
+++ b/src/corelib/global/qfloat16.cpp
@@ -41,7 +41,11 @@
QT_BEGIN_NAMESPACE
-/*! \headerfile <QFloat16>
+/*!
+ \headerfile <QFloat16>
+ \title 16-bit Floating Point Support
+ \ingroup funclists
+ \brief The <QFloat16> header file provides 16-bit floating point support.
This header file provides support for half-precision (16-bit) floating
point data with the class \c qfloat16. It is fully compliant with IEEE
@@ -59,24 +63,6 @@ QT_BEGIN_NAMESPACE
\since 5.9
*/
-Q_STATIC_ASSERT_X(sizeof(float) == sizeof(quint32),
- "qfloat16 assumes that floats are 32 bits wide");
-
-// There are a few corner cases regarding denormals where GHS compiler is relying
-// hardware behavior that is not IEC 559 compliant. Therefore the compiler
-// reports std::numeric_limits<float>::is_iec559 as false. This is all right
-// according to our needs.
-
-#if !defined(Q_CC_GHS)
-Q_STATIC_ASSERT_X(std::numeric_limits<float>::is_iec559,
- "Only works with IEEE 754 floating point");
-#endif
-
-Q_STATIC_ASSERT_X(std::numeric_limits<float>::has_infinity &&
- std::numeric_limits<float>::has_quiet_NaN &&
- std::numeric_limits<float>::has_signaling_NaN,
- "Only works with IEEE 754 floating point");
-
/*!
Returns true if the \c qfloat16 \a {f} is equivalent to infinity.
\relates <QFloat16>
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 22fc20d47e..ea9d207177 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -112,6 +112,38 @@ Q_CORE_EXPORT void *qMemSet(void *dest, int c, size_t n);
Q_STATIC_ASSERT_X(sizeof(int) == 4, "Qt assumes that int is 32 bits");
Q_STATIC_ASSERT_X(UCHAR_MAX == 255, "Qt assumes that char is 8 bits");
Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined incorrectly");
+Q_STATIC_ASSERT_X(sizeof(float) == 4, "Qt assumes that float is 32 bits");
+
+// While we'd like to check for __STDC_IEC_559__, as per ISO/IEC 9899:2011
+// Annex F (C11, normative for C++11), there are a few corner cases regarding
+// denormals where GHS compiler is relying hardware behavior that is not IEC
+// 559 compliant. So split the check in several subchecks.
+
+// On GHC the compiler reports std::numeric_limits<float>::is_iec559 as false.
+// This is all right according to our needs.
+#if !defined(Q_CC_GHS)
+Q_STATIC_ASSERT_X(std::numeric_limits<float>::is_iec559,
+ "Qt assumes IEEE 754 floating point");
+#endif
+
+// Technically, presence of NaN and infinities are implied from the above check,
+// but double checking our environment doesn't hurt...
+Q_STATIC_ASSERT_X(std::numeric_limits<float>::has_infinity &&
+ std::numeric_limits<float>::has_quiet_NaN &&
+ std::numeric_limits<float>::has_signaling_NaN,
+ "Qt assumes IEEE 754 floating point");
+
+// is_iec559 checks for ISO/IEC/IEEE 60559:2011 (aka IEEE 754-2008) compliance,
+// but that allows for a non-binary radix. We need to recheck that.
+// Note how __STDC_IEC_559__ would instead check for IEC 60559:1989, aka
+// ANSI/IEEE 754−1985, which specifically implies binary floating point numbers.
+Q_STATIC_ASSERT_X(std::numeric_limits<float>::radix == 2,
+ "Qt assumes binary IEEE 754 floating point");
+
+// not required by the definition of size_t, but we depend on this
+Q_STATIC_ASSERT_X(sizeof(size_t) == sizeof(void *), "size_t and a pointer don't have the same size");
+Q_STATIC_ASSERT(sizeof(size_t) == sizeof(qssize_t)); // implied by the definition
+Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
/*!
\class QFlag
@@ -774,6 +806,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>
@@ -3058,7 +3105,7 @@ void qt_assert_x(const char *where, const char *what, const char *file, int line
Deliberately not exported as part of the Qt API, but used in both
qsimplerichtext.cpp and qgfxraster_qws.cpp
*/
-Q_CORE_EXPORT unsigned int qt_int_sqrt(unsigned int n)
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
{
// n must be in the range 0...UINT_MAX/2-1
if (n >= (UINT_MAX>>2)) {
@@ -4429,8 +4476,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 79053329a1..cfc6ef8b16 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -355,7 +355,7 @@ typedef double qreal;
#if !defined(QT_NAMESPACE) && defined(__cplusplus) && !defined(Q_QDOC)
extern "C"
#endif
-Q_CORE_EXPORT const char *qVersion() Q_DECL_NOTHROW;
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION const char *qVersion() Q_DECL_NOTHROW;
#if defined(__cplusplus)
@@ -436,6 +436,9 @@ namespace QtPrivate {
sizeof(void *) == sizeof(quintptr)
&& sizeof(void *) == sizeof(qptrdiff)
+
+ size_t and qssize_t are not guaranteed to be the same size as a pointer, but
+ they usually are.
*/
template <int> struct QIntegerForSize;
template <> struct QIntegerForSize<1> { typedef quint8 Unsigned; typedef qint8 Signed; };
@@ -451,6 +454,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 +616,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
/*
@@ -655,7 +671,7 @@ Q_NORETURN Q_CORE_EXPORT void qTerminate() Q_DECL_NOTHROW;
# endif
#endif
-Q_CORE_EXPORT bool qSharedBuild() Q_DECL_NOTHROW;
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qSharedBuild() Q_DECL_NOTHROW;
#ifndef Q_OUTOFLINE_TEMPLATE
# define Q_OUTOFLINE_TEMPLATE
@@ -704,9 +720,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 +737,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
@@ -910,13 +926,9 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic
# endif
#endif
-namespace QtPrivate {
-template <typename T> struct QAddConst { typedef const T Type; };
-}
-
// this adds const to non-const objects (like std::as_const)
template <typename T>
-Q_DECL_CONSTEXPR typename QtPrivate::QAddConst<T>::Type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
+Q_DECL_CONSTEXPR typename std::add_const<T>::type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
// prevent rvalue arguments:
template <typename T>
void qAsConst(const T &&) Q_DECL_EQ_DELETE;
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 6a91b2cfd0..a52f0de9f0 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..9056eab2f1 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -508,6 +508,8 @@ public:
AA_CompressHighFrequencyEvents = 25,
AA_DontCheckOpenGLContextThreadAffinity = 26,
AA_DisableShaderDiskCache = 27,
+ AA_DontShowShortcutsInContextMenus = 28,
+ AA_CompressTabletEvents = 29,
// Add new attributes before this line
AA_AttributeCount
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index c030baa05c..076b006235 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
@@ -245,7 +250,14 @@
(In the future, the compression feature may be implemented across platforms.)
You can test the attribute to see whether compression is enabled.
If your application needs to handle all events with no compression,
- you can unset this attribute. This value has been added in Qt 5.7.
+ you can unset this attribute. Notice that input events from tablet devices
+ will not be compressed. See AA_CompressTabletEvents if you want these to be
+ compressed as well. This value has been added in Qt 5.7.
+
+ \value AA_CompressTabletEvents Enables compression of input events from tablet devices.
+ Notice that AA_CompressHighFrequencyEvents must be true for events compression
+ to be enabled, and that this flag extends the former to tablet events. Its default
+ value is false. This value has been added in Qt 5.10.
\value AA_DontCheckOpenGLContextThreadAffinity When making a context
current using QOpenGLContext, do not check that the
diff --git a/src/corelib/global/qnumeric.h b/src/corelib/global/qnumeric.h
index 80be984bef..535a96aaec 100644
--- a/src/corelib/global/qnumeric.h
+++ b/src/corelib/global/qnumeric.h
@@ -45,15 +45,15 @@
QT_BEGIN_NAMESPACE
-Q_CORE_EXPORT bool qIsInf(double d);
-Q_CORE_EXPORT bool qIsNaN(double d);
-Q_CORE_EXPORT bool qIsFinite(double d);
-Q_CORE_EXPORT bool qIsInf(float f);
-Q_CORE_EXPORT bool qIsNaN(float f);
-Q_CORE_EXPORT bool qIsFinite(float f);
-Q_CORE_EXPORT double qSNaN();
-Q_CORE_EXPORT double qQNaN();
-Q_CORE_EXPORT double qInf();
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
Q_CORE_EXPORT quint32 qFloatDistance(float a, float b);
Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 2291675501..37eddfa9b5 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -73,12 +73,12 @@
QT_BEGIN_NAMESPACE
namespace qnumeric_std_wrapper {
// the 'using namespace std' below is cases where the stdlib already put the math.h functions in the std namespace and undefined the macros.
-static inline bool math_h_isnan(double d) { using namespace std; return isnan(d); }
-static inline bool math_h_isinf(double d) { using namespace std; return isinf(d); }
-static inline bool math_h_isfinite(double d) { using namespace std; return isfinite(d); }
-static inline bool math_h_isnan(float f) { using namespace std; return isnan(f); }
-static inline bool math_h_isinf(float f) { using namespace std; return isinf(f); }
-static inline bool math_h_isfinite(float f) { using namespace std; return isfinite(f); }
+Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(double d) { using namespace std; return isnan(d); }
+Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(double d) { using namespace std; return isinf(d); }
+Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(double d) { using namespace std; return isfinite(d); }
+Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(float f) { using namespace std; return isnan(f); }
+Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(float f) { using namespace std; return isinf(f); }
+Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(float f) { using namespace std; return isfinite(f); }
}
QT_END_NAMESPACE
// These macros from math.h conflict with the real functions in the std namespace.
@@ -94,23 +94,23 @@ QT_BEGIN_NAMESPACE
namespace qnumeric_std_wrapper {
#if defined(QT_MATH_H_DEFINES_MACROS)
# undef QT_MATH_H_DEFINES_MACROS
-static inline bool isnan(double d) { return math_h_isnan(d); }
-static inline bool isinf(double d) { return math_h_isinf(d); }
-static inline bool isfinite(double d) { return math_h_isfinite(d); }
-static inline bool isnan(float f) { return math_h_isnan(f); }
-static inline bool isinf(float f) { return math_h_isinf(f); }
-static inline bool isfinite(float f) { return math_h_isfinite(f); }
+Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return math_h_isnan(d); }
+Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return math_h_isinf(d); }
+Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return math_h_isfinite(d); }
+Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return math_h_isnan(f); }
+Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return math_h_isinf(f); }
+Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return math_h_isfinite(f); }
#else
-static inline bool isnan(double d) { return std::isnan(d); }
-static inline bool isinf(double d) { return std::isinf(d); }
-static inline bool isfinite(double d) { return std::isfinite(d); }
-static inline bool isnan(float f) { return std::isnan(f); }
-static inline bool isinf(float f) { return std::isinf(f); }
-static inline bool isfinite(float f) { return std::isfinite(f); }
+Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return std::isnan(d); }
+Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return std::isinf(d); }
+Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return std::isfinite(d); }
+Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return std::isnan(f); }
+Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return std::isinf(f); }
+Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return std::isfinite(f); }
#endif
}
-Q_DECL_CONSTEXPR static inline double qt_inf() Q_DECL_NOEXCEPT
+Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_inf() Q_DECL_NOEXCEPT
{
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_infinity,
"platform has no definition for infinity for type double");
@@ -118,7 +118,7 @@ Q_DECL_CONSTEXPR static inline double qt_inf() Q_DECL_NOEXCEPT
}
// Signaling NaN
-Q_DECL_CONSTEXPR static inline double qt_snan() Q_DECL_NOEXCEPT
+Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_snan() Q_DECL_NOEXCEPT
{
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_signaling_NaN,
"platform has no definition for signaling NaN for type double");
@@ -126,39 +126,39 @@ Q_DECL_CONSTEXPR static inline double qt_snan() Q_DECL_NOEXCEPT
}
// Quiet NaN
-Q_DECL_CONSTEXPR static inline double qt_qnan() Q_DECL_NOEXCEPT
+Q_DECL_CONSTEXPR Q_DECL_CONST_FUNCTION static inline double qt_qnan() Q_DECL_NOEXCEPT
{
Q_STATIC_ASSERT_X(std::numeric_limits<double>::has_quiet_NaN,
"platform has no definition for quiet NaN for type double");
return std::numeric_limits<double>::quiet_NaN();
}
-static inline bool qt_is_inf(double d)
+Q_DECL_CONST_FUNCTION static inline bool qt_is_inf(double d)
{
return qnumeric_std_wrapper::isinf(d);
}
-static inline bool qt_is_nan(double d)
+Q_DECL_CONST_FUNCTION static inline bool qt_is_nan(double d)
{
return qnumeric_std_wrapper::isnan(d);
}
-static inline bool qt_is_finite(double d)
+Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(double d)
{
return qnumeric_std_wrapper::isfinite(d);
}
-static inline bool qt_is_inf(float f)
+Q_DECL_CONST_FUNCTION static inline bool qt_is_inf(float f)
{
return qnumeric_std_wrapper::isinf(f);
}
-static inline bool qt_is_nan(float f)
+Q_DECL_CONST_FUNCTION static inline bool qt_is_nan(float f)
{
return qnumeric_std_wrapper::isnan(f);
}
-static inline bool qt_is_finite(float f)
+Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f)
{
return qnumeric_std_wrapper::isfinite(f);
}
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..85dc2f33a2 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -727,6 +727,18 @@ QString QAbstractFileEngine::owner(FileOwner owner) const
}
/*!
+ \fn bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+
+ \since 5.10
+ Sets the file \a time to \a newDate, returning true if successful;
+ otherwise returns false.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa fileTime()
+*/
+
+/*!
If \a time is \c CreationTime, return when the file was created.
If \a time is \c ModificationTime, return when the file was most
recently modified. If \a time is \c AccessTime, return when the
@@ -832,6 +844,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..9d0a101b49 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -144,9 +144,11 @@ public:
virtual QString fileName(FileName file=DefaultName) const;
virtual uint ownerId(FileOwner) const;
virtual QString owner(FileOwner) const;
+ virtual bool setFileTime(const QDateTime &newDate, FileTime time) = 0;
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 9a42fb4a37..9044ad74b1 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 575607e147..0a429d091a 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 186722b69b..ee8ef679a9 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 06d706b915..ddd343b515 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/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index 715dc7293a..8533602d63 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -738,6 +738,82 @@ bool QFileDevice::unmap(uchar *address)
return false;
}
+/*!
+ \enum QFileDevice::FileTime
+ \since 5.10
+
+ This enum is used by the fileTime() and setFileTime() functions.
+
+ \value FileCreationTime When the file was created (not supported on UNIX).
+ \value FileModificationTime When the file was most recently modified.
+ \value FileAccessTime When the file was most recently accessed (e.g.
+ read or written to).
+
+ \sa setFileName(), fileTime()
+*/
+
+static inline QAbstractFileEngine::FileTime FileDeviceTimeToAbstractFileEngineTime(QFileDevice::FileTime time)
+{
+ switch (time) {
+ case QFileDevice::FileAccessTime:
+ return QAbstractFileEngine::AccessTime;
+
+ case QFileDevice::FileCreationTime:
+ return QAbstractFileEngine::CreationTime;
+
+ case QFileDevice::FileModificationTime:
+ return QAbstractFileEngine::ModificationTime;
+ }
+
+ Q_UNREACHABLE();
+ return QAbstractFileEngine::AccessTime;
+}
+
+/*!
+ \since 5.10
+ Returns the file time specified by \a time.
+ If the time cannot be determined return QDateTime() (an invalid
+ date time).
+
+ \sa setFileName(), FileTime, QDateTime::isValid()
+*/
+QDateTime QFileDevice::fileTime(QFileDevice::FileTime time) const
+{
+ Q_D(const QFileDevice);
+
+ if (d->engine())
+ return d->engine()->fileTime(FileDeviceTimeToAbstractFileEngineTime(time));
+
+ return QDateTime();
+}
+
+/*!
+ \since 5.10
+ Sets the file \a time to \a newDate, returning true if successful;
+ otherwise returns false.
+
+ \note The file must be open to use this function.
+
+ \sa fileTime(), FileTime
+*/
+bool QFileDevice::setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime)
+{
+ Q_D(QFileDevice);
+
+ if (!d->engine()) {
+ d->setError(QFileDevice::UnspecifiedError, tr("No file engine available"));
+ return false;
+ }
+
+ if (!d->fileEngine->setFileTime(newDate, FileDeviceTimeToAbstractFileEngineTime(fileTime))) {
+ d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+ return false;
+ }
+
+ unsetError();
+ return true;
+}
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfiledevice.h b/src/corelib/io/qfiledevice.h
index 4cfda1b044..3519a049a9 100644
--- a/src/corelib/io/qfiledevice.h
+++ b/src/corelib/io/qfiledevice.h
@@ -45,6 +45,7 @@
QT_BEGIN_NAMESPACE
+class QDateTime;
class QFileDevicePrivate;
class Q_CORE_EXPORT QFileDevice : public QIODevice
@@ -73,6 +74,12 @@ public:
CopyError = 14
};
+ enum FileTime {
+ FileCreationTime,
+ FileModificationTime,
+ FileAccessTime
+ };
+
enum Permission {
ReadOwner = 0x4000, WriteOwner = 0x2000, ExeOwner = 0x1000,
ReadUser = 0x0400, WriteUser = 0x0200, ExeUser = 0x0100,
@@ -119,6 +126,9 @@ public:
uchar *map(qint64 offset, qint64 size, MemoryMapFlags flags = NoOptions);
bool unmap(uchar *address);
+ QDateTime fileTime(QFileDevice::FileTime time) const;
+ bool setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime);
+
protected:
QFileDevice();
#ifdef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 12fd7d3048..baac3117ea 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -42,6 +42,7 @@
#include "qglobal.h"
#include "qdir.h"
#include "qfileinfo_p.h"
+#include "qdebug.h"
QT_BEGIN_NAMESPACE
@@ -262,8 +263,8 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
info objects, just append one to the file name given to the constructors
or setFile().
- The file's dates are returned by created(), lastModified() and
- lastRead(). Information about the file's access permissions is
+ The file's dates are returned by created(), lastModified(), lastRead() and
+ fileTime(). Information about the file's access permissions is
obtained with isReadable(), isWritable() and isExecutable(). The
file's ownership is available from owner(), ownerId(), group() and
groupId(). You can examine a file's permissions and ownership in a
@@ -1324,7 +1325,7 @@ QDateTime QFileInfo::created() const
/*!
Returns the date and local time when the file was last modified.
- \sa created(), lastRead()
+ \sa created(), lastRead(), fileTime()
*/
QDateTime QFileInfo::lastModified() const
{
@@ -1346,7 +1347,7 @@ QDateTime QFileInfo::lastModified() const
On platforms where this information is not available, returns the
same as lastModified().
- \sa created(), lastModified()
+ \sa created(), lastModified(), fileTime()
*/
QDateTime QFileInfo::lastRead() const
{
@@ -1363,6 +1364,45 @@ QDateTime QFileInfo::lastRead() const
}
/*!
+ \enum QFileInfo::FileTime
+ \since 5.10
+
+ This enum is used by the fileTime() function.
+
+ \value FileCreationTime When the file was created (not supported on UNIX).
+ \value FileModificationTime When the file was most recently modified.
+ \value FileAccessTime When the file was most recently accessed (e.g.
+ read or written to).
+
+ \sa fileTime()
+*/
+
+/*!
+ \since 5.10
+ Returns the file time specified by \a time.
+ If the time cannot be determined return QDateTime() (an invalid
+ date time).
+
+ \sa FileTime, QDateTime::isValid()
+*/
+QDateTime QFileInfo::fileTime(QFileInfo::FileTime time) const
+{
+ switch (time) {
+ case QFileInfo::FileCreationTime:
+ return created();
+
+ case QFileInfo::FileModificationTime:
+ return lastModified();
+
+ case QFileInfo::FileAccessTime:
+ return lastRead();
+
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+/*!
\internal
*/
QFileInfoPrivate* QFileInfo::d_func()
@@ -1406,4 +1446,15 @@ void QFileInfo::setCaching(bool enable)
Synonym for QList<QFileInfo>.
*/
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QFileInfo &fi)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg.noquote();
+ dbg << "QFileInfo(" << QDir::toNativeSeparators(fi.filePath()) << ')';
+ return dbg;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index a160e8463e..d212b6dac2 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -57,6 +57,12 @@ class Q_CORE_EXPORT QFileInfo
{
friend class QDirIteratorPrivate;
public:
+ enum FileTime {
+ FileCreationTime,
+ FileModificationTime,
+ FileAccessTime
+ };
+
explicit QFileInfo(QFileInfoPrivate *d);
QFileInfo();
@@ -132,6 +138,7 @@ public:
QDateTime created() const;
QDateTime lastModified() const;
QDateTime lastRead() const;
+ QDateTime fileTime(QFileInfo::FileTime time) const;
bool caching() const;
void setCaching(bool on);
@@ -151,6 +158,10 @@ Q_DECLARE_SHARED(QFileInfo)
typedef QList<QFileInfo> QFileInfoList;
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QFileInfo &);
+#endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QFileInfo)
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index e195afdae9..929db259ec 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -43,6 +43,7 @@
#include "qfilesystemengine_p.h"
#include "qfile.h"
+#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qvarlengtharray.h>
#include <stdlib.h> // for realpath()
@@ -67,6 +68,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);
@@ -642,8 +646,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..75478f0467 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)
@@ -890,6 +899,10 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
+/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+ \reimp
+*/
+
/*! \fn QDateTime QFSFileEngine::fileTime(FileTime time) const
\reimp
*/
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index 593ecc2687..80dd9363db 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -96,6 +96,7 @@ public:
QString fileName(FileName file) const Q_DECL_OVERRIDE;
uint ownerId(FileOwner) const Q_DECL_OVERRIDE;
QString owner(FileOwner) const Q_DECL_OVERRIDE;
+ bool setFileTime(const QDateTime &newDate, FileTime time) Q_DECL_OVERRIDE;
QDateTime fileTime(FileTime time) const Q_DECL_OVERRIDE;
void setFileName(const QString &file) Q_DECL_OVERRIDE;
int handle() const Q_DECL_OVERRIDE;
@@ -108,6 +109,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..4617d09874 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");
@@ -151,6 +100,44 @@ static inline QString msgOpenDirectory()
#endif
}
+#if !QT_CONFIG(futimens) && (QT_CONFIG(futimes) || QT_CONFIG(futimesat))
+namespace {
+namespace GetFileTimes {
+
+template <typename T>
+static inline typename QtPrivate::QEnableIf<(&T::st_atim, &T::st_mtim, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification)
+{
+ access->tv_sec = p->st_atim.tv_sec;
+ access->tv_usec = p->st_atim.tv_nsec / 1000;
+
+ modification->tv_sec = p->st_mtim.tv_sec;
+ modification->tv_usec = p->st_mtim.tv_nsec / 1000;
+}
+
+template <typename T>
+static inline typename QtPrivate::QEnableIf<(&T::st_atimespec, &T::st_mtimespec, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification)
+{
+ access->tv_sec = p->st_atimespec.tv_sec;
+ access->tv_usec = p->st_atimespec.tv_nsec / 1000;
+
+ modification->tv_sec = p->st_mtimespec.tv_sec;
+ modification->tv_usec = p->st_mtimespec.tv_nsec / 1000;
+}
+
+template <typename T>
+static inline typename QtPrivate::QEnableIf<(&T::st_atimensec, &T::st_mtimensec, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification)
+{
+ access->tv_sec = p->st_atime;
+ access->tv_usec = p->st_atimensec / 1000;
+
+ modification->tv_sec = p->st_mtime;
+ modification->tv_usec = p->st_mtimensec / 1000;
+}
+
+}
+}
+#endif
+
/*!
\internal
*/
@@ -158,6 +145,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 +188,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;
@@ -676,6 +622,83 @@ bool QFSFileEngine::setSize(qint64 size)
return ret;
}
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+{
+ Q_D(QFSFileEngine);
+
+ if (d->openMode == QIODevice::NotOpen) {
+ setError(QFile::PermissionsError, qt_error_string(EACCES));
+ return false;
+ }
+
+ if (!newDate.isValid() || time == QAbstractFileEngine::CreationTime) {
+ setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
+ return false;
+ }
+
+#if QT_CONFIG(futimens)
+ struct timespec ts[2];
+
+ ts[0].tv_sec = ts[1].tv_sec = 0;
+ ts[0].tv_nsec = ts[1].tv_nsec = UTIME_OMIT;
+
+ const qint64 msecs = newDate.toMSecsSinceEpoch();
+
+ if (time == QAbstractFileEngine::AccessTime) {
+ ts[0].tv_sec = msecs / 1000;
+ ts[0].tv_nsec = (msecs % 1000) * 1000000;
+ } else if (time == QAbstractFileEngine::ModificationTime) {
+ ts[1].tv_sec = msecs / 1000;
+ ts[1].tv_nsec = (msecs % 1000) * 1000000;
+ }
+
+ if (futimens(d->nativeHandle(), ts) == -1) {
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
+
+ return true;
+#elif QT_CONFIG(futimes) || QT_CONFIG(futimesat)
+ struct timeval tv[2];
+ QT_STATBUF st;
+
+ if (QT_FSTAT(d->nativeHandle(), &st) == -1) {
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ GetFileTimes::get(&st, &tv[0], &tv[1]);
+
+ const qint64 msecs = newDate.toMSecsSinceEpoch();
+
+ if (time == QAbstractFileEngine::AccessTime) {
+ tv[0].tv_sec = msecs / 1000;
+ tv[0].tv_usec = (msecs % 1000) * 1000;
+ } else if (time == QAbstractFileEngine::ModificationTime) {
+ tv[1].tv_sec = msecs / 1000;
+ tv[1].tv_usec = (msecs % 1000) * 1000;
+ }
+
+#if QT_CONFIG(futimes)
+ if (futimes(d->nativeHandle(), tv) == -1) {
+#else
+ if (futimesat(d->nativeHandle(), NULL, tv) == -1) {
+#endif
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
+
+ return true;
+#else
+ setError(QFile::UnspecifiedError, qt_error_string(ENOSYS));
+ return false;
+#endif
+}
+
QDateTime QFSFileEngine::fileTime(FileTime time) const
{
Q_D(const QFSFileEngine);
@@ -793,6 +816,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..5c6098c3b0 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -80,6 +80,39 @@ static inline bool isUncPath(const QString &path)
&& path.size() > 2 && path.at(2) != QLatin1Char('.'));
}
+static inline void QDateTimeToSystemTime(const QDateTime &date, SYSTEMTIME *systemTime)
+{
+ const QDate d = date.date();
+ const QTime t = date.time();
+
+ systemTime->wYear = d.year();
+ systemTime->wMonth = d.month();
+ systemTime->wDay = d.day();
+ systemTime->wHour = t.hour();
+ systemTime->wMinute = t.minute();
+ systemTime->wSecond = t.second();
+ systemTime->wMilliseconds = t.msec();
+ systemTime->wDayOfWeek = d.dayOfWeek() % 7;
+}
+
+static inline bool QDateTimeToFileTime(const QDateTime &date, FILETIME *fileTime)
+{
+ SYSTEMTIME sTime;
+
+#if defined(Q_OS_WINCE)
+ QDateTimeToSystemTime(date, &sTime);
+#else
+ SYSTEMTIME lTime;
+
+ QDateTimeToSystemTime(date, &lTime);
+
+ if (!::TzSpecificLocalTimeToSystemTime(0, &lTime, &sTime))
+ return false;
+#endif
+
+ return ::SystemTimeToFileTime(&sTime, fileTime);
+}
+
/*!
\internal
*/
@@ -850,6 +883,69 @@ bool QFSFileEngine::setSize(qint64 size)
return false;
}
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+{
+ Q_D(QFSFileEngine);
+
+ if (d->openMode == QFile::NotOpen) {
+ setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return false;
+ }
+
+ if (!newDate.isValid()) {
+ setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
+ return false;
+ }
+
+ HANDLE handle = d->fileHandle;
+
+#ifndef Q_OS_WINCE
+ if (handle == INVALID_HANDLE_VALUE) {
+ if (d->fh)
+ handle = reinterpret_cast<HANDLE>(::_get_osfhandle(QT_FILENO(d->fh)));
+ else if (d->fd != -1)
+ handle = reinterpret_cast<HANDLE>(::_get_osfhandle(d->fd));
+ }
+#endif
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return false;
+ }
+
+ FILETIME fTime;
+ FILETIME *pLastWrite = NULL;
+ FILETIME *pLastAccess = NULL;
+ FILETIME *pCreationTime = NULL;
+
+ switch (time) {
+ case QAbstractFileEngine::ModificationTime:
+ pLastWrite = &fTime;
+ break;
+
+ case QAbstractFileEngine::AccessTime:
+ pLastAccess = &fTime;
+ break;
+
+ case QAbstractFileEngine::CreationTime:
+ pCreationTime = &fTime;
+ break;
+ }
+
+ if (!QDateTimeToFileTime(newDate, &fTime)) {
+ setError(QFile::UnspecifiedError, qt_error_string());
+ return false;
+ }
+
+ if (!::SetFileTime(handle, pCreationTime, pLastAccess, pLastWrite)) {
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
+
+ return true;
+}
QDateTime QFSFileEngine::fileTime(FileTime time) const
{
@@ -998,4 +1094,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..bea54f86da 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();
@@ -363,13 +363,13 @@ public:
bool waitForDeadChild();
#endif
#ifdef Q_OS_WIN
+ bool callCreateProcess(QProcess::CreateProcessArguments *cpargs);
bool drainOutputPipes();
void flushPipeWriter();
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 b822417ddf..251f68c9b4 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
@@ -424,8 +425,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)
@@ -447,29 +456,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);
@@ -477,16 +463,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.
@@ -507,7 +489,7 @@ void QProcessPrivate::startProcess()
// Start the child.
if (forkfd == FFD_CHILD_PROCESS) {
- execChild(workingDirPtr, path, argv, envp);
+ execChild(workingDirPtr, argv, envp);
::_exit(-1);
}
@@ -548,7 +530,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
@@ -571,7 +553,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
@@ -586,25 +568,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: ";
}
@@ -929,7 +899,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);
@@ -971,23 +941,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..fc4d3b225d 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;
}
@@ -450,6 +458,16 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Hash &
return envlist;
}
+bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs)
+{
+ if (modifyCreateProcessArgs)
+ modifyCreateProcessArgs(cpargs);
+ return CreateProcess(cpargs->applicationName, cpargs->arguments, cpargs->processAttributes,
+ cpargs->threadAttributes, cpargs->inheritHandles, cpargs->flags,
+ cpargs->environment, cpargs->currentDirectory, cpargs->startupInfo,
+ cpargs->processInformation);
+}
+
void QProcessPrivate::startProcess()
{
Q_Q(QProcess);
@@ -472,15 +490,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");
@@ -507,18 +520,14 @@ void QProcessPrivate::startProcess()
const QString nativeWorkingDirectory = QDir::toNativeSeparators(workingDirectory);
QProcess::CreateProcessArguments cpargs = {
- 0, (wchar_t*)args.utf16(),
- 0, 0, TRUE, dwCreationFlags,
- environment.isEmpty() ? 0 : envlist.data(),
- nativeWorkingDirectory.isEmpty() ? Q_NULLPTR : (wchar_t*)nativeWorkingDirectory.utf16(),
+ nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
+ nullptr, nullptr, true, dwCreationFlags,
+ environment.isEmpty() ? nullptr : envlist.data(),
+ nativeWorkingDirectory.isEmpty()
+ ? nullptr : reinterpret_cast<const wchar_t *>(nativeWorkingDirectory.utf16()),
&startupInfo, pid
};
- if (modifyCreateProcessArgs)
- modifyCreateProcessArgs(&cpargs);
- success = CreateProcess(cpargs.applicationName, cpargs.arguments, cpargs.processAttributes,
- cpargs.threadAttributes, cpargs.inheritHandles, cpargs.flags,
- cpargs.environment, cpargs.currentDirectory, cpargs.startupInfo,
- cpargs.processInformation);
+ success = callCreateProcess(&cpargs);
QString errorString;
if (!success) {
@@ -826,6 +835,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 +846,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 +870,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,
@@ -874,10 +892,14 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
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(),
- &startupInfo, &pinfo);
+ QProcess::CreateProcessArguments cpargs = {
+ nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
+ nullptr, nullptr, false, dwCreationFlags, envPtr,
+ workingDirectory.isEmpty()
+ ? nullptr : reinterpret_cast<const wchar_t *>(workingDirectory.utf16()),
+ &startupInfo, &pinfo
+ };
+ success = callCreateProcess(&cpargs);
if (success) {
CloseHandle(pinfo.hThread);
@@ -885,7 +907,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..ff31524c1c 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,
@@ -1459,6 +1457,13 @@ QString QResourceFileEngine::owner(FileOwner) const
return QString();
}
+bool QResourceFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+{
+ Q_UNUSED(newDate);
+ Q_UNUSED(time);
+ return false;
+}
+
QDateTime QResourceFileEngine::fileTime(FileTime time) const
{
Q_D(const QResourceFileEngine);
diff --git a/src/corelib/io/qresource_p.h b/src/corelib/io/qresource_p.h
index e08ba64d2b..1b0f4f66e4 100644
--- a/src/corelib/io/qresource_p.h
+++ b/src/corelib/io/qresource_p.h
@@ -103,6 +103,7 @@ public:
virtual uint ownerId(FileOwner) const Q_DECL_OVERRIDE;
virtual QString owner(FileOwner) const Q_DECL_OVERRIDE;
+ virtual bool setFileTime(const QDateTime &newDate, FileTime time) Q_DECL_OVERRIDE;
virtual QDateTime fileTime(FileTime time) const Q_DECL_OVERRIDE;
virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE;
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index d5460238ec..850e729987 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/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 5144ac0ec9..ee3cb4efcb 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -954,8 +954,7 @@ QTextStreamPrivate::PaddingResult QTextStreamPrivate::padding(int len) const
right = padSize - padSize/2;
break;
}
- const PaddingResult result = { left, right };
- return result;
+ return { left, right };
}
/*!
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/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index 827ed43b63..b68e9e6d4b 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -129,17 +129,8 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
actualReadBufferSize--;
readSoFar = 1;
} else {
- qint64 bytesToRead = qMin(actualReadBufferSize, maxlen);
- readSoFar = 0;
- while (readSoFar < bytesToRead) {
- const char *ptr = readBuffer.readPointer();
- qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
- readBuffer.nextDataBlockSize());
- memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
- readSoFar += bytesToReadFromThisBlock;
- readBuffer.free(bytesToReadFromThisBlock);
- actualReadBufferSize -= bytesToReadFromThisBlock;
- }
+ readSoFar = readBuffer.read(data, qMin(actualReadBufferSize, maxlen));
+ actualReadBufferSize -= readSoFar;
}
if (!pipeBroken) {
diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
index 226a2401e1..539c190ac3 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);
}
@@ -969,12 +1012,7 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
// reinsert moved, mapped indexes
QVector<QPair<QModelIndex, Mapping*> >::iterator it = moved_source_index_mappings.begin();
for (; it != moved_source_index_mappings.end(); ++it) {
-#ifdef QT_STRICT_ITERATORS
- source_index_mapping.insert((*it).first, (*it).second);
- (*it).second->map_iter = source_index_mapping.constFind((*it).first);
-#else
- (*it).second->map_iter = source_index_mapping.insert((*it).first, (*it).second);
-#endif
+ (*it).second->map_iter = QHash<QModelIndex, Mapping *>::const_iterator(source_index_mapping.insert((*it).first, (*it).second));
}
}
@@ -1125,7 +1163,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 +1175,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 +1194,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 +1228,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 +1472,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 +1541,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 +1834,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 +2657,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 2b47d43469..bcfd88fb19 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/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp
index d4cc4b81df..c5a5aaf39d 100644
--- a/src/corelib/json/qjsonarray.cpp
+++ b/src/corelib/json/qjsonarray.cpp
@@ -212,6 +212,27 @@ QJsonArray &QJsonArray::operator =(const QJsonArray &other)
return *this;
}
+/*!
+ \fn QJsonArray::QJsonArray(QJsonArray &&other)
+ \since 5.10
+
+ Move-constructs a QJsonArray from \a other.
+*/
+
+/*!
+ \fn QJsonArray &QJsonArray::operator =(QJsonArray &&other)
+ \since 5.10
+
+ Move-assigns \a other to this array.
+*/
+
+/*!
+ \fn void QJsonArray::swap(QJsonArray &other)
+ \since 5.10
+
+ Swaps the array \a other with this. This operation is very fast and never fails.
+*/
+
/*! \fn QJsonArray &QJsonArray::operator+=(const QJsonValue &value)
Appends \a value to the array, and returns a reference to the array itself.
diff --git a/src/corelib/json/qjsonarray.h b/src/corelib/json/qjsonarray.h
index 3b6fa37cfa..ddba2ca78e 100644
--- a/src/corelib/json/qjsonarray.h
+++ b/src/corelib/json/qjsonarray.h
@@ -72,6 +72,20 @@ public:
QJsonArray(const QJsonArray &other);
QJsonArray &operator =(const QJsonArray &other);
+ QJsonArray(QJsonArray &&other) Q_DECL_NOTHROW
+ : d(other.d),
+ a(other.a)
+ {
+ other.d = nullptr;
+ other.a = nullptr;
+ }
+
+ QJsonArray &operator =(QJsonArray &&other) Q_DECL_NOTHROW
+ {
+ swap(other);
+ return *this;
+ }
+
static QJsonArray fromStringList(const QStringList &list);
static QJsonArray fromVariantList(const QVariantList &list);
QVariantList toVariantList() const;
@@ -101,6 +115,12 @@ public:
bool operator==(const QJsonArray &other) const;
bool operator!=(const QJsonArray &other) const;
+ void swap(QJsonArray &other) Q_DECL_NOTHROW
+ {
+ qSwap(d, other.d);
+ qSwap(a, other.a);
+ }
+
class const_iterator;
class iterator {
@@ -243,6 +263,8 @@ private:
QJsonPrivate::Array *a;
};
+Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonArray)
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
#endif
diff --git a/src/corelib/json/qjsondocument.cpp b/src/corelib/json/qjsondocument.cpp
index ed454d5442..d1169d90e3 100644
--- a/src/corelib/json/qjsondocument.cpp
+++ b/src/corelib/json/qjsondocument.cpp
@@ -153,6 +153,28 @@ QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
return *this;
}
+/*!
+ \fn QJsonDocument::QJsonDocument(QJsonDocument &&other)
+ \since 5.10
+
+ Move-constructs a QJsonDocument from \a other.
+*/
+
+/*!
+ \fn QJsonDocument &QJsonDocument::operator =(QJsonDocument &&other)
+ \since 5.10
+
+ Move-assigns \a other to this document.
+*/
+
+/*!
+ \fn void QJsonDocument::swap(QJsonDocument &other)
+ \since 5.10
+
+ Swaps the document \a other with this. This operation is very fast and never fails.
+*/
+
+
/*! \enum QJsonDocument::DataValidation
This value is used to tell QJsonDocument whether to validate the binary data
diff --git a/src/corelib/json/qjsondocument.h b/src/corelib/json/qjsondocument.h
index 19885a8d56..82f223709e 100644
--- a/src/corelib/json/qjsondocument.h
+++ b/src/corelib/json/qjsondocument.h
@@ -93,6 +93,23 @@ public:
QJsonDocument(const QJsonDocument &other);
QJsonDocument &operator =(const QJsonDocument &other);
+ QJsonDocument(QJsonDocument &&other) Q_DECL_NOTHROW
+ : d(other.d)
+ {
+ other.d = nullptr;
+ }
+
+ QJsonDocument &operator =(QJsonDocument &&other) Q_DECL_NOTHROW
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(QJsonDocument &other) Q_DECL_NOTHROW
+ {
+ qSwap(d, other.d);
+ }
+
enum DataValidation {
Validate,
BypassValidation
@@ -147,6 +164,8 @@ private:
QJsonPrivate::Data *d;
};
+Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonDocument)
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
#endif
diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp
index b5b6f36bc6..4a316c8a6f 100644
--- a/src/corelib/json/qjsonobject.cpp
+++ b/src/corelib/json/qjsonobject.cpp
@@ -194,6 +194,28 @@ QJsonObject &QJsonObject::operator =(const QJsonObject &other)
}
/*!
+ \fn QJsonObject::QJsonObject(QJsonObject &&other)
+ \since 5.10
+
+ Move-constructs a QJsonObject from \a other.
+*/
+
+/*!
+ \fn QJsonObject &QJsonObject::operator =(QJsonObject &&other)
+ \since 5.10
+
+ Move-assigns \a other to this object.
+*/
+
+/*!
+ \fn void QJsonObject::swap(QJsonObject &other)
+ \since 5.10
+
+ Swaps the object \a other with this. This operation is very fast and never fails.
+*/
+
+
+/*!
Converts the variant map \a map to a QJsonObject.
The keys in \a map will be used as the keys in the JSON object,
diff --git a/src/corelib/json/qjsonobject.h b/src/corelib/json/qjsonobject.h
index e238c84d98..c77e2164a8 100644
--- a/src/corelib/json/qjsonobject.h
+++ b/src/corelib/json/qjsonobject.h
@@ -74,6 +74,25 @@ public:
QJsonObject(const QJsonObject &other);
QJsonObject &operator =(const QJsonObject &other);
+ QJsonObject(QJsonObject &&other) Q_DECL_NOTHROW
+ : d(other.d), o(other.o)
+ {
+ other.d = nullptr;
+ other.o = nullptr;
+ }
+
+ QJsonObject &operator =(QJsonObject &&other) Q_DECL_NOTHROW
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(QJsonObject &other) Q_DECL_NOTHROW
+ {
+ qSwap(d, other.d);
+ qSwap(o, other.o);
+ }
+
static QJsonObject fromVariantMap(const QVariantMap &map);
QVariantMap toVariantMap() const;
static QJsonObject fromVariantHash(const QVariantHash &map);
@@ -241,6 +260,8 @@ private:
QJsonPrivate::Object *o;
};
+Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonObject)
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &);
#endif
diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp
index 4b52014db1..16f4913e9c 100644
--- a/src/corelib/json/qjsonvalue.cpp
+++ b/src/corelib/json/qjsonvalue.cpp
@@ -276,14 +276,32 @@ QJsonValue::QJsonValue(const QJsonValue &other)
QJsonValue &QJsonValue::operator =(const QJsonValue &other)
{
QJsonValue copy(other);
- // swap(copy);
- qSwap(dbl, copy.dbl);
- qSwap(d, copy.d);
- qSwap(t, copy.t);
+ swap(copy);
return *this;
}
/*!
+ \fn QJsonValue::QJsonValue(QJsonValue &&other)
+ \since 5.10
+
+ Move-constructs a QJsonValue from \a other.
+*/
+
+/*!
+ \fn QJsonValue &QJsonValue::operator =(QJsonValue &&other)
+ \since 5.10
+
+ Move-assigns \a other to this value.
+*/
+
+/*!
+ \fn void QJsonValue::swap(QJsonValue &other)
+ \since 5.10
+
+ Swaps the value \a other with this. This operation is very fast and never fails.
+*/
+
+/*!
\fn bool QJsonValue::isNull() const
Returns \c true if the value is null.
diff --git a/src/corelib/json/qjsonvalue.h b/src/corelib/json/qjsonvalue.h
index a853acaddd..96ccd34b6e 100644
--- a/src/corelib/json/qjsonvalue.h
+++ b/src/corelib/json/qjsonvalue.h
@@ -92,6 +92,29 @@ public:
QJsonValue(const QJsonValue &other);
QJsonValue &operator =(const QJsonValue &other);
+ QJsonValue(QJsonValue &&other) Q_DECL_NOTHROW
+ : ui(other.ui),
+ d(other.d),
+ t(other.t)
+ {
+ other.ui = 0;
+ other.d = nullptr;
+ other.t = Null;
+ }
+
+ QJsonValue &operator =(QJsonValue &&other) Q_DECL_NOTHROW
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(QJsonValue &other) Q_DECL_NOTHROW
+ {
+ qSwap(ui, other.ui);
+ qSwap(d, other.d);
+ qSwap(t, other.t);
+ }
+
static QJsonValue fromVariant(const QVariant &variant);
QVariant toVariant() const;
@@ -217,6 +240,8 @@ public:
};
#endif
+Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonValue)
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
#endif
diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h
index 0d3e53e4a7..3a530cf1de 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..272d6179d1 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>
@@ -94,6 +93,45 @@ QMacAutoReleasePool::~QMacAutoReleasePool()
[static_cast<NSAutoreleasePool*>(pool) drain];
}
+#ifdef Q_OS_MACOS
+/*!
+ Ensure that Objective-C objects auto-released in main(), directly or indirectly,
+ after QCoreApplication construction, are released when the app goes out of scope.
+ The memory will be reclaimed by the system either way when the process exits,
+ but by having a root level pool we ensure that the objects get their dealloc
+ methods called, which is useful for debugging object ownership graphs, etc.
+*/
+
+QT_END_NAMESPACE
+#define ROOT_LEVEL_POOL_MARKER QT_ROOT_LEVEL_POOL__THESE_OBJECTS_WILL_BE_RELEASED_WHEN_QAPP_GOES_OUT_OF_SCOPE
+@interface QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) : NSObject @end
+@implementation QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) @end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(ROOT_LEVEL_POOL_MARKER);
+QT_BEGIN_NAMESPACE
+
+const char ROOT_LEVEL_POOL_DISABLE_SWITCH[] = "QT_DISABLE_ROOT_LEVEL_AUTORELEASE_POOL";
+
+QMacRootLevelAutoReleasePool::QMacRootLevelAutoReleasePool()
+{
+ if (qEnvironmentVariableIsSet(ROOT_LEVEL_POOL_DISABLE_SWITCH))
+ return;
+
+ pool.reset(new QMacAutoReleasePool);
+
+ [[[ROOT_LEVEL_POOL_MARKER alloc] init] autorelease];
+
+ if (qstrcmp(qgetenv("OBJC_DEBUG_MISSING_POOLS"), "YES") == 0) {
+ qDebug("QCoreApplication root level NSAutoreleasePool in place. Break on ~%s and use\n" \
+ "'p [NSAutoreleasePool showPools]' to show leaked objects, or set %s",
+ __FUNCTION__, ROOT_LEVEL_POOL_DISABLE_SWITCH);
+ }
+}
+
+QMacRootLevelAutoReleasePool::~QMacRootLevelAutoReleasePool()
+{
+}
+#endif
+
// -------------------------------------------------------------------------
#ifdef Q_OS_OSX
@@ -140,6 +178,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 +187,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..12e9518979 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -68,6 +68,7 @@
#endif
#include "qstring.h"
+#include "qscopedpointer.h"
#if defined( __OBJC__) && defined(QT_NAMESPACE)
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__)
@@ -76,6 +77,37 @@
#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;
+};
+
+
+#ifdef Q_OS_MACOS
+class QMacRootLevelAutoReleasePool
+{
+public:
+ QMacRootLevelAutoReleasePool();
+ ~QMacRootLevelAutoReleasePool();
+private:
+ QScopedPointer<QMacAutoReleasePool> pool;
+};
+#endif
/*
Helper class that automates refernce counting for CFtypes.
@@ -90,32 +122,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 86bace3260..eca575ba01 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -102,6 +102,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/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 39e7c71a9c..a5bd2513b6 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -1019,6 +1019,21 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
}
/*!
+ \internal
+ \since 5.10
+
+ Forwards the \a event to the \a receiver, using the spontaneous
+ state of the \a originatingEvent if specified.
+*/
+bool QCoreApplication::forwardEvent(QObject *receiver, QEvent *event, QEvent *originatingEvent)
+{
+ if (event && originatingEvent)
+ event->spont = originatingEvent->spont;
+
+ return notifyInternal2(receiver, event);
+}
+
+/*!
Sends \a event to \a receiver: \a {receiver}->event(\a event).
Returns the value that is returned from the receiver's event
handler. Note that this function is called for all events sent to
diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h
index 0fee7b3de8..34133533f0 100644
--- a/src/corelib/kernel/qcoreapplication.h
+++ b/src/corelib/kernel/qcoreapplication.h
@@ -206,6 +206,7 @@ private:
QT_DEPRECATED bool notifyInternal(QObject *receiver, QEvent *event); // ### Qt6 BIC: remove me
# endif
static bool notifyInternal2(QObject *receiver, QEvent *);
+ static bool forwardEvent(QObject *receiver, QEvent *event, QEvent *originatingEvent = nullptr);
#endif
static QCoreApplication *self;
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index c646786296..da6ce1249f 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -58,6 +58,10 @@
#include "private/qobject_p.h"
#endif
+#ifdef Q_OS_MACOS
+#include "private/qcore_mac_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
typedef QList<QTranslator*> QTranslatorList;
@@ -85,6 +89,10 @@ public:
QString appName() const;
QString appVersion() const;
+#ifdef Q_OS_MACOS
+ QMacRootLevelAutoReleasePool autoReleasePool;
+#endif
+
#ifdef Q_OS_DARWIN
static QString infoDictionaryStringProperty(const QString &propertyName);
#endif
diff --git a/src/corelib/kernel/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/qfunctions_fake_env_p.h b/src/corelib/kernel/qfunctions_fake_env_p.h
index 16d18c4d88..7010d2cf5d 100644
--- a/src/corelib/kernel/qfunctions_fake_env_p.h
+++ b/src/corelib/kernel/qfunctions_fake_env_p.h
@@ -77,7 +77,9 @@ struct NameEquals {
{ return qstrcmp(other.name, name) == 0; }
};
+#ifndef Q_CLANG_QDOC
Q_GLOBAL_STATIC(QVector<Variable>, qt_app_environment)
+#endif
errno_t qt_fake_getenv_s(size_t *sizeNeeded, char *buffer, size_t bufferSize, const char *varName)
{
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..305e9065e9 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
@@ -242,16 +244,13 @@ Q_DECL_CONSTEXPR inline double qRadiansToDegrees(double radians)
}
-#if defined(QT_HAS_BUILTIN_CLZ)
-inline quint32 qNextPowerOfTwo(quint32 v)
+Q_DECL_RELAXED_CONSTEXPR inline quint32 qNextPowerOfTwo(quint32 v)
{
+#if defined(QT_HAS_BUILTIN_CLZ)
if (v == 0)
return 1;
return 2U << (31 ^ QAlgorithmsPrivate::qt_builtin_clz(v));
-}
#else
-inline quint32 qNextPowerOfTwo(quint32 v)
-{
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
@@ -259,19 +258,16 @@ inline quint32 qNextPowerOfTwo(quint32 v)
v |= v >> 16;
++v;
return v;
-}
#endif
+}
-#if defined(QT_HAS_BUILTIN_CLZLL)
-inline quint64 qNextPowerOfTwo(quint64 v)
+Q_DECL_RELAXED_CONSTEXPR inline quint64 qNextPowerOfTwo(quint64 v)
{
+#if defined(QT_HAS_BUILTIN_CLZLL)
if (v == 0)
return 1;
return Q_UINT64_C(2) << (63 ^ QAlgorithmsPrivate::qt_builtin_clzll(v));
-}
#else
-inline quint64 qNextPowerOfTwo(quint64 v)
-{
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
@@ -280,15 +276,15 @@ inline quint64 qNextPowerOfTwo(quint64 v)
v |= v >> 32;
++v;
return v;
-}
#endif
+}
-inline quint32 qNextPowerOfTwo(qint32 v)
+Q_DECL_RELAXED_CONSTEXPR inline quint32 qNextPowerOfTwo(qint32 v)
{
return qNextPowerOfTwo(quint32(v));
}
-inline quint64 qNextPowerOfTwo(qint64 v)
+Q_DECL_RELAXED_CONSTEXPR inline quint64 qNextPowerOfTwo(qint64 v)
{
return qNextPowerOfTwo(quint64(v));
}
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 a8003f7e46..f07b463482 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.
@@ -3264,7 +3347,21 @@ int QMetaProperty::notifySignalIndex() const
if (hasNotifySignal()) {
int offset = priv(mobj->d.data)->propertyData +
priv(mobj->d.data)->propertyCount * 3 + idx;
- return mobj->d.data[offset] + mobj->methodOffset();
+ int methodIndex = mobj->d.data[offset];
+ if (methodIndex & IsUnresolvedSignal) {
+ methodIndex &= ~IsUnresolvedSignal;
+ const QByteArray signalName = stringData(mobj, methodIndex);
+ const QMetaObject *m = mobj;
+ const int idx = indexOfMethodRelative<MethodSignal>(&m, signalName, 0, nullptr);
+ if (idx >= 0) {
+ return idx + m->methodOffset();
+ } else {
+ qWarning("QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'",
+ signalName.constData(), objectClassName(mobj), name());
+ return -1;
+ }
+ }
+ return methodIndex + mobj->methodOffset();
} else {
return -1;
}
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index e247c48703..434ef84808 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -111,7 +111,8 @@ enum MetaObjectFlags {
enum MetaDataFlags {
IsUnresolvedType = 0x80000000,
- TypeNameIndexMask = 0x7FFFFFFF
+ TypeNameIndexMask = 0x7FFFFFFF,
+ IsUnresolvedSignal = 0x70000000
};
enum EnumFlags {
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index 56f187a59d..e3b70638c6 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -190,12 +190,13 @@ class QMetaEnumBuilderPrivate
{
public:
QMetaEnumBuilderPrivate(const QByteArray& _name)
- : name(_name), isFlag(false)
+ : name(_name), isFlag(false), isScoped(false)
{
}
QByteArray name;
bool isFlag;
+ bool isScoped;
QList<QByteArray> keys;
QVector<int> values;
};
@@ -637,6 +638,7 @@ QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype)
{
QMetaEnumBuilder en = addEnumerator(prototype.name());
en.setIsFlag(prototype.isFlag());
+ en.setIsScoped(prototype.isScoped());
int count = prototype.keyCount();
for (int index = 0; index < count; ++index)
en.addKey(prototype.key(index), prototype.value(index));
@@ -1408,12 +1410,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_ASSERT(!buf || dataIndex == pmeta->enumeratorData);
for (const auto &enumerator : d->enumerators) {
int name = strings.enter(enumerator.name);
- int isFlag = (int)(enumerator.isFlag);
+ int isFlag = enumerator.isFlag ? EnumIsFlag : 0;
+ int isScoped = enumerator.isScoped ? EnumIsScoped : 0;
int count = enumerator.keys.size();
int enumOffset = enumIndex;
if (buf) {
data[dataIndex] = name;
- data[dataIndex + 1] = isFlag;
+ data[dataIndex + 1] = isFlag | isScoped;
data[dataIndex + 2] = count;
data[dataIndex + 3] = enumOffset;
}
@@ -1641,6 +1644,7 @@ void QMetaObjectBuilder::serialize(QDataStream& stream) const
for (const auto &enumerator : d->enumerators) {
stream << enumerator.name;
stream << enumerator.isFlag;
+ stream << enumerator.isScoped;
stream << enumerator.keys;
stream << enumerator.values;
}
@@ -1807,6 +1811,7 @@ void QMetaObjectBuilder::deserialize
addEnumerator(name);
QMetaEnumBuilderPrivate &enumerator = d->enumerators[index];
stream >> enumerator.isFlag;
+ stream >> enumerator.isScoped;
stream >> enumerator.keys;
stream >> enumerator.values;
if (enumerator.keys.size() != enumerator.values.size()) {
@@ -2633,6 +2638,31 @@ void QMetaEnumBuilder::setIsFlag(bool value)
}
/*!
+ Return \c true if this enumerator should be considered scoped (C++11 enum class).
+
+ \sa setIsScoped()
+*/
+bool QMetaEnumBuilder::isScoped() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->isScoped;
+ return false;
+}
+
+/*!
+ Sets this enumerator to be a scoped enum if \value is true
+
+ \sa isScoped()
+*/
+void QMetaEnumBuilder::setIsScoped(bool value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ d->isScoped = value;
+}
+
+/*!
Returns the number of keys.
\sa key(), addKey()
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
index 144595330d..03b2afaebc 100644
--- a/src/corelib/kernel/qmetaobjectbuilder_p.h
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -300,6 +300,9 @@ public:
bool isFlag() const;
void setIsFlag(bool value);
+ bool isScoped() const;
+ void setIsScoped(bool value);
+
int keyCount() const;
QByteArray key(int index) const;
int value(int index) const;
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index b75f2ad9dc..e48807ea49 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -308,6 +308,7 @@ struct DefinedTypesFilter {
\omitvalue TrackingPointerToQObject
\omitvalue WasDeclaredAsMetaType
\omitvalue IsGadget This type is a Q_GADGET and it's corresponding QMetaObject can be accessed with QMetaType::metaObject Since 5.5.
+ \omitvalue PointerToGadget
*/
/*!
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index d88f469e0f..f704c5b21a 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 3f50716cd7..3b0f7ead09 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.h b/src/corelib/kernel/qobject.h
index 6941c55896..2e66daa914 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -304,7 +304,7 @@ public:
static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
{
- return connect(sender, signal, sender, slot, Qt::DirectConnection);
+ return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection);
}
//connect to a functor, with a "context" object defining in which event loop is going to be executed
@@ -334,7 +334,7 @@ public:
return connectImpl(sender, reinterpret_cast<void **>(&signal), context, Q_NULLPTR,
new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
- typename SignalType::ReturnType>(slot),
+ typename SignalType::ReturnType>(std::move(slot)),
type, types, &SignalType::Object::staticMetaObject);
}
#endif //Q_QDOC
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..0a5d003b05 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -234,7 +234,7 @@ public:
mutable quint32 connectedSignals[2];
union {
- QObject *currentChildBeingDeleted;
+ QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
};
@@ -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 29ab77b269..b9f2e47e32 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; };
@@ -350,6 +350,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(Func f) : QSlotObjectBase(&impl), function(std::move(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/kernel/qtimer.h b/src/corelib/kernel/qtimer.h
index 6e61ca10cb..7db5fc759b 100644
--- a/src/corelib/kernel/qtimer.h
+++ b/src/corelib/kernel/qtimer.h
@@ -122,14 +122,14 @@ public:
!std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Func1 slot)
{
- singleShot(interval, defaultTypeFor(interval), nullptr, slot);
+ singleShot(interval, defaultTypeFor(interval), nullptr, std::move(slot));
}
template <typename Duration, typename Func1>
static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
!std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Qt::TimerType timerType, Func1 slot)
{
- singleShot(interval, timerType, nullptr, slot);
+ singleShot(interval, timerType, nullptr, std::move(slot));
}
// singleShot to a functor or function pointer (with context)
template <typename Duration, typename Func1>
@@ -137,7 +137,7 @@ public:
!std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, QObject *context, Func1 slot)
{
- singleShot(interval, defaultTypeFor(interval), context, slot);
+ singleShot(interval, defaultTypeFor(interval), context, std::move(slot));
}
template <typename Duration, typename Func1>
static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
@@ -150,7 +150,7 @@ public:
singleShotImpl(interval, timerType, context,
new QtPrivate::QFunctorSlotObject<Func1, 0,
- typename QtPrivate::List_Left<void, 0>::Value, void>(slot));
+ typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(slot)));
}
#endif
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/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp
index 98a0e8eb1b..28113babfe 100644
--- a/src/corelib/mimetypes/qmimetype.cpp
+++ b/src/corelib/mimetypes/qmimetype.cpp
@@ -206,10 +206,14 @@ uint qHash(const QMimeType &key, uint seed) Q_DECL_NOTHROW
*/
/*!
- \fn bool QMimeType::isValid() const;
- Returns \c true if the QMimeType object contains valid data, otherwise returns \c false.
+ \property QMimeType::valid
+ \brief \c true if the QMimeType object contains valid data, \c false otherwise
+
A valid MIME type has a non-empty name().
The invalid MIME type is the default-constructed QMimeType.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
bool QMimeType::isValid() const
{
@@ -217,9 +221,12 @@ bool QMimeType::isValid() const
}
/*!
- \fn bool QMimeType::isDefault() const;
- Returns \c true if this MIME type is the default MIME type which
+ \property QMimeType::isDefault
+ \brief \c true if this MIME type is the default MIME type which
applies to all files: application/octet-stream.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
bool QMimeType::isDefault() const
{
@@ -227,8 +234,11 @@ bool QMimeType::isDefault() const
}
/*!
- \fn QString QMimeType::name() const;
- Returns the name of the MIME type.
+ \property QMimeType::name
+ \brief the name of the MIME type
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QString QMimeType::name() const
{
@@ -236,9 +246,13 @@ QString QMimeType::name() const
}
/*!
- Returns the description of the MIME type to be displayed on user interfaces.
+ \property QMimeType::comment
+ \brief the description of the MIME type to be displayed on user interfaces
The default language (QLocale().name()) is used to select the appropriate translation.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QString QMimeType::comment() const
{
@@ -267,8 +281,8 @@ QString QMimeType::comment() const
}
/*!
- \fn QString QMimeType::genericIconName() const;
- Returns the file name of a generic icon that represents the MIME type.
+ \property QMimeType::genericIconName
+ \brief the file name of a generic icon that represents the MIME type
This should be used if the icon returned by iconName() cannot be found on
the system. It is used for categories of similar types (like spreadsheets
@@ -276,6 +290,9 @@ QString QMimeType::comment() const
The freedesktop.org Icon Naming Specification lists a set of such icon names.
The icon name can be given to QIcon::fromTheme() in order to load the icon.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QString QMimeType::genericIconName() const
{
@@ -297,10 +314,13 @@ QString QMimeType::genericIconName() const
}
/*!
- \fn QString QMimeType::iconName() const;
- Returns the file name of an icon image that represents the MIME type.
+ \property QMimeType::iconName
+ \brief the file name of an icon image that represents the MIME type
The icon name can be given to QIcon::fromTheme() in order to load the icon.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QString QMimeType::iconName() const
{
@@ -316,8 +336,11 @@ QString QMimeType::iconName() const
}
/*!
- \fn QStringList QMimeType::globPatterns() const;
- Returns the list of glob matching patterns.
+ \property QMimeType::globPatterns
+ \brief the list of glob matching patterns
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QStringList QMimeType::globPatterns() const
{
@@ -326,6 +349,9 @@ QStringList QMimeType::globPatterns() const
}
/*!
+ \property QMimeType::parentMimeTypes
+ \brief the names of parent MIME types
+
A type is a subclass of another type if any instance of the first type is
also an instance of the second. For example, all image/svg+xml files are also
text/xml, text/plain and application/octet-stream files. Subclassing is about
@@ -336,6 +362,9 @@ QStringList QMimeType::globPatterns() const
A mimetype can have multiple parents. For instance application/x-perl
has two parents: application/x-executable and text/plain. This makes
it possible to both execute perl scripts, and to open them in text editors.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QStringList QMimeType::parentMimeTypes() const
{
@@ -357,6 +386,9 @@ static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
}
/*!
+ \property QMimeType::allAncestors
+ \brief the names of direct and indirect parent MIME types
+
Return all the parent mimetypes of this mimetype, direct and indirect.
This includes the parent(s) of its parent(s), etc.
@@ -365,6 +397,9 @@ static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
Note that application/octet-stream is the ultimate parent for all types
of files (but not directories).
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QStringList QMimeType::allAncestors() const
{
@@ -374,7 +409,8 @@ QStringList QMimeType::allAncestors() const
}
/*!
- Return the list of aliases of this mimetype.
+ \property QMimeType::aliases
+ \brief the list of aliases of this mimetype
For instance, for text/csv, the returned list would be:
text/x-csv, text/x-comma-separated-values.
@@ -383,6 +419,9 @@ QStringList QMimeType::allAncestors() const
never to aliases directly.
The order of the aliases in the list is undefined.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QStringList QMimeType::aliases() const
{
@@ -390,8 +429,13 @@ QStringList QMimeType::aliases() const
}
/*!
- Returns the known suffixes for the MIME type.
+ \property QMimeType::suffixes
+ \brief the known suffixes for the MIME type
+
No leading dot is included, so for instance this would return "jpg", "jpeg" for image/jpeg.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QStringList QMimeType::suffixes() const
{
@@ -412,9 +456,14 @@ QStringList QMimeType::suffixes() const
}
/*!
- Returns the preferred suffix for the MIME type.
+ \property QMimeType::preferredSuffix
+ \brief the preferred suffix for the MIME type
+
No leading dot is included, so for instance this would return "pdf" for application/pdf.
The return value can be empty, for mime types which do not have any suffixes associated.
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QString QMimeType::preferredSuffix() const
{
@@ -423,8 +472,11 @@ QString QMimeType::preferredSuffix() const
}
/*!
- \fn QString QMimeType::filterString() const;
- Returns a filter string usable for a file dialog.
+ \property QMimeType::filterString
+ \brief a filter string usable for a file dialog
+
+ While this property was introduced in 5.10, the
+ corresponding accessor method has always been there.
*/
QString QMimeType::filterString() const
{
@@ -449,6 +501,8 @@ QString QMimeType::filterString() const
Returns \c true if this mimetype is \a mimeTypeName,
or inherits \a mimeTypeName (see parentMimeTypes()),
or \a mimeTypeName is an alias for this mimetype.
+
+ This method has been made invokable from QML since 5.10.
*/
bool QMimeType::inherits(const QString &mimeTypeName) const
{
diff --git a/src/corelib/mimetypes/qmimetype.h b/src/corelib/mimetypes/qmimetype.h
index e9ff9ace84..def4034f8a 100644
--- a/src/corelib/mimetypes/qmimetype.h
+++ b/src/corelib/mimetypes/qmimetype.h
@@ -45,6 +45,7 @@
#ifndef QT_NO_MIMETYPE
+#include <QtCore/qobjectdefs.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
@@ -58,6 +59,21 @@ Q_CORE_EXPORT uint qHash(const QMimeType &key, uint seed = 0) Q_DECL_NOTHROW;
class Q_CORE_EXPORT QMimeType
{
+ Q_GADGET
+ Q_PROPERTY(bool valid READ isValid CONSTANT)
+ Q_PROPERTY(bool isDefault READ isDefault CONSTANT)
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString comment READ comment CONSTANT)
+ Q_PROPERTY(QString genericIconName READ genericIconName CONSTANT)
+ Q_PROPERTY(QString iconName READ iconName CONSTANT)
+ Q_PROPERTY(QStringList globPatterns READ globPatterns CONSTANT)
+ Q_PROPERTY(QStringList parentMimeTypes READ parentMimeTypes CONSTANT)
+ Q_PROPERTY(QStringList allAncestors READ allAncestors CONSTANT)
+ Q_PROPERTY(QStringList aliases READ aliases CONSTANT)
+ Q_PROPERTY(QStringList suffixes READ suffixes CONSTANT)
+ Q_PROPERTY(QString preferredSuffix READ preferredSuffix CONSTANT)
+ Q_PROPERTY(QString filterString READ filterString CONSTANT)
+
public:
QMimeType();
QMimeType(const QMimeType &other);
@@ -94,7 +110,7 @@ public:
QStringList suffixes() const;
QString preferredSuffix() const;
- bool inherits(const QString &mimeTypeName) const;
+ Q_INVOKABLE bool inherits(const QString &mimeTypeName) const;
QString filterString() const;
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 40000e7b24..0cc193c325 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/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp
index 0afce7fcf0..c9644c73d3 100644
--- a/src/corelib/plugin/quuid.cpp
+++ b/src/corelib/plugin/quuid.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -49,21 +50,25 @@
#endif
QT_BEGIN_NAMESPACE
-template <class Char, class Integral>
-void _q_toHex(Char *&dst, Integral value)
+// 16 bytes (a uint, two shorts and a uchar[8]), each represented by two hex
+// digits; plus four dashes and a pair of enclosing brace: 16*2 + 4 + 2 = 38.
+enum { MaxStringUuidLength = 38 };
+
+template <class Integral>
+void _q_toHex(char *&dst, Integral value)
{
value = qToBigEndian(value);
const char* p = reinterpret_cast<const char*>(&value);
for (uint i = 0; i < sizeof(Integral); ++i, dst += 2) {
- dst[0] = Char(QtMiscUtils::toHexLower((p[i] >> 4) & 0xf));
- dst[1] = Char(QtMiscUtils::toHexLower(p[i] & 0xf));
+ dst[0] = QtMiscUtils::toHexLower((p[i] >> 4) & 0xf);
+ dst[1] = QtMiscUtils::toHexLower(p[i] & 0xf);
}
}
-template <class Char, class Integral>
-bool _q_fromHex(const Char *&src, Integral &value)
+template <class Integral>
+bool _q_fromHex(const char *&src, Integral &value)
{
value = 0;
@@ -79,48 +84,64 @@ bool _q_fromHex(const Char *&src, Integral &value)
return true;
}
-template <class Char>
-void _q_uuidToHex(Char *&dst, const uint &d1, const ushort &d2, const ushort &d3, const uchar (&d4)[8])
+static char *_q_uuidToHex(const QUuid &uuid, char *dst)
{
- *dst++ = Char('{');
- _q_toHex(dst, d1);
- *dst++ = Char('-');
- _q_toHex(dst, d2);
- *dst++ = Char('-');
- _q_toHex(dst, d3);
- *dst++ = Char('-');
+ *dst++ = '{';
+ _q_toHex(dst, uuid.data1);
+ *dst++ = '-';
+ _q_toHex(dst, uuid.data2);
+ *dst++ = '-';
+ _q_toHex(dst, uuid.data3);
+ *dst++ = '-';
for (int i = 0; i < 2; i++)
- _q_toHex(dst, d4[i]);
- *dst++ = Char('-');
+ _q_toHex(dst, uuid.data4[i]);
+ *dst++ = '-';
for (int i = 2; i < 8; i++)
- _q_toHex(dst, d4[i]);
- *dst = Char('}');
+ _q_toHex(dst, uuid.data4[i]);
+ *dst++ = '}';
+ return dst;
}
-template <class Char>
-bool _q_uuidFromHex(const Char *&src, uint &d1, ushort &d2, ushort &d3, uchar (&d4)[8])
+/*!
+ \internal
+
+ Parses the string representation of a UUID (with optional surrounding "{}")
+ by reading at most MaxStringUuidLength (38) characters from \a src, which
+ may be \c nullptr. Stops at the first invalid character (which includes a
+ premature NUL).
+
+ Returns the successfully parsed QUuid, or a null QUuid in case of failure.
+*/
+Q_NEVER_INLINE
+static QUuid _q_uuidFromHex(const char *src)
{
- if (*src == Char('{'))
- src++;
- if (!_q_fromHex(src, d1)
- || *src++ != Char('-')
- || !_q_fromHex(src, d2)
- || *src++ != Char('-')
- || !_q_fromHex(src, d3)
- || *src++ != Char('-')
- || !_q_fromHex(src, d4[0])
- || !_q_fromHex(src, d4[1])
- || *src++ != Char('-')
- || !_q_fromHex(src, d4[2])
- || !_q_fromHex(src, d4[3])
- || !_q_fromHex(src, d4[4])
- || !_q_fromHex(src, d4[5])
- || !_q_fromHex(src, d4[6])
- || !_q_fromHex(src, d4[7])) {
- return false;
+ uint d1;
+ ushort d2, d3;
+ uchar d4[8];
+
+ if (src) {
+ if (*src == '{')
+ src++;
+ if (Q_LIKELY( _q_fromHex(src, d1)
+ && *src++ == '-'
+ && _q_fromHex(src, d2)
+ && *src++ == '-'
+ && _q_fromHex(src, d3)
+ && *src++ == '-'
+ && _q_fromHex(src, d4[0])
+ && _q_fromHex(src, d4[1])
+ && *src++ == '-'
+ && _q_fromHex(src, d4[2])
+ && _q_fromHex(src, d4[3])
+ && _q_fromHex(src, d4[4])
+ && _q_fromHex(src, d4[5])
+ && _q_fromHex(src, d4[6])
+ && _q_fromHex(src, d4[7]))) {
+ return QUuid(d1, d2, d3, d4[0], d4[1], d4[2], d4[3], d4[4], d4[5], d4[6], d4[7]);
+ }
}
- return true;
+ return QUuid();
}
#ifndef QT_BOOTSTRAPPED
@@ -331,7 +352,7 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto
/*!
Creates a QUuid object from the string \a text, which must be
formatted as five hex fields separated by '-', e.g.,
- "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' is a hex
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
digit. The curly braces shown here are optional, but it is normal to
include them. If the conversion fails, a null UUID is created. See
toString() for an explanation of how the five hex fields map to the
@@ -340,45 +361,76 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto
\sa toString(), QUuid()
*/
QUuid::QUuid(const QString &text)
+ : QUuid(fromString(text))
{
- if (text.length() < 36) {
- *this = QUuid();
- return;
- }
+}
+
+/*!
+ \since 5.10
- const ushort *data = reinterpret_cast<const ushort *>(text.unicode());
+ Creates a QUuid object from the string \a text, which must be
+ formatted as five hex fields separated by '-', e.g.,
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
+ digit. The curly braces shown here are optional, but it is normal to
+ include them. If the conversion fails, a null UUID is returned. See
+ toString() for an explanation of how the five hex fields map to the
+ public data members in QUuid.
- if (*data == '{' && text.length() < 37) {
- *this = QUuid();
- return;
- }
+ \sa toString(), QUuid()
+*/
+QUuid QUuid::fromString(QStringView text) Q_DECL_NOTHROW
+{
+ if (text.size() > MaxStringUuidLength)
+ text = text.left(MaxStringUuidLength); // text.truncate(MaxStringUuidLength);
+
+ char latin1[MaxStringUuidLength + 1];
+ char *dst = latin1;
+
+ for (QChar ch : text)
+ *dst++ = ch.toLatin1();
+
+ *dst++ = '\0'; // don't read garbage as potentially valid data
- if (!_q_uuidFromHex(data, data1, data2, data3, data4)) {
- *this = QUuid();
- return;
+ return _q_uuidFromHex(latin1);
+}
+
+/*!
+ \since 5.10
+ \overload
+
+ Creates a QUuid object from the string \a text, which must be
+ formatted as five hex fields separated by '-', e.g.,
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
+ digit. The curly braces shown here are optional, but it is normal to
+ include them. If the conversion fails, a null UUID is returned. See
+ toString() for an explanation of how the five hex fields map to the
+ public data members in QUuid.
+
+ \sa toString(), QUuid()
+*/
+QUuid QUuid::fromString(QLatin1String text) Q_DECL_NOTHROW
+{
+ if (Q_UNLIKELY(text.size() < MaxStringUuidLength - 2
+ || (text.front() == QLatin1Char('{') && text.size() < MaxStringUuidLength - 1))) {
+ // Too short. Don't call _q_uuidFromHex(); QL1Ss need not be NUL-terminated,
+ // and we don't want to read trailing garbage as potentially valid data.
+ text = QLatin1String();
}
+ return _q_uuidFromHex(text.data());
}
/*!
\internal
*/
QUuid::QUuid(const char *text)
+ : QUuid(_q_uuidFromHex(text))
{
- if (!text) {
- *this = QUuid();
- return;
- }
-
- if (!_q_uuidFromHex(text, data1, data2, data3, data4)) {
- *this = QUuid();
- return;
- }
}
/*!
Creates a QUuid object from the QByteArray \a text, which must be
formatted as five hex fields separated by '-', e.g.,
- "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' is a hex
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
digit. The curly braces shown here are optional, but it is normal to
include them. If the conversion fails, a null UUID is created. See
toByteArray() for an explanation of how the five hex fields map to the
@@ -389,23 +441,8 @@ QUuid::QUuid(const char *text)
\sa toByteArray(), QUuid()
*/
QUuid::QUuid(const QByteArray &text)
+ : QUuid(fromString(QLatin1String(text.data(), text.size())))
{
- if (text.length() < 36) {
- *this = QUuid();
- return;
- }
-
- const char *data = text.constData();
-
- if (*data == '{' && text.length() < 37) {
- *this = QUuid();
- return;
- }
-
- if (!_q_uuidFromHex(data, data1, data2, data3, data4)) {
- *this = QUuid();
- return;
- }
}
/*!
@@ -548,12 +585,11 @@ QUuid QUuid::fromRfc4122(const QByteArray &bytes)
*/
QString QUuid::toString() const
{
- QString result(38, Qt::Uninitialized);
- ushort *data = (ushort *)result.data();
-
- _q_uuidToHex(data, data1, data2, data3, data4);
-
- return result;
+ char latin1[MaxStringUuidLength];
+ const auto end = _q_uuidToHex(*this, latin1);
+ Q_ASSERT(end - latin1 == MaxStringUuidLength);
+ Q_UNUSED(end);
+ return QString::fromLatin1(latin1, MaxStringUuidLength);
}
/*!
@@ -594,11 +630,10 @@ QString QUuid::toString() const
*/
QByteArray QUuid::toByteArray() const
{
- QByteArray result(38, Qt::Uninitialized);
- char *data = result.data();
-
- _q_uuidToHex(data, data1, data2, data3, data4);
-
+ QByteArray result(MaxStringUuidLength, Qt::Uninitialized);
+ const auto end = _q_uuidToHex(*this, const_cast<char*>(result.constData()));
+ Q_ASSERT(end - result.constData() == MaxStringUuidLength);
+ Q_UNUSED(end);
return result;
}
diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h
index 264f572993..d975528dcf 100644
--- a/src/corelib/plugin/quuid.h
+++ b/src/corelib/plugin/quuid.h
@@ -116,6 +116,8 @@ public:
#endif
QUuid(const QString &);
+ static QUuid fromString(QStringView string) Q_DECL_NOTHROW;
+ static QUuid fromString(QLatin1String string) Q_DECL_NOTHROW;
QUuid(const char *);
QString toString() const;
QUuid(const QByteArray &);
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/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 996a1df9a0..b662475003 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -880,6 +880,51 @@ bool QThread::isInterruptionRequested() const
return d->interruptionRequested;
}
+/*
+ \fn template <typename Function, typename Args...> static QThread *QThread::create(Function &&f, Args &&... args)
+ \since 5.10
+
+ Creates a new QThread object that will execute the function \a f with the
+ arguments \a args.
+
+ The new thread is not started -- it must be started by an explicit call
+ to start(). This allows you to connect to its signals, move QObjects
+ to the thread, choose the new thread's priority and so on. The function
+ \a f will be called in the new thread.
+
+ Returns the newly created QThread instance.
+
+ \note the caller acquires ownership of the returned QThread instance.
+
+ \note this function is only available when using C++17.
+
+ \warning do not call start() on the returned QThread instance more than once;
+ doing so will result in undefined behavior.
+
+ \sa start()
+*/
+
+/*
+ \fn template <typename Function> static QThread *QThread::create(Function &&f)
+ \since 5.10
+
+ Creates a new QThread object that will execute the function \a f.
+
+ The new thread is not started -- it must be started by an explicit call
+ to start(). This allows you to connect to its signals, move QObjects
+ to the thread, choose the new thread's priority and so on. The function
+ \a f will be called in the new thread.
+
+ Returns the newly created QThread instance.
+
+ \note the caller acquires ownership of the returned QThread instance.
+
+ \warning do not call start() on the returned QThread instance more than once;
+ doing so will result in undefined behavior.
+
+ \sa start()
+*/
+
/*!
\class QDaemonThread
\since 5.5
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h
index 45786537e2..a061394deb 100644
--- a/src/corelib/thread/qthread.h
+++ b/src/corelib/thread/qthread.h
@@ -42,6 +42,23 @@
#include <QtCore/qobject.h>
+// The implementation of QThread::create uses various C++14/C++17 facilities;
+// we must check for their presence. For std::async (used in all codepaths)
+// there is no SG10 feature macro; just test for the header presence.
+// For the C++17 codepath do some more throughout checks for std::invoke and
+// C++14 lambdas availability.
+#if QT_HAS_INCLUDE(<future>)
+# define QTHREAD_HAS_CREATE
+# include <future> // for std::async
+# include <functional> // for std::invoke; no guard needed as it's a C++98 header
+
+# if defined(__cpp_lib_invoke) && __cpp_lib_invoke >= 201411 \
+ && defined(__cpp_init_captures) && __cpp_init_captures >= 201304 \
+ && defined(__cpp_generic_lambdas) && __cpp_generic_lambdas >= 201304
+# define QTHREAD_HAS_VARIADIC_CREATE
+# endif
+#endif
+
#include <limits.h>
QT_BEGIN_NAMESPACE
@@ -98,6 +115,16 @@ public:
bool event(QEvent *event) Q_DECL_OVERRIDE;
int loopLevel() const;
+#ifdef QTHREAD_HAS_CREATE
+#ifdef QTHREAD_HAS_VARIADIC_CREATE
+ template <typename Function, typename... Args>
+ static QThread *create(Function &&f, Args &&... args);
+#else
+ template <typename Function>
+ static QThread *create(Function &&f);
+#endif
+#endif
+
public Q_SLOTS:
void start(Priority = InheritPriority);
void terminate();
@@ -131,6 +158,99 @@ private:
friend class QThreadData;
};
+#ifdef QTHREAD_HAS_CREATE
+namespace QtPrivate {
+
+class QThreadCreateThread : public QThread
+{
+public:
+#if defined(QTHREAD_HAS_VARIADIC_CREATE)
+ // C++17: std::thread's constructor complying call
+ template <typename Function, typename... Args>
+ explicit QThreadCreateThread(Function &&f, Args &&... args)
+ : m_future(std::async(std::launch::deferred,
+ [f = static_cast<typename std::decay<Function>::type>(std::forward<Function>(f))](auto &&... largs) mutable -> void
+ {
+ (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
+ }, std::forward<Args>(args)...))
+ {
+ }
+#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304
+ // C++14: implementation for just one callable
+ template <typename Function>
+ explicit QThreadCreateThread(Function &&f)
+ : m_future(std::async(std::launch::deferred,
+ [f = static_cast<typename std::decay<Function>::type>(std::forward<Function>(f))]() mutable -> void
+ {
+ (void)f();
+ }))
+ {
+ }
+#else
+private:
+ // C++11: same as C++14, but with a workaround for not having generalized lambda captures
+ template <typename Function>
+ struct Callable
+ {
+ explicit Callable(Function &&f)
+ : m_function(std::forward<Function>(f))
+ {
+ }
+
+#if defined(Q_COMPILER_DEFAULT_MEMBERS) && defined(Q_COMPILER_DELETE_MEMBERS)
+ // Apply the same semantics of a lambda closure type w.r.t. the special
+ // member functions, if possible: delete the copy assignment operator,
+ // bring back all the others as per the RO5 (cf. §8.1.5.1/11 [expr.prim.lambda.closure])
+ ~Callable() = default;
+ Callable(const Callable &) = default;
+ Callable(Callable &&) = default;
+ Callable &operator=(const Callable &) = delete;
+ Callable &operator=(Callable &&) = default;
+#endif
+
+ void operator()()
+ {
+ (void)m_function();
+ }
+
+ typename std::decay<Function>::type m_function;
+ };
+
+public:
+ template <typename Function>
+ explicit QThreadCreateThread(Function &&f)
+ : m_future(std::async(std::launch::deferred, Callable<Function>(std::forward<Function>(f))))
+ {
+ }
+#endif // QTHREAD_HAS_VARIADIC_CREATE
+
+private:
+ void run() override
+ {
+ m_future.get();
+ }
+
+ std::future<void> m_future;
+};
+
+} // namespace QtPrivate
+
+#ifdef QTHREAD_HAS_VARIADIC_CREATE
+template <typename Function, typename... Args>
+QThread *QThread::create(Function &&f, Args &&... args)
+{
+ return new QtPrivate::QThreadCreateThread(std::forward<Function>(f), std::forward<Args>(args)...);
+}
+#else
+template <typename Function>
+QThread *QThread::create(Function &&f)
+{
+ return new QtPrivate::QThreadCreateThread(std::forward<Function>(f));
+}
+#endif // QTHREAD_HAS_VARIADIC_CREATE
+
+#endif // QTHREAD_HAS_CREATE
+
#else // QT_NO_THREAD
class Q_CORE_EXPORT QThread : public QObject
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index 885b4c0c1e..f3d4750177 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -184,8 +184,8 @@ public:
#endif // Q_OS_UNIX
#ifdef Q_OS_WIN
- static unsigned int __stdcall start(void *);
- static void finish(void *, bool lockAnyway=true);
+ static unsigned int __stdcall start(void *) Q_DECL_NOEXCEPT;
+ static void finish(void *, bool lockAnyway=true) Q_DECL_NOEXCEPT;
Qt::HANDLE handle;
unsigned int id;
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index f359d25a73..cddc4053b1 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -61,6 +61,10 @@
#include "qdebug.h"
+#ifdef __GLIBCXX__
+#include <cxxabi.h>
+#endif
+
#include <sched.h>
#include <errno.h>
@@ -324,49 +328,70 @@ void *QThreadPrivate::start(void *arg)
#endif
pthread_cleanup_push(QThreadPrivate::finish, arg);
- QThread *thr = reinterpret_cast<QThread *>(arg);
- QThreadData *data = QThreadData::get2(thr);
-
+#ifndef QT_NO_EXCEPTIONS
+ try
+#endif
{
- QMutexLocker locker(&thr->d_func()->mutex);
+ QThread *thr = reinterpret_cast<QThread *>(arg);
+ QThreadData *data = QThreadData::get2(thr);
- // do we need to reset the thread priority?
- if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
- thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
- }
-
- data->threadId.store(to_HANDLE(pthread_self()));
- set_thread_data(data);
+ {
+ QMutexLocker locker(&thr->d_func()->mutex);
- data->ref();
- data->quitNow = thr->d_func()->exited;
- }
+ // do we need to reset the thread priority?
+ if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
+ thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
+ }
- if (data->eventDispatcher.load()) // custom event dispatcher set?
- data->eventDispatcher.load()->startingUp();
- else
- createEventDispatcher(data);
+ data->threadId.store(to_HANDLE(pthread_self()));
+ set_thread_data(data);
-#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
- {
- // sets the name of the current thread.
- QString objectName = thr->objectName();
+ data->ref();
+ data->quitNow = thr->d_func()->exited;
+ }
- pthread_t thread_id = from_HANDLE<pthread_t>(data->threadId.load());
- if (Q_LIKELY(objectName.isEmpty()))
- setCurrentThreadName(thread_id, thr->metaObject()->className());
+ if (data->eventDispatcher.load()) // custom event dispatcher set?
+ data->eventDispatcher.load()->startingUp();
else
- setCurrentThreadName(thread_id, objectName.toLocal8Bit());
- }
+ createEventDispatcher(data);
+
+#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
+ {
+ // sets the name of the current thread.
+ QString objectName = thr->objectName();
+
+ pthread_t thread_id = from_HANDLE<pthread_t>(data->threadId.load());
+ if (Q_LIKELY(objectName.isEmpty()))
+ setCurrentThreadName(thread_id, thr->metaObject()->className());
+ else
+ setCurrentThreadName(thread_id, objectName.toLocal8Bit());
+ }
#endif
- emit thr->started(QThread::QPrivateSignal());
+ emit thr->started(QThread::QPrivateSignal());
#if !defined(Q_OS_ANDROID)
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
- pthread_testcancel();
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
#endif
- thr->run();
+ thr->run();
+ }
+#ifndef QT_NO_EXCEPTIONS
+#ifdef __GLIBCXX__
+ // POSIX thread cancellation under glibc is implemented by throwing an exception
+ // of this type. Do what libstdc++ is doing and handle it specially in order not to
+ // abort the application if user's code calls a cancellation function.
+ catch (const abi::__forced_unwind &) {
+ throw;
+ }
+#endif // __GLIBCXX__
+ catch (...) {
+ qTerminate();
+ }
+#endif // QT_NO_EXCEPTIONS
+ // This pop runs finish() below. It's outside the try/catch (and has its
+ // own try/catch) to prevent finish() to be run in case an exception is
+ // thrown.
pthread_cleanup_pop(1);
return 0;
@@ -374,35 +399,53 @@ void *QThreadPrivate::start(void *arg)
void QThreadPrivate::finish(void *arg)
{
- QThread *thr = reinterpret_cast<QThread *>(arg);
- QThreadPrivate *d = thr->d_func();
+#ifndef QT_NO_EXCEPTIONS
+ try
+#endif
+ {
+ QThread *thr = reinterpret_cast<QThread *>(arg);
+ QThreadPrivate *d = thr->d_func();
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->mutex);
- d->isInFinish = true;
- d->priority = QThread::InheritPriority;
- void *data = &d->data->tls;
- locker.unlock();
- emit thr->finished(QThread::QPrivateSignal());
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QThreadStorageData::finish((void **)data);
- locker.relock();
-
- QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.load();
- if (eventDispatcher) {
- d->data->eventDispatcher = 0;
+ d->isInFinish = true;
+ d->priority = QThread::InheritPriority;
+ void *data = &d->data->tls;
locker.unlock();
- eventDispatcher->closingDown();
- delete eventDispatcher;
+ emit thr->finished(QThread::QPrivateSignal());
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QThreadStorageData::finish((void **)data);
locker.relock();
- }
- d->running = false;
- d->finished = true;
- d->interruptionRequested = false;
+ QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.load();
+ if (eventDispatcher) {
+ d->data->eventDispatcher = 0;
+ locker.unlock();
+ eventDispatcher->closingDown();
+ delete eventDispatcher;
+ locker.relock();
+ }
+
+ d->running = false;
+ d->finished = true;
+ d->interruptionRequested = false;
- d->isInFinish = false;
- d->thread_done.wakeAll();
+ d->isInFinish = false;
+ d->thread_done.wakeAll();
+ }
+#ifndef QT_NO_EXCEPTIONS
+#ifdef __GLIBCXX__
+ // POSIX thread cancellation under glibc is implemented by throwing an exception
+ // of this type. Do what libstdc++ is doing and handle it specially in order not to
+ // abort the application if user's code calls a cancellation function.
+ catch (const abi::__forced_unwind &) {
+ throw;
+ }
+#endif // __GLIBCXX__
+ catch (...) {
+ qTerminate();
+ }
+#endif // QT_NO_EXCEPTIONS
}
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
index ef7bfc511d..24d3ca2d7d 100644
--- a/src/corelib/thread/qthread_win.cpp
+++ b/src/corelib/thread/qthread_win.cpp
@@ -344,7 +344,7 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data)
#ifndef QT_NO_THREAD
-unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg)
+unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg) Q_DECL_NOEXCEPT
{
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadData *data = QThreadData::get2(thr);
@@ -381,7 +381,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi
return 0;
}
-void QThreadPrivate::finish(void *arg, bool lockAnyway)
+void QThreadPrivate::finish(void *arg, bool lockAnyway) Q_DECL_NOEXCEPT
{
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadPrivate *d = thr->d_func();
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 329cc358d4..b5b48324e7 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -1134,6 +1134,13 @@ static inline char qToLower(char c)
Same as prepend(\a ch).
*/
+/*! \fn void QByteArray::shrink_to_fit()
+ \since 5.10
+
+ This function is provided for STL compatibility. It is equivalent to
+ squeeze().
+*/
+
/*! \fn QByteArray::QByteArray(const QByteArray &other)
Constructs a copy of \a other.
@@ -1446,6 +1453,66 @@ QByteArray &QByteArray::operator=(const char *str)
\overload
*/
+/*!
+ \fn char QByteArray::front() const
+ \since 5.10
+
+ Returns the first character in the byte array.
+ Same as \c{at(0)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty byte array constitutes
+ undefined behavior.
+
+ \sa back(), at(), operator[]()
+*/
+
+/*!
+ \fn char QByteArray::back() const
+ \since 5.10
+
+ Returns the last character in the byte array.
+ Same as \c{at(size() - 1)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty byte array constitutes
+ undefined behavior.
+
+ \sa front(), at(), operator[]()
+*/
+
+/*!
+ \fn QByteRef QByteArray::front()
+ \since 5.10
+
+ Returns a reference to the first character in the byte array.
+ Same as \c{operator[](0)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty byte array constitutes
+ undefined behavior.
+
+ \sa back(), at(), operator[]()
+*/
+
+/*!
+ \fn QByteRef QByteArray::back()
+ \since 5.10
+
+ Returns a reference to the last character in the byte array.
+ Same as \c{operator[](size() - 1)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty byte array constitutes
+ undefined behavior.
+
+ \sa front(), at(), operator[]()
+*/
+
/*! \fn bool QByteArray::contains(const QByteArray &ba) const
Returns \c true if the byte array contains an occurrence of the byte
@@ -2905,7 +2972,7 @@ bool QByteArray::endsWith(char ch) const
Example:
\snippet code/src_corelib_tools_qbytearray.cpp 27
- \sa right(), mid(), startsWith(), truncate()
+ \sa startsWith(), right(), mid(), chopped(), chop(), truncate()
*/
QByteArray QByteArray::left(int len) const
@@ -2927,7 +2994,7 @@ QByteArray QByteArray::left(int len) const
Example:
\snippet code/src_corelib_tools_qbytearray.cpp 28
- \sa endsWith(), left(), mid()
+ \sa endsWith(), left(), mid(), chopped(), chop(), truncate()
*/
QByteArray QByteArray::right(int len) const
@@ -2950,7 +3017,7 @@ QByteArray QByteArray::right(int len) const
Example:
\snippet code/src_corelib_tools_qbytearray.cpp 29
- \sa left(), right()
+ \sa left(), right(), chopped(), chop(), truncate()
*/
QByteArray QByteArray::mid(int pos, int len) const
@@ -2974,6 +3041,18 @@ QByteArray QByteArray::mid(int pos, int len) const
}
/*!
+ \fn QByteArray::chopped(int len) const
+ \since 5.10
+
+ Returns a byte array that contains the leftmost size() - \a len bytes of
+ this byte array.
+
+ \note The behavior is undefined if \a len is negative or greater than size().
+
+ \sa endsWith(), left(), right(), mid(), chop(), truncate()
+*/
+
+/*!
\fn QByteArray QByteArray::toLower() const
Returns a lowercase copy of the byte array. The bytearray is
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 03bb9b5747..144216a6ef 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -186,32 +186,36 @@ public:
{ qSwap(d, other.d); }
inline int size() const;
- bool isEmpty() const;
+ inline bool isEmpty() const;
void resize(int size);
QByteArray &fill(char c, int size = -1);
- int capacity() const;
- void reserve(int size);
- void squeeze();
+ inline int capacity() const;
+ inline void reserve(int size);
+ inline void squeeze();
#ifndef QT_NO_CAST_FROM_BYTEARRAY
- operator const char *() const;
- operator const void *() const;
+ inline operator const char *() const;
+ inline operator const void *() const;
#endif
- char *data();
- const char *data() const;
+ inline char *data();
+ inline const char *data() const;
inline const char *constData() const;
inline void detach();
- bool isDetached() const;
+ inline bool isDetached() const;
inline bool isSharedWith(const QByteArray &other) const { return d == other.d; }
void clear();
- char at(int i) const;
- char operator[](int i) const;
- char operator[](uint i) const;
- QByteRef operator[](int i);
- QByteRef operator[](uint i);
+ inline char at(int i) const;
+ inline char operator[](int i) const;
+ inline char operator[](uint i) const;
+ inline QByteRef operator[](int i);
+ inline QByteRef operator[](uint i);
+ char front() const Q_REQUIRED_RESULT { return at(0); }
+ inline QByteRef front() Q_REQUIRED_RESULT;
+ char back() const Q_REQUIRED_RESULT { return at(size() - 1); }
+ inline QByteRef back() Q_REQUIRED_RESULT;
int indexOf(char c, int from = 0) const;
int indexOf(const char *c, int from = 0) const;
@@ -220,9 +224,9 @@ public:
int lastIndexOf(const char *c, int from = -1) const;
int lastIndexOf(const QByteArray &a, int from = -1) const;
- bool contains(char c) const;
- bool contains(const char *a) const;
- bool contains(const QByteArray &a) const;
+ inline bool contains(char c) const;
+ inline bool contains(const char *a) const;
+ inline bool contains(const QByteArray &a) const;
int count(char c) const;
int count(const char *a) const;
int count(const QByteArray &a) const;
@@ -230,6 +234,8 @@ public:
Q_REQUIRED_RESULT QByteArray left(int len) const;
Q_REQUIRED_RESULT QByteArray right(int len) const;
Q_REQUIRED_RESULT QByteArray mid(int index, int len = -1) const;
+ Q_REQUIRED_RESULT QByteArray chopped(int len) const
+ { Q_ASSERT(len >= 0); Q_ASSERT(len <= size()); return left(size() - len); }
bool startsWith(const QByteArray &a) const;
bool startsWith(char c) const;
@@ -280,12 +286,12 @@ public:
Q_REQUIRED_RESULT QByteArray rightJustified(int width, char fill = ' ', bool truncate = false) const;
QByteArray &prepend(char c);
- QByteArray &prepend(int count, char c);
+ inline QByteArray &prepend(int count, char c);
QByteArray &prepend(const char *s);
QByteArray &prepend(const char *s, int len);
QByteArray &prepend(const QByteArray &a);
QByteArray &append(char c);
- QByteArray &append(int count, char c);
+ inline QByteArray &append(int count, char c);
QByteArray &append(const char *s);
QByteArray &append(const char *s, int len);
QByteArray &append(const QByteArray &a);
@@ -298,17 +304,17 @@ public:
QByteArray &replace(int index, int len, const char *s);
QByteArray &replace(int index, int len, const char *s, int alen);
QByteArray &replace(int index, int len, const QByteArray &s);
- QByteArray &replace(char before, const char *after);
+ inline QByteArray &replace(char before, const char *after);
QByteArray &replace(char before, const QByteArray &after);
- QByteArray &replace(const char *before, const char *after);
+ inline QByteArray &replace(const char *before, const char *after);
QByteArray &replace(const char *before, int bsize, const char *after, int asize);
QByteArray &replace(const QByteArray &before, const QByteArray &after);
- QByteArray &replace(const QByteArray &before, const char *after);
+ inline QByteArray &replace(const QByteArray &before, const char *after);
QByteArray &replace(const char *before, const QByteArray &after);
QByteArray &replace(char before, char after);
- QByteArray &operator+=(char c);
- QByteArray &operator+=(const char *s);
- QByteArray &operator+=(const QByteArray &a);
+ inline QByteArray &operator+=(char c);
+ inline QByteArray &operator+=(const char *s);
+ inline QByteArray &operator+=(const QByteArray &a);
QList<QByteArray> split(char sep) const;
@@ -352,13 +358,13 @@ public:
const QByteArray &include = QByteArray(),
char percent = '%') const;
- QByteArray &setNum(short, int base = 10);
- QByteArray &setNum(ushort, int base = 10);
- QByteArray &setNum(int, int base = 10);
- QByteArray &setNum(uint, int base = 10);
+ inline QByteArray &setNum(short, int base = 10);
+ inline QByteArray &setNum(ushort, int base = 10);
+ inline QByteArray &setNum(int, int base = 10);
+ inline QByteArray &setNum(uint, int base = 10);
QByteArray &setNum(qlonglong, int base = 10);
QByteArray &setNum(qulonglong, int base = 10);
- QByteArray &setNum(float, char f = 'g', int prec = 6);
+ inline QByteArray &setNum(float, char f = 'g', int prec = 6);
QByteArray &setNum(double, char f = 'g', int prec = 6);
QByteArray &setRawData(const char *a, uint n); // ### Qt 6: use an int
@@ -413,12 +419,13 @@ public:
typedef char *pointer;
typedef const char *const_pointer;
typedef char value_type;
- void push_back(char c);
- void push_back(const char *c);
- void push_back(const QByteArray &a);
- void push_front(char c);
- void push_front(const char *c);
- void push_front(const QByteArray &a);
+ inline void push_back(char c);
+ inline void push_back(const char *c);
+ inline void push_back(const QByteArray &a);
+ inline void push_front(char c);
+ inline void push_front(const char *c);
+ inline void push_front(const QByteArray &a);
+ void shrink_to_fit() { squeeze(); }
static inline QByteArray fromStdString(const std::string &s);
inline std::string toStdString() const;
@@ -549,6 +556,8 @@ inline QByteRef QByteArray::operator[](int i)
{ Q_ASSERT(i >= 0); return QByteRef(*this, i); }
inline QByteRef QByteArray::operator[](uint i)
{ return QByteRef(*this, i); }
+inline QByteRef QByteArray::front() { return operator[](0); }
+inline QByteRef QByteArray::back() { return operator[](size() - 1); }
inline QByteArray::iterator QByteArray::begin()
{ detach(); return d->data(); }
inline QByteArray::const_iterator QByteArray::begin() const
@@ -683,8 +692,4 @@ Q_DECLARE_SHARED(QByteArray)
QT_END_NAMESPACE
-#ifdef QT_USE_QSTRINGBUILDER
-#include <QtCore/qstring.h>
-#endif
-
#endif // QBYTEARRAY_H
diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp
index 1d3293e85e..5c887f47cd 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.
@@ -1532,6 +1550,11 @@ static inline ushort foldCase(ushort ch) Q_DECL_NOTHROW
return convertCase_helper<QUnicodeTables::CasefoldTraits>(ch);
}
+static inline QChar foldCase(QChar ch) Q_DECL_NOTHROW
+{
+ return QChar(foldCase(ch.unicode()));
+}
+
/*!
\fn QChar QChar::toCaseFolded() const
diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h
index 81ef67d116..53cb8993fb 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_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/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index bcdbc5af2a..b09499d25b 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -160,8 +160,7 @@ static ParsedDate getDateFromJulianDay(qint64 julianDay)
if (year <= 0)
--year ;
- const ParsedDate result = { year, month, day };
- return result;
+ return { year, month, day };
}
/*****************************************************************************
@@ -866,7 +865,7 @@ QString QDate::toString(Qt::DateFormat format) const
case Qt::DefaultLocaleLongDate:
return QLocale().toString(*this, QLocale::LongFormat);
case Qt::RFC2822Date:
- return QLocale::c().toString(*this, QStringLiteral("dd MMM yyyy"));
+ return QLocale::c().toString(*this, QStringViewLiteral("dd MMM yyyy"));
default:
#ifndef QT_NO_TEXTDATE
case Qt::TextDate:
@@ -879,6 +878,9 @@ QString QDate::toString(Qt::DateFormat format) const
}
/*!
+ \fn QString QDate::toString(const QString &format) const
+ \fn QString QDate::toString(QStringView format) const
+
Returns the date as a string. The \a format parameter determines
the format of the result string.
@@ -927,10 +929,18 @@ QString QDate::toString(Qt::DateFormat format) const
\sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString()
*/
-QString QDate::toString(const QString& format) const
+QString QDate::toString(QStringView format) const
{
return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
+
+#if QT_STRINGVIEW_LEVEL < 2
+QString QDate::toString(const QString &format) const
+{
+ return toString(qToStringViewIgnoringNull(format));
+}
+#endif
+
#endif //QT_NO_DATESTRING
/*!
@@ -1625,6 +1635,9 @@ QString QTime::toString(Qt::DateFormat format) const
}
/*!
+ \fn QString QTime::toString(const QString &format) const
+ \fn QString QTime::toString(QStringView format) const
+
Returns the time as a string. The \a format parameter determines
the format of the result string.
@@ -1675,11 +1688,20 @@ QString QTime::toString(Qt::DateFormat format) const
\sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString()
*/
-QString QTime::toString(const QString& format) const
+QString QTime::toString(QStringView format) const
{
return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
+
+#if QT_STRINGVIEW_VERSION < 2
+QString QTime::toString(const QString &format) const
+{
+ return toString(qToStringViewIgnoringNull(format));
+}
+#endif
+
#endif //QT_NO_DATESTRING
+
/*!
Sets the time to hour \a h, minute \a m, seconds \a s and
milliseconds \a ms.
@@ -3796,7 +3818,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
case Qt::DefaultLocaleLongDate:
return QLocale().toString(*this, QLocale::LongFormat);
case Qt::RFC2822Date: {
- buf = QLocale::c().toString(*this, QStringLiteral("dd MMM yyyy hh:mm:ss "));
+ buf = QLocale::c().toString(*this, QStringViewLiteral("dd MMM yyyy hh:mm:ss "));
buf += toOffsetString(Qt::TextDate, offsetFromUtc());
return buf;
}
@@ -3854,6 +3876,9 @@ QString QDateTime::toString(Qt::DateFormat format) const
}
/*!
+ \fn QString QDateTime::toString(const QString &format) const
+ \fn QString QDateTime::toString(QStringView format) const
+
Returns the datetime as a string. The \a format parameter
determines the format of the result string.
@@ -3926,10 +3951,18 @@ QString QDateTime::toString(Qt::DateFormat format) const
\sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString()
*/
-QString QDateTime::toString(const QString& format) const
+QString QDateTime::toString(QStringView format) const
{
return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
+
+#if QT_STRINGVIEW_LEVEL < 2
+QString QDateTime::toString(const QString &format) const
+{
+ return toString(qToStringViewIgnoringNull(format));
+}
+#endif
+
#endif //QT_NO_DATESTRING
static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date, QTime *time)
@@ -5265,7 +5298,7 @@ QDebug operator<<(QDebug dbg, const QDate &date)
QDebug operator<<(QDebug dbg, const QTime &time)
{
QDebugStateSaver saver(dbg);
- dbg.nospace() << "QTime(" << time.toString(QStringLiteral("HH:mm:ss.zzz")) << ')';
+ dbg.nospace() << "QTime(" << time.toString(QStringViewLiteral("HH:mm:ss.zzz")) << ')';
return dbg;
}
@@ -5274,7 +5307,7 @@ QDebug operator<<(QDebug dbg, const QDateTime &date)
QDebugStateSaver saver(dbg);
const Qt::TimeSpec ts = date.timeSpec();
dbg.nospace() << "QDateTime(";
- dbg.noquote() << date.toString(QStringLiteral("yyyy-MM-dd HH:mm:ss.zzz t"))
+ dbg.noquote() << date.toString(QStringViewLiteral("yyyy-MM-dd HH:mm:ss.zzz t"))
<< ' ' << ts;
switch (ts) {
case Qt::UTC:
diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h
index 2518dc7301..815fa12b23 100644
--- a/src/corelib/tools/qdatetime.h
+++ b/src/corelib/tools/qdatetime.h
@@ -89,8 +89,11 @@ public:
#endif // QT_NO_TEXTDATE
#ifndef QT_NO_DATESTRING
QString toString(Qt::DateFormat f = Qt::TextDate) const;
+#if QT_STRINGVIEW_LEVEL < 2
QString toString(const QString &format) const;
#endif
+ QString toString(QStringView format) const;
+#endif
#if QT_DEPRECATED_SINCE(5,0)
QT_DEPRECATED inline bool setYMD(int y, int m, int d)
{ if (uint(y) <= 99) y += 1900; return setDate(y, m, d); }
@@ -162,8 +165,11 @@ public:
int msec() const;
#ifndef QT_NO_DATESTRING
QString toString(Qt::DateFormat f = Qt::TextDate) const;
+#if QT_STRINGVIEW_LEVEL < 2
QString toString(const QString &format) const;
#endif
+ QString toString(QStringView format) const;
+#endif
bool setHMS(int h, int m, int s, int ms = 0);
Q_REQUIRED_RESULT QTime addSecs(int secs) const;
@@ -295,8 +301,11 @@ public:
#ifndef QT_NO_DATESTRING
QString toString(Qt::DateFormat f = Qt::TextDate) const;
+#if QT_STRINGVIEW_LEVEL < 2
QString toString(const QString &format) const;
#endif
+ QString toString(QStringView format) const;
+#endif
Q_REQUIRED_RESULT QDateTime addDays(qint64 days) const;
Q_REQUIRED_RESULT QDateTime addMonths(int months) const;
Q_REQUIRED_RESULT QDateTime addYears(int years) const;
diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp
index 62dd25e072..d46d9942d3 100644
--- a/src/corelib/tools/qdatetimeparser.cpp
+++ b/src/corelib/tools/qdatetimeparser.cpp
@@ -705,7 +705,7 @@ int QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionInde
state = Invalid;
int num = 0;
const SectionNode &sn = sectionNode(sectionIndex);
- if ((sn.type & Internal) == Internal) {
+ if (sn.type & Internal) {
qWarning("QDateTimeParser::parseSection Internal error (%s %d)",
qPrintable(sn.name()), sectionIndex);
return -1;
@@ -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
@@ -757,11 +756,9 @@ int QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionInde
if (sn.count >= 3) {
QString sectiontext = sectionTextRef.toString();
if (sn.type == MonthSection) {
- int min = 1;
const QDate minDate = getMinimum().date();
- if (currentValue.date().year() == minDate.year()) {
- min = minDate.month();
- }
+ const int min = (currentValue.date().year() == minDate.year())
+ ? minDate.month() : 1;
num = findMonth(sectiontext.toLower(), min, sectionIndex, &sectiontext, &used);
} else {
num = findDay(sectiontext.toLower(), 1, sectionIndex, &sectiontext, &used);
@@ -784,26 +781,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);
@@ -881,17 +877,199 @@ int QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionInde
#ifndef QT_NO_DATESTRING
/*!
\internal
+
+ Returns a date consistent with the given data on parts specified by known,
+ while staying as close to the given data as it can. Returns an invalid date
+ when on valid date is consistent with the data.
+*/
+
+static QDate actualDate(QDateTimeParser::Sections known, int year, int year2digits,
+ int month, int day, int dayofweek)
+{
+ QDate actual(year, month, day);
+ if (actual.isValid() && year % 100 == year2digits && actual.dayOfWeek() == dayofweek)
+ return actual; // The obvious candidate is fine :-)
+
+ if (dayofweek < 1 || dayofweek > 7) // Invalid: ignore
+ known &= ~QDateTimeParser::DayOfWeekSectionMask;
+
+ // Assuming year > 0 ...
+ if (year % 100 != year2digits) {
+ if (known & QDateTimeParser::YearSection2Digits) {
+ // Over-ride year, even if specified:
+ year += year2digits - year % 100;
+ known &= ~QDateTimeParser::YearSection;
+ } else {
+ year2digits = year % 100;
+ }
+ }
+ Q_ASSERT(year % 100 == year2digits);
+
+ if (month < 1) { // If invalid, clip to nearest valid and ignore in known.
+ month = 1;
+ known &= ~QDateTimeParser::MonthSection;
+ } else if (month > 12) {
+ month = 12;
+ known &= ~QDateTimeParser::MonthSection;
+ }
+
+ QDate first(year, month, 1);
+ int last = known & QDateTimeParser::YearSection && known & QDateTimeParser::MonthSection
+ ? first.daysInMonth() : 0;
+ // If we also know day-of-week, tweak last to the last in the month that matches it:
+ if (last && known & QDateTimeParser::DayOfWeekSectionMask) {
+ int diff = (dayofweek - first.dayOfWeek() - last) % 7;
+ Q_ASSERT(diff <= 0); // C++11 specifies (-ve) % (+ve) to be <= 0.
+ last += diff;
+ }
+ if (day < 1) {
+ if (known & QDateTimeParser::DayOfWeekSectionMask && last) {
+ day = 1 + dayofweek - first.dayOfWeek();
+ if (day < 1)
+ day += 7;
+ } else {
+ day = 1;
+ }
+ known &= ~QDateTimeParser::DaySection;
+ } else if (day > 31) {
+ day = last;
+ known &= ~QDateTimeParser::DaySection;
+ } else if (last && day > last && (known & QDateTimeParser::DaySection) == 0) {
+ day = last;
+ }
+
+ actual = QDate(year, month, day);
+ if (!actual.isValid() // We can't do better than we have, in this case
+ || (known & QDateTimeParser::DaySection
+ && known & QDateTimeParser::MonthSection
+ && known & QDateTimeParser::YearSection) // ditto
+ || actual.dayOfWeek() == dayofweek // Good enough, use it.
+ || (known & QDateTimeParser::DayOfWeekSectionMask) == 0) { // No contradiction, use it.
+ return actual;
+ }
+
+ /*
+ Now it gets trickier.
+
+ We have some inconsistency in our data; we've been told day of week, but
+ it doesn't fit with our year, month and day. At least one of these is
+ unknown, though: so we can fix day of week by tweaking it.
+ */
+
+ if ((known & QDateTimeParser::DaySection) == 0) {
+ // Relatively easy to fix.
+ day += dayofweek - actual.dayOfWeek();
+ if (day < 1)
+ day += 7;
+ else if (day > actual.daysInMonth())
+ day -= 7;
+ actual = QDate(year, month, day);
+ return actual;
+ }
+
+ if ((known & QDateTimeParser::MonthSection) == 0) {
+ /*
+ Try possible month-offsets, m, preferring small; at least one (present
+ month doesn't work) and at most 11 (max month, 12, minus min, 1); try
+ in both directions, ignoring any offset that takes us out of range.
+ */
+ for (int m = 1; m < 12; m++) {
+ if (m < month) {
+ actual = QDate(year, month - m, day);
+ if (actual.dayOfWeek() == dayofweek)
+ return actual;
+ }
+ if (m + month <= 12) {
+ actual = QDate(year, month + m, day);
+ if (actual.dayOfWeek() == dayofweek)
+ return actual;
+ }
+ }
+ // Should only get here in corner cases; e.g. day == 31
+ actual = QDate(year, month, day); // Restore from trial values.
+ }
+
+ if ((known & QDateTimeParser::YearSection) == 0) {
+ if (known & QDateTimeParser::YearSection2Digits) {
+ /*
+ Two-digit year and month are specified; choice of century can only
+ fix this if diff is in one of {1, 2, 5} or {2, 4, 6}; but not if
+ diff is in the other. It's also only reasonable to consider
+ adjacent century, e.g. if year thinks it's 2012 and two-digit year
+ is '97, it makes sense to consider 1997. If either adjacent
+ century does work, the other won't.
+ */
+ actual = QDate(year + 100, month, day);
+ if (actual.dayOfWeek() == dayofweek)
+ return actual;
+ actual = QDate(year - 100, month, day);
+ if (actual.dayOfWeek() == dayofweek)
+ return actual;
+ } else {
+ // Offset by 7 is usually enough, but rare cases may need more:
+ for (int y = 1; y < 12; y++) {
+ actual = QDate(year - y, month, day);
+ if (actual.dayOfWeek() == dayofweek)
+ return actual;
+ actual = QDate(year + y, month, day);
+ if (actual.dayOfWeek() == dayofweek)
+ return actual;
+ }
+ }
+ actual = QDate(year, month, day); // Restore from trial values.
+ }
+
+ return actual; // It'll just have to do :-(
+}
+
+/*!
+ \internal
+*/
+
+static QTime actualTime(QDateTimeParser::Sections known,
+ int hour, int hour12, int ampm,
+ int minute, int second, int msec)
+{
+ // If we have no conflict, or don't know enough to diagonose one, use this:
+ QTime actual(hour, minute, second, msec);
+ if (hour12 < 0 || hour12 > 12) { // ignore bogus value
+ known &= ~QDateTimeParser::Hour12Section;
+ hour12 = hour % 12;
+ }
+
+ if (ampm == -1 || (known & QDateTimeParser::AmPmSection) == 0) {
+ if ((known & QDateTimeParser::Hour12Section) == 0 || hour % 12 == hour12)
+ return actual;
+
+ if ((known & QDateTimeParser::Hour24Section) == 0)
+ hour = hour12 + (hour > 12 ? 12 : 0);
+ } else {
+ Q_ASSERT(ampm == 0 || ampm == 1);
+ if (hour - hour12 == ampm * 12)
+ return actual;
+
+ if ((known & QDateTimeParser::Hour24Section) == 0
+ && known & QDateTimeParser::Hour12Section) {
+ hour = hour12 + ampm * 12;
+ }
+ }
+ actual = QTime(hour, minute, second, msec);
+ return actual;
+}
+
+/*!
+ \internal
*/
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 +1077,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 +1107,12 @@ 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(QDateTime(actualDate(isSet, year, year2digits,
+ month, day, dayofweek),
+ actualTime(isSet, hour, hour12, ampm,
+ minute, second, msec),
+ spec),
+ index, input, cursorPosition, pos, tmpstate, &used);
QDTPDEBUG << "sectionValue" << sn.name() << input
<< "pos" << pos << "used" << used << stateName(tmpstate);
if (fixup && tmpstate == Intermediate && used < sn.count) {
@@ -1067,8 +1250,8 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos
input.replace(sectionPos(sn), sectionSize(i), dayName);
}
}
- } else {
- state = qMin(Intermediate, state);
+ } else if (state > Intermediate) {
+ state = Intermediate;
}
}
}
@@ -1099,20 +1282,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 +1321,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 +1331,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 +1352,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 +1386,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 +1407,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;
}
@@ -1461,15 +1646,13 @@ QDateTimeParser::FieldInfo QDateTimeParser::fieldInfo(int index) const
case MinuteSection:
case Hour24Section:
case Hour12Section:
- case YearSection:
case YearSection2Digits:
+ ret |= AllowPartial;
+ Q_FALLTHROUGH();
+ case YearSection:
ret |= Numeric;
- if (sn.type != YearSection) {
- ret |= AllowPartial;
- }
- if (sn.count != 1) {
+ if (sn.count != 1)
ret |= FixedWidth;
- }
break;
case MonthSection:
case DaySection:
@@ -1596,14 +1779,13 @@ bool QDateTimeParser::skipToNextSection(int index, const QDateTime &current, con
if (pos < 0 || pos >= text.size())
pos = -1;
- const bool potential = potentialValue(text, min, max, index, current, pos);
- return !potential;
-
- /* If the value potentially can become another valid entry we
- * don't want to skip to the next. E.g. In a M field (month
- * without leading 0 if you type 1 we don't want to autoskip but
- * if you type 3 we do
+ /*
+ If the value potentially can become another valid entry we don't want to
+ skip to the next. E.g. In a M field (month without leading 0) if you type
+ 1 we don't want to autoskip (there might be [012] following) but if you
+ type 3 we do.
*/
+ return !potentialValue(text, min, max, index, current, pos);
}
/*!
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 1f9c05c0b7..59aab32347 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -203,7 +203,7 @@ static inline uint hash(const uchar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
- if (hasFastCrc32())
+ if (seed && hasFastCrc32())
return crc32(p, len, h);
for (size_t i = 0; i < len; ++i)
@@ -221,7 +221,7 @@ static inline uint hash(const QChar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
- if (hasFastCrc32())
+ if (seed && hasFastCrc32())
return crc32(p, len, h);
for (size_t i = 0; i < len; ++i)
@@ -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
{
@@ -281,8 +288,15 @@ static uint qt_create_qhash_seed()
#ifndef QT_BOOTSTRAPPED
QByteArray envSeed = qgetenv("QT_HASH_SEED");
- if (!envSeed.isNull())
- return envSeed.toUInt();
+ if (!envSeed.isNull()) {
+ uint seed = envSeed.toUInt();
+ if (seed) {
+ // can't use qWarning here (reentrancy)
+ fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0, cannot guarantee that the "
+ "hashing functions will produce a stable value.");
+ }
+ return seed;
+ }
#ifdef Q_OS_UNIX
int randomfd = qt_safe_open("/dev/urandom", O_RDONLY);
@@ -372,14 +386,17 @@ int qGlobalQHashSeed()
is needed. We discourage to do it in production code as it can make your
application susceptible to \l{algorithmic complexity attacks}.
+ From Qt 5.10 and onwards, the only allowed values are 0 and -1. Passing the
+ value -1 will reinitialize the global QHash seed to a random value, while
+ the value of 0 is used to request a stable algorithm for C++ primitive
+ types types (like \c int) and string types (QString, QByteArray).
+
The seed is set in any newly created QHash. See \l{qHash} about how this seed
is being used by QHash.
If the environment variable \c QT_HASH_SEED is set, calling this function will
result in a no-op.
- Passing the value -1 will reinitialize the global QHash seed to a random value.
-
\sa qGlobalQHashSeed
*/
void qSetGlobalQHashSeed(int newSeed)
@@ -390,6 +407,11 @@ void qSetGlobalQHashSeed(int newSeed)
int x(qt_create_qhash_seed() & INT_MAX);
qt_qhash_seed.store(x);
} else {
+ if (newSeed) {
+ // can't use qWarning here (reentrancy)
+ fprintf(stderr, "qSetGlobalQHashSeed: forced seed value is not 0, cannot guarantee that the "
+ "hashing functions will produce a stable value.");
+ }
qt_qhash_seed.store(newSeed & INT_MAX);
}
}
@@ -405,37 +427,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 +1043,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
@@ -1252,9 +1269,8 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
should never depend on a particular QHash ordering, there may be situations
where you temporarily need deterministic behavior, for example for debugging or
regression testing. To disable the randomization, define the environment
- variable \c QT_HASH_SEED. The contents of that variable, interpreted as a
- decimal value, will be used as the seed for qHash(). Alternatively, you can
- call the qSetGlobalQHashSeed() function.
+ variable \c QT_HASH_SEED to have the value 0. Alternatively, you can call
+ the qSetGlobalQHashSeed() function with the value 0.
\sa QHashIterator, QMutableHashIterator, QMap, QSet
*/
@@ -1706,6 +1722,60 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
\sa keyBegin()
*/
+/*! \fn QHash::key_value_iterator QHash::keyValueBegin()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn QHash::key_value_iterator QHash::keyValueEnd()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn QHash::const_key_value_iterator QHash::keyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn QHash::const_key_value_iterator QHash::constKeyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn QHash::const_key_value_iterator QHash::keyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn QHash::const_key_value_iterator QHash::constKeyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \sa constKeyValueBegin()
+*/
+
/*! \fn QHash::iterator QHash::erase(const_iterator pos)
\since 5.7
@@ -2441,6 +2511,18 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW
Returns the underlying const_iterator this key_iterator is based on.
*/
+/*! \typedef QHash::key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QHash and QMultiHash.
+
+ QHash::key_value_iterator is essentially the same as QHash::iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash)
\relates QHash
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index b2c3cf574d..d7378df746 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -449,6 +449,9 @@ public:
const_iterator base() const { return i; }
};
+ typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
+ typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
+
// STL style
inline iterator begin() { detach(); return iterator(d->firstNode()); }
inline const_iterator begin() const { return const_iterator(d->firstNode()); }
@@ -460,6 +463,12 @@ public:
inline const_iterator constEnd() const { return const_iterator(e); }
inline key_iterator keyBegin() const { return key_iterator(begin()); }
inline key_iterator keyEnd() const { return key_iterator(end()); }
+ inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
+ inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
+ inline const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
QPair<iterator, iterator> equal_range(const Key &key);
QPair<const_iterator, const_iterator> equal_range(const Key &key) const Q_DECL_NOTHROW;
@@ -816,7 +825,7 @@ Q_OUTOFLINE_TEMPLATE T QHash<Key, T>::take(const Key &akey)
Node **node = findNode(akey);
if (*node != e) {
- T t = (*node)->value;
+ T t = std::move((*node)->value);
Node *next = (*node)->next;
deleteNode(*node);
*node = next;
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/qiterator.h b/src/corelib/tools/qiterator.h
index 3953005242..9550c302bb 100644
--- a/src/corelib/tools/qiterator.h
+++ b/src/corelib/tools/qiterator.h
@@ -179,6 +179,157 @@ public: \
n = c->end(); return false; } \
};
+template<typename Key, typename T, class Iterator>
+class QKeyValueIterator
+{
+public:
+ typedef typename Iterator::iterator_category iterator_category;
+ typedef typename Iterator::difference_type difference_type;
+ typedef std::pair<Key, T> value_type;
+ typedef const value_type *pointer;
+ typedef const value_type &reference;
+
+ QKeyValueIterator() = default;
+ Q_DECL_CONSTEXPR explicit QKeyValueIterator(Iterator o) Q_DECL_NOEXCEPT_EXPR(std::is_nothrow_move_constructible<Iterator>::value)
+ : i(std::move(o)) {}
+
+ std::pair<Key, T> operator*() const {
+ return std::pair<Key, T>(i.key(), i.value());
+ }
+
+ friend Q_DECL_CONSTEXPR bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) Q_DECL_NOEXCEPT { return lhs.i == rhs.i; }
+ friend Q_DECL_CONSTEXPR bool operator!=(QKeyValueIterator lhs, QKeyValueIterator rhs) Q_DECL_NOEXCEPT { return lhs.i != rhs.i; }
+
+ inline QKeyValueIterator &operator++() { ++i; return *this; }
+ inline QKeyValueIterator operator++(int) { return QKeyValueIterator(i++);}
+ inline QKeyValueIterator &operator--() { --i; return *this; }
+ inline QKeyValueIterator operator--(int) { return QKeyValueIterator(i--); }
+ Iterator base() const { return i; }
+
+private:
+ Iterator i;
+};
+
+/*! \class QKeyValueIterator
+ \inmodule QtCore
+ \since 5.10
+
+ \brief Iterator over the key/value pairs of an associative container.
+
+ The QKeyValueIterator class provides an STL-style iterator for returning
+ key/value pairs from associative containers like QHash and QMap. It
+ supports the same API as the STL associative containers, i.e. getting a
+ key/value pair when iterating through the container.
+
+ This will allow for better interoperability between QMap, QHash and friends
+ and STL-style algorithms.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+*/
+
+/*! \typedef QKeyValueIterator::iterator_category
+ \internal
+*/
+
+/*! \typedef QKeyValueIterator::difference_type
+ \internal
+*/
+
+/*! \typedef QKeyValueIterator::value_type
+ \internal
+*/
+
+/*! \typedef QKeyValueIterator::pointer
+ \internal
+*/
+
+/*! \typedef QKeyValueIterator::reference
+ \internal
+*/
+
+/*! \fn QKeyValueIterator()
+
+ Constructs a default QKeyValueIterator.
+*/
+
+/*! \fn QKeyValueIterator(Iterator o)
+
+ Constructs a QKeyValueIterator on top of \a o.
+*/
+
+/*! \fn const T &QKeyValueIterator::operator*() const
+
+ Returns the current entry as a pair.
+*/
+
+/*! \fn bool QKeyValueIterator::operator==(QKeyValueIterator lhs, QKeyValueIterator rhs)
+
+ Returns \c true if \a rhs points to the same item as \a lhs otherwise returns
+ \c false.
+
+ \sa operator!=()
+*/
+
+/*! \fn bool QKeyValueIterator::operator!=(QKeyValueIterator lhs, QKeyValueIterator rhs) const
+
+ Returns \c true if \a rhs points to a different item than \a lhs otherwise
+ returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn QKeyValueIterator &QKeyValueIterator::operator++()
+
+ The prefix ++ operator (\c{++i}) advances the iterator to the
+ next item in the container and returns the iterator.
+
+ \note Advancing the iterator past its container's end() constitutes
+ undefined behavior.
+
+ \sa operator--()
+*/
+
+/*! \fn QKeyValueIterator QKeyValueIterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{i++}) advances the iterator to the
+ next item in the container and returns the iterator's prior value.
+
+ \note Advancing the iterator past its container's end() constitutes
+ undefined behavior.
+*/
+
+/*! \fn QKeyValueIterator &QKeyValueIterator::operator--()
+
+ The prefix -- operator (\c{--i}) backs the iterator up to the previous item
+ in the container and returns the iterator.
+
+ \note Backing up an iterator to before its container's begin() constitutes
+ undefined behavior.
+
+ \sa operator++()
+*/
+
+/*! \fn QKeyValueIterator QKeyValueIterator::operator--(int)
+
+ \overload
+
+ The postfix -- operator (\c{i--}) backs the iterator up to the previous item
+ in the container and returns the iterator's prior value.
+
+ \note Backing up an iterator to before its container's begin() constitutes
+ undefined behavior.
+*/
+
+/*! \fn Iterator QKeyValueIterator::base() const
+ Returns the underlying iterator this QKeyValueIterator is based on.
+*/
+
QT_END_NAMESPACE
#endif // QITERATOR_H
diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h
index 249f76dafd..9f54ba7825 100644
--- a/src/corelib/tools/qlinkedlist.h
+++ b/src/corelib/tools/qlinkedlist.h
@@ -448,7 +448,7 @@ bool QLinkedList<T>::removeOne(const T &_t)
template <typename T>
inline T QLinkedList<T>::takeFirst()
{
- T t = first();
+ T t = std::move(first());
removeFirst();
return t;
}
@@ -456,7 +456,7 @@ inline T QLinkedList<T>::takeFirst()
template <typename T>
inline T QLinkedList<T>::takeLast()
{
- T t = last();
+ T t = std::move(last());
removeLast();
return t;
}
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index e2706de9ee..1042c29460 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -555,14 +555,14 @@ inline void QList<T>::removeAt(int i)
template <typename T>
inline T QList<T>::takeAt(int i)
{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::take", "index out of range");
- detach(); Node *n = reinterpret_cast<Node *>(p.at(i)); T t = n->t(); node_destruct(n);
+ detach(); Node *n = reinterpret_cast<Node *>(p.at(i)); T t = std::move(n->t()); node_destruct(n);
p.remove(i); return t; }
template <typename T>
inline T QList<T>::takeFirst()
-{ T t = first(); removeFirst(); return t; }
+{ T t = std::move(first()); removeFirst(); return t; }
template <typename T>
inline T QList<T>::takeLast()
-{ T t = last(); removeLast(); return t; }
+{ T t = std::move(last()); removeLast(); return t; }
template <typename T>
Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc)
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index dcdf6b5ed7..5557b5af2d 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
@@ -527,7 +518,7 @@ static const QLocaleData *findLocaleData(const QString &name)
return QLocaleData::findLocaleData(lang, script, cntry);
}
-QString qt_readEscapedFormatString(const QString &format, int *idx)
+QString qt_readEscapedFormatString(QStringView format, int *idx)
{
int &i = *idx;
@@ -561,13 +552,31 @@ QString qt_readEscapedFormatString(const QString &format, int *idx)
return result;
}
-int qt_repeatCount(const QString &s, int i)
+/*!
+ \internal
+
+ Counts the number of identical leading characters in \a s.
+
+ If \a s is empty, returns 0.
+
+ Otherwise, returns the number of consecutive \c{s.front()}
+ characters at the start of \a s.
+
+ \code
+ qt_repeatCount(u"a"); // == 1
+ qt_repeatCount(u"ab"); // == 1
+ qt_repeatCount(u"aab"); // == 2
+ \endcode
+*/
+int qt_repeatCount(QStringView s)
{
- QChar c = s.at(i);
- int j = i + 1;
+ if (s.isEmpty())
+ return 0;
+ const QChar c = s.front();
+ qssize_t j = 1;
while (j < s.size() && s.at(j) == c)
++j;
- return j - i;
+ return int(j);
}
static const QLocaleData *default_data = 0;
@@ -1122,27 +1131,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 +1220,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 +1236,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 +1254,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 +1272,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 +1290,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 +1309,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 +1328,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 +1371,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 +1391,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 +1411,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 +1431,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 +1451,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 +1472,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 +1493,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 +1540,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.
@@ -1564,6 +1743,7 @@ QString QLocale::toString(qulonglong i) const
return d->m_data->unsLongLongToString(i, -1, 10, -1, flags);
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a localized string representation of the given \a date in the
specified \a format.
@@ -1574,6 +1754,19 @@ QString QLocale::toString(const QDate &date, const QString &format) const
{
return d->dateTimeToString(format, QDateTime(), date, QTime(), this);
}
+#endif
+
+/*!
+ \since 5.10
+
+ Returns a localized string representation of the given \a date in the
+ specified \a format.
+ If \a format is an empty string, an empty string is returned.
+*/
+QString QLocale::toString(const QDate &date, QStringView format) const
+{
+ return d->dateTimeToString(format, QDateTime(), date, QTime(), this);
+}
/*!
Returns a localized string representation of the given \a date according
@@ -1599,7 +1792,7 @@ QString QLocale::toString(const QDate &date, FormatType format) const
return toString(date, format_str);
}
-static bool timeFormatContainsAP(const QString &format)
+static bool timeFormatContainsAP(QStringView format)
{
int i = 0;
while (i < format.size()) {
@@ -1616,6 +1809,7 @@ static bool timeFormatContainsAP(const QString &format)
return false;
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a localized string representation of the given \a time according
to the specified \a format.
@@ -1625,7 +1819,21 @@ QString QLocale::toString(const QTime &time, const QString &format) const
{
return d->dateTimeToString(format, QDateTime(), QDate(), time, this);
}
+#endif
+
+/*!
+ \since 5.10
+
+ Returns a localized string representation of the given \a time according
+ to the specified \a format.
+ If \a format is an empty string, an empty string is returned.
+*/
+QString QLocale::toString(const QTime &time, QStringView format) const
+{
+ return d->dateTimeToString(format, QDateTime(), QDate(), time, this);
+}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
\since 4.4
@@ -1638,6 +1846,19 @@ QString QLocale::toString(const QDateTime &dateTime, const QString &format) cons
{
return d->dateTimeToString(format, dateTime, QDate(), QTime(), this);
}
+#endif
+
+/*!
+ \since 5.10
+
+ Returns a localized string representation of the given \a dateTime according
+ to the specified \a format.
+ If \a format is an empty string, an empty string is returned.
+*/
+QString QLocale::toString(const QDateTime &dateTime, QStringView format) const
+{
+ return d->dateTimeToString(format, dateTime, QDate(), QTime(), this);
+}
/*!
\since 4.4
@@ -2549,7 +2770,7 @@ QString QLocale::pmText() const
}
-QString QLocalePrivate::dateTimeToString(const QString &format, const QDateTime &datetime,
+QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &datetime,
const QDate &dateOnly, const QTime &timeOnly,
const QLocale *q) const
{
@@ -2582,7 +2803,7 @@ QString QLocalePrivate::dateTimeToString(const QString &format, const QDateTime
}
const QChar c = format.at(i);
- int repeat = qt_repeatCount(format, i);
+ int repeat = qt_repeatCount(format.mid(i));
bool used = false;
if (formatDate) {
switch (c.unicode()) {
@@ -2717,7 +2938,7 @@ QString QLocalePrivate::dateTimeToString(const QString &format, const QDateTime
case 'a':
used = true;
- if (i + 1 < format.length() && format.at(i + 1).unicode() == 'p') {
+ if (i + 1 < format.size() && format.at(i + 1).unicode() == 'p') {
repeat = 2;
} else {
repeat = 1;
@@ -2727,7 +2948,7 @@ QString QLocalePrivate::dateTimeToString(const QString &format, const QDateTime
case 'A':
used = true;
- if (i + 1 < format.length() && format.at(i + 1).unicode() == 'P') {
+ if (i + 1 < format.size() && format.at(i + 1).unicode() == 'P') {
repeat = 2;
} else {
repeat = 1;
@@ -3079,12 +3300,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())
@@ -3202,7 +3423,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();
@@ -3216,7 +3437,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 (qssize_t i = 0; i < str.size(); ++i) {
char c = digitToCLocale(str.at(i));
if (c >= '0' && c <= '9') {
@@ -3303,11 +3524,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;
@@ -3320,11 +3541,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;
@@ -3333,11 +3554,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;
@@ -3346,7 +3567,7 @@ qulonglong QLocaleData::stringToUnsLongLong(const QChar *begin, int len, int bas
return bytearrayToUnsLongLong(buff.constData(), base, ok);
}
-double QLocaleData::bytearrayToDouble(const char *num, bool *ok, bool *overflow)
+double QLocaleData::bytearrayToDouble(const char *num, bool *ok)
{
bool nonNullOk = false;
int len = static_cast<int>(strlen(num));
@@ -3355,12 +3576,10 @@ double QLocaleData::bytearrayToDouble(const char *num, bool *ok, bool *overflow)
double d = asciiToDouble(num, len, nonNullOk, processed);
if (ok)
*ok = nonNullOk;
- if (overflow)
- *overflow = processed < len;
return d;
}
-qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok, bool *overflow)
+qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok)
{
bool _ok;
const char *endptr;
@@ -3368,8 +3587,6 @@ qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok,
if (*num == '\0') {
if (ok != 0)
*ok = false;
- if (overflow != 0)
- *overflow = false;
return 0;
}
@@ -3378,11 +3595,6 @@ qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok,
if (!_ok) {
if (ok != 0)
*ok = false;
- if (overflow != 0) {
- // the only way qstrtoll can fail with *endptr != '\0' on a non-empty
- // input string is overflow
- *overflow = *endptr != '\0';
- }
return 0;
}
@@ -3390,15 +3602,11 @@ qlonglong QLocaleData::bytearrayToLongLong(const char *num, int base, bool *ok,
// we stopped at a non-digit character after converting some digits
if (ok != 0)
*ok = false;
- if (overflow != 0)
- *overflow = false;
return 0;
}
if (ok != 0)
*ok = true;
- if (overflow != 0)
- *overflow = false;
return l;
}
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index bd89e48234..f9482a7e3a 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;
@@ -961,12 +972,18 @@ public:
inline QString toString(uint i) const;
QString toString(double i, char f = 'g', int prec = 6) const;
inline QString toString(float i, char f = 'g', int prec = 6) const;
+
+#if QT_STRINGVIEW_LEVEL < 2
QString toString(const QDate &date, const QString &formatStr) const;
- QString toString(const QDate &date, FormatType format = LongFormat) const;
QString toString(const QTime &time, const QString &formatStr) const;
+ QString toString(const QDateTime &dateTime, const QString &format) const;
+#endif
+ QString toString(const QDate &date, QStringView formatStr) const;
+ QString toString(const QTime &time, QStringView formatStr) const;
+ QString toString(const QDateTime &dateTime, QStringView format) const;
+ QString toString(const QDate &date, FormatType format = LongFormat) const;
QString toString(const QTime &time, FormatType format = LongFormat) const;
QString toString(const QDateTime &dateTime, FormatType format = LongFormat) const;
- QString toString(const QDateTime &dateTime, const QString &format) const;
QString dateFormat(FormatType format = LongFormat) const;
QString timeFormat(FormatType format = LongFormat) const;
diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm
index c5519bfabf..edbaaf5d18 100644
--- a/src/corelib/tools/qlocale_mac.mm
+++ b/src/corelib/tools/qlocale_mac.mm
@@ -150,7 +150,7 @@ static QString macTimeToString(const QTime &time, bool short_format)
// See also qtbase/util/local_database/dateconverter.py
// Makes the assumption that input formats are always well formed and consecutive letters
// never exceed the maximum for the format code.
-static QString macToQtFormat(const QString &sys_fmt)
+static QString macToQtFormat(QStringView sys_fmt)
{
QString result;
int i = 0;
@@ -166,7 +166,7 @@ static QString macToQtFormat(const QString &sys_fmt)
}
QChar c = sys_fmt.at(i);
- int repeat = qt_repeatCount(sys_fmt, i);
+ int repeat = qt_repeatCount(sys_fmt.mid(i));
switch (c.unicode()) {
// Qt does not support the following options
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index f7adb021b6..e77b73c089 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;
-
- // 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,
+ 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;
+
+ static double bytearrayToDouble(const char *num, bool *ok);
+ // this function is used in QIntValidator (QtGui)
+ Q_CORE_EXPORT static qint64 bytearrayToLongLong(const char *num, int base, bool *ok);
+ static quint64 bytearrayToUnsLongLong(const char *num, int base, bool *ok);
+
+ 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);
@@ -373,7 +362,7 @@ public:
static void updateSystemPrivate();
- QString dateTimeToString(const QString &format, const QDateTime &datetime,
+ QString dateTimeToString(QStringView format, const QDateTime &datetime,
const QDate &dateOnly, const QTime &timeOnly,
const QLocale *q) const;
@@ -423,9 +412,9 @@ inline char QLocaleData::digitToCLocale(QChar in) const
return 0;
}
-QString qt_readEscapedFormatString(const QString &format, int *idx);
+QString qt_readEscapedFormatString(QStringView format, int *idx);
bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry);
-int qt_repeatCount(const QString &s, int i);
+int qt_repeatCount(QStringView s);
enum { AsciiSpaceMask = (1 << (' ' - 1)) |
(1 << ('\t' - 1)) | // 9: HT - horizontal tab
diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp
index 2475859abd..1d80320d8e 100644
--- a/src/corelib/tools/qlocale_win.cpp
+++ b/src/corelib/tools/qlocale_win.cpp
@@ -160,7 +160,7 @@ private:
SubstitutionType substitution();
QString &substituteDigits(QString &string);
- static QString winToQtFormat(const QString &sys_fmt);
+ static QString winToQtFormat(QStringView sys_fmt);
};
Q_GLOBAL_STATIC(QSystemLocalePrivate, systemLocalePrivate)
@@ -680,7 +680,7 @@ void QSystemLocalePrivate::update()
zero = QChar();
}
-QString QSystemLocalePrivate::winToQtFormat(const QString &sys_fmt)
+QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt)
{
QString result;
int i = 0;
@@ -696,7 +696,7 @@ QString QSystemLocalePrivate::winToQtFormat(const QString &sys_fmt)
}
QChar c = sys_fmt.at(i);
- int repeat = qt_repeatCount(sys_fmt, i);
+ int repeat = qt_repeatCount(sys_fmt.mid(i));
switch (c.unicode()) {
// Date
diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp
index 29534bdeee..afdd30e5c8 100644
--- a/src/corelib/tools/qmap.cpp
+++ b/src/corelib/tools/qmap.cpp
@@ -908,6 +908,61 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa keyBegin(), lastKey()
*/
+
+/*! \fn QMap::key_value_iterator QMap::keyValueBegin()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the map.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn QMap::key_value_iterator QMap::keyValueEnd()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the map.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn QMap::const_key_value_iterator QMap::keyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the map.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn QMap::const_key_value_iterator QMap::constKeyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the map.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn QMap::const_key_value_iterator QMap::keyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the map.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn QMap::const_key_value_iterator QMap::constKeyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the map.
+
+ \sa constKeyValueBegin()
+*/
+
/*! \fn const Key &QMap::firstKey() const
\since 5.2
@@ -1782,6 +1837,18 @@ void QMapDataBase::freeData(QMapDataBase *d)
Returns the underlying const_iterator this key_iterator is based on.
*/
+/*! \typedef QMap::key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QMap and QMultiMap.
+
+ QMap::key_value_iterator is essentially the same as QMap::iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
\relates QMap
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index a3b11eddcf..9a663c2c20 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -548,6 +548,8 @@ public:
const_iterator base() const { return i; }
};
+ typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
+ typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
// STL style
inline iterator begin() { detach(); return iterator(d->begin()); }
@@ -560,6 +562,12 @@ public:
inline const_iterator cend() const { return const_iterator(d->end()); }
inline key_iterator keyBegin() const { return key_iterator(begin()); }
inline key_iterator keyEnd() const { return key_iterator(end()); }
+ inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
+ inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
+ inline const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
iterator erase(iterator it);
// more Qt
@@ -948,7 +956,7 @@ Q_OUTOFLINE_TEMPLATE T QMap<Key, T>::take(const Key &akey)
Node *node = d->findNode(akey);
if (node) {
- T t = node->value;
+ T t = std::move(node->value);
d->deleteNode(node);
return t;
}
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/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp
index 88b696f53a..86bc99716d 100644
--- a/src/corelib/tools/qregularexpression.cpp
+++ b/src/corelib/tools/qregularexpression.cpp
@@ -871,7 +871,7 @@ struct QRegularExpressionPrivate : QSharedData
CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
const QRegularExpressionMatchPrivate *previous = 0) const;
- int captureIndexForName(const QString &name) const;
+ int captureIndexForName(QStringView name) const;
// sizeof(QSharedData) == 4, so start our members with an enum
QRegularExpression::PatternOptions patternOptions;
@@ -1173,14 +1173,14 @@ void QRegularExpressionPrivate::optimizePattern(OptimizePatternOption option)
Returns the capturing group number for the given name. Duplicated names for
capturing groups are not supported.
*/
-int QRegularExpressionPrivate::captureIndexForName(const QString &name) const
+int QRegularExpressionPrivate::captureIndexForName(QStringView name) const
{
Q_ASSERT(!name.isEmpty());
if (!compiledPattern)
return -1;
- int index = pcre2_substring_number_from_name_16(compiledPattern, name.utf16());
+ int index = pcre2_substring_number_from_name_16(compiledPattern, reinterpret_cast<PCRE2_SPTR16>(name.utf16()));
if (index >= 0)
return index;
@@ -2054,11 +2054,12 @@ int QRegularExpressionMatch::lastCapturedIndex() const
}
/*!
- Returns the substring captured by the \a nth capturing group. If the \a nth
- capturing group did not capture a string or doesn't exist, returns a null
- QString.
+ Returns the substring captured by the \a nth capturing group.
- \sa capturedRef(), lastCapturedIndex(), capturedStart(), capturedEnd(),
+ If the \a nth capturing group did not capture a string, or if there is no
+ such capturing group, returns a null QString.
+
+ \sa capturedRef(), capturedView(), lastCapturedIndex(), capturedStart(), capturedEnd(),
capturedLength(), QString::isNull()
*/
QString QRegularExpressionMatch::captured(int nth) const
@@ -2076,10 +2077,11 @@ QString QRegularExpressionMatch::captured(int nth) const
/*!
Returns a reference to the substring captured by the \a nth capturing group.
- If the \a nth capturing group did not capture a string or doesn't exist,
- returns a null QStringRef.
- \sa captured(), lastCapturedIndex(), capturedStart(), capturedEnd(),
+ If the \a nth capturing group did not capture a string, or if there is no
+ such capturing group, returns a null QStringRef.
+
+ \sa captured(), capturedView(), lastCapturedIndex(), capturedStart(), capturedEnd(),
capturedLength(), QStringRef::isNull()
*/
QStringRef QRegularExpressionMatch::capturedRef(int nth) const
@@ -2096,15 +2098,65 @@ QStringRef QRegularExpressionMatch::capturedRef(int nth) const
}
/*!
- Returns the substring captured by the capturing group named \a name. If the
- capturing group named \a name did not capture a string or doesn't exist,
- returns a null QString.
+ \since 5.10
+
+ Returns a view of the substring captured by the \a nth capturing group.
+
+ If the \a nth capturing group did not capture a string, or if there is no
+ such capturing group, returns a null QStringView.
+
+ \sa captured(), capturedRef(), lastCapturedIndex(), capturedStart(), capturedEnd(),
+ capturedLength(), QStringView::isNull()
+*/
+QStringView QRegularExpressionMatch::capturedView(int nth) const
+{
+ return capturedRef(nth);
+}
+
+#if QT_STRINGVIEW_LEVEL < 2
+/*!
+ Returns the substring captured by the capturing group named \a name.
- \sa capturedRef(), capturedStart(), capturedEnd(), capturedLength(),
+ If the named capturing group \a name did not capture a string, or if
+ there is no capturing group named \a name, returns a null QString.
+
+ \sa capturedRef(), capturedView(), capturedStart(), capturedEnd(), capturedLength(),
QString::isNull()
*/
QString QRegularExpressionMatch::captured(const QString &name) const
{
+ return captured(qToStringViewIgnoringNull(name));
+}
+
+/*!
+ Returns a reference to the string captured by the capturing group named \a
+ name.
+
+ If the named capturing group \a name did not capture a string, or if
+ there is no capturing group named \a name, returns a null QStringRef.
+
+ \sa captured(), capturedView(), capturedStart(), capturedEnd(), capturedLength(),
+ QStringRef::isNull()
+*/
+QStringRef QRegularExpressionMatch::capturedRef(const QString &name) const
+{
+ return capturedRef(qToStringViewIgnoringNull(name));
+}
+#endif // QT_STRINGVIEW_LEVEL < 2
+
+/*!
+ \since 5.10
+
+ Returns the substring captured by the capturing group named \a name.
+
+ If the named capturing group \a name did not capture a string, or if
+ there is no capturing group named \a name, returns a null QString.
+
+ \sa capturedRef(), capturedView(), capturedStart(), capturedEnd(), capturedLength(),
+ QString::isNull()
+*/
+QString QRegularExpressionMatch::captured(QStringView name) const
+{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::captured: empty capturing group name passed");
return QString();
@@ -2116,14 +2168,18 @@ QString QRegularExpressionMatch::captured(const QString &name) const
}
/*!
+ \since 5.10
+
Returns a reference to the string captured by the capturing group named \a
- name. If the capturing group named \a name did not capture a string or
- doesn't exist, returns a null QStringRef.
+ name.
+
+ If the named capturing group \a name did not capture a string, or if
+ there is no capturing group named \a name, returns a null QStringRef.
- \sa captured(), capturedStart(), capturedEnd(), capturedLength(),
+ \sa captured(), capturedView(), capturedStart(), capturedEnd(), capturedLength(),
QStringRef::isNull()
*/
-QStringRef QRegularExpressionMatch::capturedRef(const QString &name) const
+QStringRef QRegularExpressionMatch::capturedRef(QStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedRef: empty capturing group name passed");
@@ -2136,6 +2192,30 @@ QStringRef QRegularExpressionMatch::capturedRef(const QString &name) const
}
/*!
+ \since 5.10
+
+ Returns a view of the string captured by the capturing group named \a
+ name.
+
+ If the named capturing group \a name did not capture a string, or if
+ there is no capturing group named \a name, returns a null QStringView.
+
+ \sa captured(), capturedRef(), capturedStart(), capturedEnd(), capturedLength(),
+ QStringRef::isNull()
+*/
+QStringView QRegularExpressionMatch::capturedView(QStringView name) const
+{
+ if (name.isEmpty()) {
+ qWarning("QRegularExpressionMatch::capturedView: empty capturing group name passed");
+ return QStringView();
+ }
+ int nth = d->regularExpression.d->captureIndexForName(name);
+ if (nth == -1)
+ return QStringView();
+ return capturedView(nth);
+}
+
+/*!
Returns a list of all strings captured by capturing groups, in the order
the groups themselves appear in the pattern string.
*/
@@ -2193,6 +2273,7 @@ int QRegularExpressionMatch::capturedEnd(int nth) const
return d->capturedOffsets.at(nth * 2 + 1);
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns the offset inside the subject string corresponding to the starting
position of the substring captured by the capturing group named \a name.
@@ -2203,6 +2284,49 @@ int QRegularExpressionMatch::capturedEnd(int nth) const
*/
int QRegularExpressionMatch::capturedStart(const QString &name) const
{
+ return capturedStart(qToStringViewIgnoringNull(name));
+}
+
+/*!
+ Returns the length of the substring captured by the capturing group named
+ \a name.
+
+ \note This function returns 0 if the capturing group named \a name did not
+ capture a string or doesn't exist.
+
+ \sa capturedStart(), capturedEnd(), captured()
+*/
+int QRegularExpressionMatch::capturedLength(const QString &name) const
+{
+ return capturedLength(qToStringViewIgnoringNull(name));
+}
+
+/*!
+ Returns the offset inside the subject string immediately after the ending
+ position of the substring captured by the capturing group named \a name. If
+ the capturing group named \a name did not capture a string or doesn't
+ exist, returns -1.
+
+ \sa capturedStart(), capturedLength(), captured()
+*/
+int QRegularExpressionMatch::capturedEnd(const QString &name) const
+{
+ return capturedEnd(qToStringViewIgnoringNull(name));
+}
+#endif // QT_STRINGVIEW_LEVEL < 2
+
+/*!
+ \since 5.10
+
+ Returns the offset inside the subject string corresponding to the starting
+ position of the substring captured by the capturing group named \a name.
+ If the capturing group named \a name did not capture a string or doesn't
+ exist, returns -1.
+
+ \sa capturedEnd(), capturedLength(), captured()
+*/
+int QRegularExpressionMatch::capturedStart(QStringView name) const
+{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedStart: empty capturing group name passed");
return -1;
@@ -2214,15 +2338,17 @@ int QRegularExpressionMatch::capturedStart(const QString &name) const
}
/*!
- Returns the offset inside the subject string corresponding to the starting
- position of the substring captured by the capturing group named \a name.
+ \since 5.10
+
+ Returns the length of the substring captured by the capturing group named
+ \a name.
\note This function returns 0 if the capturing group named \a name did not
capture a string or doesn't exist.
\sa capturedStart(), capturedEnd(), captured()
*/
-int QRegularExpressionMatch::capturedLength(const QString &name) const
+int QRegularExpressionMatch::capturedLength(QStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedLength: empty capturing group name passed");
@@ -2235,6 +2361,8 @@ int QRegularExpressionMatch::capturedLength(const QString &name) const
}
/*!
+ \since 5.10
+
Returns the offset inside the subject string immediately after the ending
position of the substring captured by the capturing group named \a name. If
the capturing group named \a name did not capture a string or doesn't
@@ -2242,7 +2370,7 @@ int QRegularExpressionMatch::capturedLength(const QString &name) const
\sa capturedStart(), capturedLength(), captured()
*/
-int QRegularExpressionMatch::capturedEnd(const QString &name) const
+int QRegularExpressionMatch::capturedEnd(QStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
diff --git a/src/corelib/tools/qregularexpression.h b/src/corelib/tools/qregularexpression.h
index fa1cc5660a..050841e70e 100644
--- a/src/corelib/tools/qregularexpression.h
+++ b/src/corelib/tools/qregularexpression.h
@@ -52,6 +52,8 @@
QT_BEGIN_NAMESPACE
+class QStringView;
+
class QRegularExpressionMatch;
class QRegularExpressionMatchIterator;
struct QRegularExpressionPrivate;
@@ -197,9 +199,16 @@ public:
QString captured(int nth = 0) const;
QStringRef capturedRef(int nth = 0) const;
+ QStringView capturedView(int nth = 0) const;
+#if QT_STRINGVIEW_LEVEL < 2
QString captured(const QString &name) const;
QStringRef capturedRef(const QString &name) const;
+#endif
+
+ QString captured(QStringView name) const;
+ QStringRef capturedRef(QStringView name) const;
+ QStringView capturedView(QStringView name) const;
QStringList capturedTexts() const;
@@ -207,9 +216,15 @@ public:
int capturedLength(int nth = 0) const;
int capturedEnd(int nth = 0) const;
+#if QT_STRINGVIEW_LEVEL < 2
int capturedStart(const QString &name) const;
int capturedLength(const QString &name) const;
int capturedEnd(const QString &name) const;
+#endif
+
+ int capturedStart(QStringView name) const;
+ int capturedLength(QStringView name) const;
+ int capturedEnd(QStringView name) const;
private:
friend class QRegularExpression;
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 28253b3ae9..725b6b6765 100644
--- a/src/corelib/tools/qsimd_p.h
+++ b/src/corelib/tools/qsimd_p.h
@@ -262,7 +262,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..907de3cb4b 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -152,21 +152,19 @@ static inline int qt_string_count(const QChar *haystack, int haystackLen,
QChar needle, Qt::CaseSensitivity cs);
static inline int qt_find_latin1_string(const QChar *hay, int size, QLatin1String needle,
int from, Qt::CaseSensitivity cs);
-static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
- const QChar *needle, int needleLen, Qt::CaseSensitivity cs);
-static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
- QLatin1String needle, Qt::CaseSensitivity cs);
-static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
- const QChar *needle, int needleLen, Qt::CaseSensitivity cs);
-static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
- QLatin1String needle, Qt::CaseSensitivity cs);
+static inline bool qt_starts_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
+static inline bool qt_starts_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs);
+static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
+static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
+static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs);
+static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
#if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__)
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 +186,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 +372,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 +391,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 +406,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 +440,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 +453,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 +480,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 +505,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 +559,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 +634,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 +650,140 @@ 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());
+}
+
+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());
+}
- return ucstrncmp(reinterpret_cast<const QChar *>(a), reinterpret_cast<const QChar *>(b), length) == 0;
+static int qt_compare_strings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return -qt_compare_strings(rhs, lhs, cs);
}
-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);
+ if (lhs.isEmpty())
+ return lencmp(0, rhs.size());
+ 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(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 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);
}
/*!
@@ -1502,7 +1601,7 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
{
int count = 0;
- QStringIterator i(reinterpret_cast<const QChar *>(uc), reinterpret_cast<const QChar *>(uc + length));
+ QStringIterator i(QStringView(uc, length));
while (i.hasNext())
out[count++] = i.next();
@@ -2789,7 +2888,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 +2901,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 +2946,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 +2957,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 +3058,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 +3255,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 +3279,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 +3295,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 +3341,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 +3361,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 +3375,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));
@@ -4366,7 +4460,7 @@ QString QString::section(const QRegularExpression &re, int start, int end, Secti
\snippet qstring/main.cpp 31
- \sa right(), mid(), startsWith()
+ \sa right(), mid(), startsWith(), chopped(), chop(), truncate()
*/
QString QString::left(int n) const
{
@@ -4384,7 +4478,7 @@ QString QString::left(int n) const
\snippet qstring/main.cpp 48
- \sa left(), mid(), endsWith()
+ \sa left(), mid(), endsWith(), chopped(), chop(), truncate()
*/
QString QString::right(int n) const
{
@@ -4407,7 +4501,7 @@ QString QString::right(int n) const
\snippet qstring/main.cpp 34
- \sa left(), right()
+ \sa left(), right(), chopped(), chop(), truncate()
*/
QString QString::mid(int position, int n) const
@@ -4431,6 +4525,19 @@ QString QString::mid(int position, int n) const
}
/*!
+ \fn QString::chopped(int len) const
+ \since 5.10
+
+ Returns a substring that contains the size() - \a len leftmost characters
+ of this string.
+
+ \note The behavior is undefined if \a len is negative or greater than size().
+
+ \sa endsWith(), left(), right(), mid(), chop(), truncate()
+*/
+
+#if QT_STRINGVIEW_LEVEL < 2
+/*!
Returns \c true if the string starts with \a s; otherwise returns
\c false.
@@ -4443,16 +4550,16 @@ QString QString::mid(int position, int n) const
*/
bool QString::startsWith(const QString& s, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(isNull() ? 0 : unicode(), size(),
- s.isNull() ? 0 : s.unicode(), s.size(), cs);
+ return qt_starts_with(*this, s, cs);
}
+#endif
/*!
\overload startsWith()
*/
bool QString::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(isNull() ? 0 : unicode(), size(), s, cs);
+ return qt_starts_with(*this, s, cs);
}
/*!
@@ -4463,12 +4570,10 @@ bool QString::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const
*/
bool QString::startsWith(QChar c, Qt::CaseSensitivity cs) const
{
- return d->size
- && (cs == Qt::CaseSensitive
- ? d->data()[0] == c
- : foldCase(d->data()[0]) == foldCase(c.unicode()));
+ return qt_starts_with(*this, c, cs);
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
\since 4.8
\overload
@@ -4482,10 +4587,25 @@ bool QString::startsWith(QChar c, Qt::CaseSensitivity cs) const
*/
bool QString::startsWith(const QStringRef &s, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(isNull() ? 0 : unicode(), size(),
- s.isNull() ? 0 : s.unicode(), s.size(), cs);
+ return qt_starts_with(*this, s, cs);
}
+#endif
+
+/*!
+ \fn bool QString::startsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \overload
+
+ Returns \c true if the string starts with the string-view \a str;
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (default), the search is case-sensitive;
+ otherwise the search is case insensitive.
+
+ \sa endsWith()
+*/
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns \c true if the string ends with \a s; otherwise returns
\c false.
@@ -4499,8 +4619,7 @@ bool QString::startsWith(const QStringRef &s, Qt::CaseSensitivity cs) const
*/
bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(isNull() ? 0 : unicode(), size(),
- s.isNull() ? 0 : s.unicode(), s.size(), cs);
+ return qt_ends_with(*this, s, cs);
}
/*!
@@ -4516,17 +4635,29 @@ bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
*/
bool QString::endsWith(const QStringRef &s, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(isNull() ? 0 : unicode(), size(),
- s.isNull() ? 0 : s.unicode(), s.size(), cs);
+ return qt_ends_with(*this, s, cs);
}
+#endif // QT_STRINGVIEW_LEVEL < 2
+/*!
+ \fn bool QString::endsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \overload endsWith()
+ Returns \c true if the string ends with the string view \a str;
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (default), the search is case
+ sensitive; otherwise the search is case insensitive.
+
+ \sa startsWith()
+*/
/*!
\overload endsWith()
*/
bool QString::endsWith(QLatin1String s, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(isNull() ? 0 : unicode(), size(), s, cs);
+ return qt_ends_with(*this, s, cs);
}
/*!
@@ -4537,35 +4668,54 @@ bool QString::endsWith(QLatin1String s, Qt::CaseSensitivity cs) const
*/
bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
{
- return d->size
- && (cs == Qt::CaseSensitive
- ? d->data()[d->size - 1] == c
- : foldCase(d->data()[d->size - 1]) == foldCase(c.unicode()));
+ return qt_ends_with(*this, c, cs);
}
+static QByteArray qt_convert_to_latin1(QStringView string);
+
QByteArray QString::toLatin1_helper(const QString &string)
{
- if (Q_UNLIKELY(string.isNull()))
- return QByteArray();
-
- return toLatin1_helper(string.constData(), string.length());
+ return qt_convert_to_latin1(string);
}
QByteArray QString::toLatin1_helper(const QChar *data, int length)
{
- QByteArray ba(length, Qt::Uninitialized);
+ return qt_convert_to_latin1(QStringView(data, length));
+}
+
+/*!
+ \since 5.10
+ \relates QStringView
+
+ Returns a Latin-1 representation of \a string as a QByteArray.
+
+ The behavior is undefined if \a string contains non-Latin1 characters.
+
+ \sa QString::toLatin1(), QStringView::toLatin1(), qConvertToUtf8(), qConvertToLocal8Bit(), qConvertToUcs4()
+*/
+QByteArray qConvertToLatin1(QStringView string)
+{
+ return qt_convert_to_latin1(string);
+}
+
+static QByteArray qt_convert_to_latin1(QStringView string)
+{
+ if (Q_UNLIKELY(string.isNull()))
+ return QByteArray();
+
+ QByteArray ba(string.length(), Qt::Uninitialized);
// since we own the only copy, we're going to const_cast the constData;
// that avoids an unnecessary call to detach() and expansion code that will never get used
qt_to_latin1(reinterpret_cast<uchar *>(const_cast<char *>(ba.constData())),
- reinterpret_cast<const ushort *>(data), length);
+ reinterpret_cast<const ushort *>(string.data()), string.length());
return ba;
}
QByteArray QString::toLatin1_helper_inplace(QString &s)
{
if (!s.isDetached())
- return s.toLatin1();
+ return qt_convert_to_latin1(s);
// We can return our own buffer to the caller.
// Conversion to Latin-1 always shrinks the buffer by half.
@@ -4601,7 +4751,7 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
characters. Those characters may be suppressed or replaced with a
question mark.
- \sa fromLatin1(), toUtf8(), toLocal8Bit(), QTextCodec
+ \sa fromLatin1(), toUtf8(), toLocal8Bit(), QTextCodec, qConvertToLatin1()
*/
/*!
@@ -4617,6 +4767,8 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
\sa fromAscii(), toLatin1(), toUtf8(), toLocal8Bit(), QTextCodec
*/
+static QByteArray qt_convert_to_local_8bit(QStringView string);
+
/*!
\fn QByteArray QString::toLocal8Bit() const
@@ -4632,21 +4784,47 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
locale, the returned byte array is undefined. Those characters may be
suppressed or replaced by another.
- \sa fromLocal8Bit(), toLatin1(), toUtf8(), QTextCodec
+ \sa fromLocal8Bit(), toLatin1(), toUtf8(), QTextCodec, qConvertToLocal8Bit()
*/
QByteArray QString::toLocal8Bit_helper(const QChar *data, int size)
{
- if (!data)
+ return qt_convert_to_local_8bit(QStringView(data, size));
+}
+
+static QByteArray qt_convert_to_local_8bit(QStringView string)
+{
+ if (string.isNull())
return QByteArray();
#ifndef QT_NO_TEXTCODEC
QTextCodec *localeCodec = QTextCodec::codecForLocale();
if (localeCodec)
- return localeCodec->fromUnicode(data, size);
+ return localeCodec->fromUnicode(string);
#endif // QT_NO_TEXTCODEC
- return toLatin1_helper(data, size);
+ return qt_convert_to_latin1(string);
}
+/*!
+ \since 5.10
+ \relates QStringView
+
+ Returns a local 8-bit representation of \a string as a QByteArray.
+
+ QTextCodec::codecForLocale() is used to perform the conversion from
+ Unicode. If the locale's encoding could not be determined, this function
+ does the same as qConvertToLatin1().
+
+ The behavior is undefined if \a string contains characters not
+ supported by the locale's 8-bit encoding.
+
+ \sa QString::toLocal8Bit(), QStringView::toLocal8Bit(), qConvertToLatin1(), qConvertToUtf8(), qConvertToUcs4()
+*/
+QByteArray qConvertToLocal8Bit(QStringView string)
+{
+ return qt_convert_to_local_8bit(string);
+}
+
+static QByteArray qt_convert_to_utf8(QStringView str);
/*!
\fn QByteArray QString::toUtf8() const
@@ -4656,18 +4834,41 @@ QByteArray QString::toLocal8Bit_helper(const QChar *data, int size)
UTF-8 is a Unicode codec and can represent all characters in a Unicode
string like QString.
- \sa fromUtf8(), toLatin1(), toLocal8Bit(), QTextCodec
+ \sa fromUtf8(), toLatin1(), toLocal8Bit(), QTextCodec, qConvertToUtf8()
*/
QByteArray QString::toUtf8_helper(const QString &str)
{
+ return qt_convert_to_utf8(str);
+}
+
+static QByteArray qt_convert_to_utf8(QStringView str)
+{
if (str.isNull())
return QByteArray();
- return QUtf8::convertFromUnicode(str.constData(), str.length());
+ return QUtf8::convertFromUnicode(str.data(), str.length());
}
/*!
+ \since 5.10
+ \relates QStringView
+
+ Returns a UTF-8 representation of \a string as a QByteArray.
+
+ UTF-8 is a Unicode codec and can represent all characters in a Unicode
+ string like QStringView.
+
+ \sa QString::toUtf8(), QStringView::toUtf8(), qConvertToLatin1(), qConvertToLocal8Bit(), qConvertToUcs4()
+*/
+QByteArray qConvertToUtf8(QStringView string)
+{
+ return qt_convert_to_utf8(string);
+}
+
+static QVector<uint> qt_convert_to_ucs4(QStringView string);
+
+/*!
\since 4.2
Returns a UCS-4/UTF-32 representation of the string as a QVector<uint>.
@@ -4679,17 +4880,44 @@ QByteArray QString::toUtf8_helper(const QString &str)
The returned vector is not NUL terminated.
- \sa fromUtf8(), toUtf8(), toLatin1(), toLocal8Bit(), QTextCodec, fromUcs4(), toWCharArray()
+ \sa fromUtf8(), toUtf8(), toLatin1(), toLocal8Bit(), QTextCodec, fromUcs4(), toWCharArray(), qConvertToUcs4()
*/
QVector<uint> QString::toUcs4() const
{
- QVector<uint> v(length());
- uint *a = v.data();
- int len = toUcs4_helper(d->data(), length(), a);
- v.resize(len);
+ return qt_convert_to_ucs4(*this);
+}
+
+static QVector<uint> qt_convert_to_ucs4(QStringView string)
+{
+ QVector<uint> v(string.length());
+ uint *a = const_cast<uint*>(v.constData());
+ QStringIterator it(string);
+ while (it.hasNext())
+ *a++ = it.next();
+ v.resize(a - v.constData());
return v;
}
+/*!
+ \since 5.10
+ \relates QStringView
+
+ Returns a UCS-4/UTF-32 representation of \a string as a QVector<uint>.
+
+ UCS-4 is a Unicode codec and therefore it is lossless. All characters from
+ this string will be encoded in UCS-4. Any invalid sequence of code units in
+ this string is replaced by the Unicode's replacement character
+ (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}).
+
+ The returned vector is not NUL terminated.
+
+ \sa QString::toUcs4(), QStringView::toUcs4(), qConvertToLatin1(), qConvertToLocal8Bit(), qConvertToUtf8()
+*/
+QVector<uint> qConvertToUcs4(QStringView string)
+{
+ return qt_convert_to_ucs4(string);
+}
+
QString::Data *QString::fromLatin1_helper(const char *str, int size)
{
Data *d;
@@ -4980,6 +5208,41 @@ QString QString::simplified_helper(QString &str)
return QStringAlgorithms<QString>::simplified_helper(str);
}
+namespace {
+ template <typename StringView>
+ StringView qt_trimmed(StringView s) Q_DECL_NOTHROW
+ {
+ auto begin = s.begin();
+ auto end = s.end();
+ QStringAlgorithms<const StringView>::trimmed_helper_positions(begin, end);
+ return StringView{begin, end};
+ }
+}
+
+/*!
+ \fn QStringView qTrimmed(QStringView s)
+ \fn QLatin1String qTrimmed(QLatin1String s)
+ \relates QStringView
+ \since 5.10
+
+ Returns \a s with whitespace removed from the start and the end.
+
+ Whitespace means any character for which QChar::isSpace() returns
+ \c true. This includes the ASCII characters '\\t', '\\n', '\\v',
+ '\\f', '\\r', and ' '.
+
+ \sa QString::trimmed(), QStringView::trimmed(), QLatin1String::trimmed()
+*/
+QStringView qTrimmed(QStringView s) Q_DECL_NOTHROW
+{
+ return qt_trimmed(s);
+}
+
+QLatin1String qTrimmed(QLatin1String s) Q_DECL_NOTHROW
+{
+ return qt_trimmed(s);
+}
+
/*!
\fn QString QString::trimmed() const
@@ -5057,6 +5320,66 @@ modifiable reference.
*/
/*!
+ \fn QChar QString::front() const
+ \since 5.10
+
+ Returns the first character in the string.
+ Same as \c{at(0)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa back(), at(), operator[]()
+*/
+
+/*!
+ \fn QChar QString::back() const
+ \since 5.10
+
+ Returns the last character in the string.
+ Same as \c{at(size() - 1)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa front(), at(), operator[]()
+*/
+
+/*!
+ \fn QCharRef QString::front()
+ \since 5.10
+
+ Returns a reference to the first character in the string.
+ Same as \c{operator[](0)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa back(), at(), operator[]()
+*/
+
+/*!
+ \fn QCharRef QString::back()
+ \since 5.10
+
+ Returns a reference to the last character in the string.
+ Same as \c{operator[](size() - 1)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa front(), at(), operator[]()
+*/
+
+/*!
\fn void QString::truncate(int position)
Truncates the string at the given \a position index.
@@ -5277,7 +5600,7 @@ QString& QString::fill(QChar ch, int size)
Equivalent to \c {s1 != 0 && compare(s1, s2) == 0}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -5290,7 +5613,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 +5629,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 +5645,7 @@ QString& QString::fill(QChar ch, int size)
expect. Consider sorting user-interface strings with
QString::localeAwareCompare().
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -5337,7 +5660,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 +5741,7 @@ QString& QString::fill(QChar ch, int size)
\snippet qstring/main.cpp 16
- \sa operator==(), operator<(), operator>()
+ \sa qCompareStrings(), operator==(), operator<(), operator>()
*/
/*!
@@ -5428,6 +5751,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 +5763,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 +5778,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 +5793,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 +5805,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 +5820,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 +5831,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 +5841,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 +5858,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 +5946,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 +5995,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 +6697,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 +6737,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 +6939,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);
}
/*!
@@ -7263,10 +7597,10 @@ struct ArgEscapeData
int escape_len; // total length of escape sequences which will be replaced
};
-static ArgEscapeData findArgEscapes(const QString &s)
+static ArgEscapeData findArgEscapes(QStringView s)
{
- const QChar *uc_begin = s.unicode();
- const QChar *uc_end = uc_begin + s.length();
+ const QChar *uc_begin = s.begin();
+ const QChar *uc_end = s.end();
ArgEscapeData d;
@@ -7325,11 +7659,11 @@ static ArgEscapeData findArgEscapes(const QString &s)
return d;
}
-static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int field_width,
- const QString &arg, const QString &larg, QChar fillChar = QLatin1Char(' '))
+static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, int field_width,
+ QStringView arg, QStringView larg, QChar fillChar)
{
- const QChar *uc_begin = s.unicode();
- const QChar *uc_end = uc_begin + s.length();
+ const QChar *uc_begin = s.begin();
+ const QChar *uc_end = s.end();
int abs_field_width = qAbs(field_width);
int result_len = s.length()
@@ -7393,11 +7727,11 @@ static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int f
}
if (locale_arg) {
- memcpy(rc, larg.unicode(), larg.length()*sizeof(QChar));
+ memcpy(rc, larg.data(), larg.length()*sizeof(QChar));
rc += larg.length();
}
else {
- memcpy(rc, arg.unicode(), arg.length()*sizeof(QChar));
+ memcpy(rc, arg.data(), arg.length()*sizeof(QChar));
rc += arg.length();
}
@@ -7419,6 +7753,7 @@ static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int f
return result;
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a copy of this string with the lowest numbered place marker
replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
@@ -7450,17 +7785,86 @@ static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int f
*/
QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
{
+ return arg(qToStringViewIgnoringNull(a), fieldWidth, fillChar);
+}
+#endif // QT_STRINGVIEW_LEVEL < 2
+
+/*!
+ \overload
+ \since 5.10
+
+ Returns a copy of this string with the lowest-numbered place-marker
+ replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
+
+ \a fieldWidth specifies the minimum amount of space that \a a
+ shall occupy. If \a a requires less space than \a fieldWidth, it
+ is padded to \a fieldWidth with character \a fillChar. A positive
+ \a fieldWidth produces right-aligned text. A negative \a fieldWidth
+ produces left-aligned text.
+
+ This example shows how we might create a \c status string for
+ reporting progress while processing a list of files:
+
+ \snippet qstring/main.cpp 11-qstringview
+
+ First, \c arg(i) replaces \c %1. Then \c arg(total) replaces \c
+ %2. Finally, \c arg(fileName) replaces \c %3.
+
+ One advantage of using arg() over asprintf() is that the order of the
+ numbered place markers can change, if the application's strings are
+ translated into other languages, but each arg() will still replace
+ the lowest-numbered unreplaced place-marker, no matter where it
+ appears. Also, if place-marker \c %i appears more than once in the
+ string, arg() replaces all of them.
+
+ If there is no unreplaced place-marker remaining, a warning message
+ is printed and the result is undefined. Place-marker numbers must be
+ in the range 1 to 99.
+*/
+QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
+{
ArgEscapeData d = findArgEscapes(*this);
- if (d.occurrences == 0) {
- qWarning("QString::arg: Argument missing: %s, %s", toLocal8Bit().data(),
- a.toLocal8Bit().data());
+ if (Q_UNLIKELY(d.occurrences == 0)) {
+ qWarning("QString::arg: Argument missing: %ls, %ls", qUtf16Printable(*this),
+ qUtf16Printable(a.toString()));
return *this;
}
return replaceArgEscapes(*this, d, fieldWidth, a, a, fillChar);
}
/*!
+ \overload
+ \since 5.10
+
+ Returns a copy of this string with the lowest-numbered place-marker
+ replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
+
+ \a fieldWidth specifies the minimum amount of space that \a a
+ shall occupy. If \a a requires less space than \a fieldWidth, it
+ is padded to \a fieldWidth with character \a fillChar. A positive
+ \a fieldWidth produces right-aligned text. A negative \a fieldWidth
+ produces left-aligned text.
+
+ One advantage of using arg() over asprintf() is that the order of the
+ numbered place markers can change, if the application's strings are
+ translated into other languages, but each arg() will still replace
+ the lowest-numbered unreplaced place-marker, no matter where it
+ appears. Also, if place-marker \c %i appears more than once in the
+ string, arg() replaces all of them.
+
+ If there is no unreplaced place-marker remaining, a warning message
+ is printed and the result is undefined. Place-marker numbers must be
+ in the range 1 to 99.
+*/
+QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
+{
+ QVarLengthArray<ushort> utf16(a.size());
+ qt_from_latin1(utf16.data(), a.data(), a.size());
+ return arg(QStringView(utf16.data(), utf16.size()), fieldWidth, fillChar);
+}
+
+/*!
\fn QString QString::arg(const QString& a1, const QString& a2) const
\overload arg()
@@ -8139,6 +8543,15 @@ bool QString::isRightToLeft() const
Appends the given \a ch character onto the end of this string.
*/
+/*! \fn void QString::shrink_to_fit()
+ \since 5.10
+
+ This function is provided for STL compatibility. It is
+ equivalent to squeeze().
+
+ \sa squeeze()
+*/
+
/*!
\fn std::string QString::toStdString() const
@@ -8316,6 +8729,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
@@ -8344,6 +8827,24 @@ QString &QString::setRawData(const QChar *unicode, int size)
\sa latin1()
*/
+/*!
+ \fn QLatin1String::QLatin1String(const char *first, const char *last)
+ \since 5.10
+
+ Constructs a QLatin1String object that stores \a first with length
+ (\a last - \a first).
+
+ The range \c{[first,last)} must remain valid for the lifetime of
+ this Latin-1 string object.
+
+ Passing \c nullptr as \a first is safe if \a last is \c nullptr,
+ too, and results in a null Latin-1 string.
+
+ The behavior is undefined if \a last precedes \a first, \a first
+ is \c nullptr and \a last is not, or if \c{last - first >
+ INT_MAX}.
+*/
+
/*! \fn QLatin1String::QLatin1String(const QByteArray &str)
Constructs a QLatin1String object that stores \a str.
@@ -8370,6 +8871,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 +8911,167 @@ QString &QString::setRawData(const QChar *unicode, int size)
\sa at()
*/
+/*!
+ \fn QLatin1Char QLatin1String::front() const
+ \since 5.10
+
+ Returns the first character in the string.
+ Same as \c{at(0)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa back(), at(), operator[]()
+*/
+
+/*!
+ \fn QLatin1Char QLatin1String::back() const
+ \since 5.10
+
+ Returns the last character in the string.
+ Same as \c{at(size() - 1)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa front(), at(), operator[]()
+*/
+
+/*!
+ \fn bool QLatin1String::startsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \fn bool QLatin1String::startsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \fn bool QLatin1String::startsWith(QChar ch) const
+ \since 5.10
+ \fn bool QLatin1String::startsWith(QChar ch, Qt::CaseSensitivity cs) const
+ \since 5.10
+
+ Returns \c true if this Latin-1 string starts with string-view \a str,
+ Latin-1 string \a l1, or character \a ch, respectively;
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
+ otherwise the search is case-insensitive.
+
+ \sa endsWith(), qStartsWith()
+*/
+
+/*!
+ \fn bool QLatin1String::endsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \fn bool QLatin1String::endsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \fn bool QLatin1String::endsWith(QChar ch) const
+ \since 5.10
+ \fn bool QLatin1String::endsWith(QChar ch, Qt::CaseSensitivity cs) const
+ \since 5.10
+
+ Returns \c true if this Latin-1 string ends with string-view \a str,
+ Latin-1 string \a l1, or character \a ch, respectively;
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
+ otherwise the search is case-insensitive.
+
+ \sa startsWith(), qEndsWith()
+*/
+
+/*!
+ \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
@@ -8401,7 +9081,7 @@ QString &QString::setRawData(const QChar *unicode, int size)
\note This function performs no error checking.
The behavior is undefined when \a start < 0 or \a start > size().
- \sa left(), right()
+ \sa left(), right(), chopped(), chop(), truncate()
*/
/*! \fn QLatin1String QLatin1String::mid(int start, int length) const
@@ -8415,7 +9095,7 @@ QString &QString::setRawData(const QChar *unicode, int size)
The behavior is undefined when \a start < 0, \a length < 0,
or \a start + \a length > size().
- \sa left(), right()
+ \sa left(), right(), chopped(), chop(), truncate()
*/
/*! \fn QLatin1String QLatin1String::left(int length) const
@@ -8427,7 +9107,7 @@ QString &QString::setRawData(const QChar *unicode, int size)
\note This function performs no error checking.
The behavior is undefined when \a length < 0 or \a length > size().
- \sa mid(), right()
+ \sa mid(), right(), chopped(), chop(), truncate()
*/
/*! \fn QLatin1String QLatin1String::right(int length) const
@@ -8439,7 +9119,60 @@ QString &QString::setRawData(const QChar *unicode, int size)
\note This function performs no error checking.
The behavior is undefined when \a length < 0 or \a length > size().
- \sa mid(), left()
+ \sa mid(), left(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QLatin1String QLatin1String::chopped(int length) const
+ \since 5.10
+
+ Returns the substring of length size() - \a length starting at the
+ beginning of this object.
+
+ Same as \c{left(size() - length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), left(), right(), chop(), truncate()
+*/
+
+/*!
+ \fn void QLatin1String::truncate(int length)
+ \since 5.10
+
+ Truncates this string to length \a length.
+
+ Same as \c{*this = left(length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), left(), right(), chopped(), chop()
+*/
+
+/*!
+ \fn void QLatin1String::chop(int length)
+ \since 5.10
+
+ Truncates this string by \a length characters.
+
+ Same as \c{*this = left(size() - length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), left(), right(), chopped(), truncate()
+*/
+
+/*!
+ \fn QLatin1String QLatin1String::trimmed() const
+ \since 5.10
+
+ Strips leading and trailing whitespace and returns the result.
+
+ Whitespace means any character for which QChar::isSpace() returns
+ \c true. This includes the ASCII characters '\\t', '\\n', '\\v',
+ '\\f', '\\r', and ' '.
+
+ \sa qTrimmed()
*/
/*! \fn bool QLatin1String::operator==(const QString &other) const
@@ -9137,8 +9870,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 +9880,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 +9894,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 +9910,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)
@@ -9247,6 +9977,36 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW
*/
/*!
+ \fn QChar QStringRef::front() const
+ \since 5.10
+
+ Returns the first character in the string.
+ Same as \c{at(0)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa back(), at(), operator[]()
+*/
+
+/*!
+ \fn QChar QStringRef::back() const
+ \since 5.10
+
+ Returns the last character in the string.
+ Same as \c{at(size() - 1)}.
+
+ This function is provided for STL compatibility.
+
+ \warning Calling this function on an empty string constitutes
+ undefined behavior.
+
+ \sa front(), at(), operator[]()
+*/
+
+/*!
\fn void QStringRef::clear()
Clears the contents of the string reference by making it null and empty.
@@ -9411,6 +10171,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 +10186,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 +10201,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 +10219,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -9470,7 +10236,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -9487,7 +10253,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -9505,7 +10271,7 @@ QStringRef QStringRef::appendTo(QString *string) const
Equivalent to \c {compare(*this, other, cs)}.
- \sa QString::compare()
+ \sa qCompareStrings()
*/
/*!
@@ -9597,7 +10363,7 @@ QString &QString::append(const QStringRef &str)
If \a n is greater than or equal to size(), or less than zero,
a reference to the entire string is returned.
- \sa right(), mid(), startsWith()
+ \sa right(), mid(), startsWith(), chopped(), chop(), truncate()
*/
QStringRef QStringRef::left(int n) const
{
@@ -9634,7 +10400,7 @@ QStringRef QString::leftRef(int n) const
If \a n is greater than or equal to size(), or less than zero,
a reference to the entire string is returned.
- \sa left(), mid(), endsWith()
+ \sa left(), mid(), endsWith(), chopped(), chop(), truncate()
*/
QStringRef QStringRef::right(int n) const
{
@@ -9676,7 +10442,7 @@ QStringRef QString::rightRef(int n) const
function returns all characters from the specified \a position
onwards.
- \sa left(), right()
+ \sa left(), right(), chopped(), chop(), truncate()
*/
QStringRef QStringRef::mid(int pos, int n) const
{
@@ -9696,6 +10462,18 @@ QStringRef QStringRef::mid(int pos, int n) const
}
/*!
+ \fn QStringRef::chopped(int len) const
+ \since 5.10
+
+ Returns a substring reference to the size() - \a len leftmost characters
+ of this string.
+
+ \note The behavior is undefined if \a len is negative or greater than size().
+
+ \sa endsWith(), left(), right(), mid(), chop(), truncate()
+*/
+
+/*!
\since 4.4
Returns a substring reference to \a n characters of this string,
@@ -10011,8 +10789,7 @@ bool QStringRef::isRightToLeft() const
*/
bool QStringRef::startsWith(const QString &str, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(isNull() ? 0 : unicode(), size(),
- str.isNull() ? 0 : str.unicode(), str.size(), cs);
+ return qt_starts_with(*this, str, cs);
}
/*!
@@ -10022,18 +10799,24 @@ bool QStringRef::startsWith(const QString &str, Qt::CaseSensitivity cs) const
*/
bool QStringRef::startsWith(QLatin1String str, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(isNull() ? 0 : unicode(), size(), str, cs);
+ return qt_starts_with(*this, str, cs);
}
/*!
+ \fn bool QStringRef::startsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \overload startsWith()
+ \sa QString::startsWith(), endsWith()
+*/
+
+/*!
\since 4.8
\overload startsWith()
\sa QString::startsWith(), endsWith()
*/
bool QStringRef::startsWith(const QStringRef &str, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(isNull() ? 0 : unicode(), size(),
- str.isNull() ? 0 : str.unicode(), str.size(), cs);
+ return qt_starts_with(*this, str, cs);
}
/*!
@@ -10050,14 +10833,7 @@ bool QStringRef::startsWith(const QStringRef &str, Qt::CaseSensitivity cs) const
*/
bool QStringRef::startsWith(QChar ch, Qt::CaseSensitivity cs) const
{
- if (!isEmpty()) {
- const ushort *data = reinterpret_cast<const ushort*>(unicode());
- return (cs == Qt::CaseSensitive
- ? data[0] == ch
- : foldCase(data[0]) == foldCase(ch.unicode()));
- } else {
- return false;
- }
+ return qt_starts_with(*this, ch, cs);
}
/*!
@@ -10072,8 +10848,7 @@ bool QStringRef::startsWith(QChar ch, Qt::CaseSensitivity cs) const
*/
bool QStringRef::endsWith(const QString &str, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(isNull() ? 0 : unicode(), size(),
- str.isNull() ? 0 : str.unicode(), str.size(), cs);
+ return qt_ends_with(*this, str, cs);
}
/*!
@@ -10090,15 +10865,7 @@ bool QStringRef::endsWith(const QString &str, Qt::CaseSensitivity cs) const
*/
bool QStringRef::endsWith(QChar ch, Qt::CaseSensitivity cs) const
{
- if (!isEmpty()) {
- const ushort *data = reinterpret_cast<const ushort*>(unicode());
- const int size = length();
- return (cs == Qt::CaseSensitive
- ? data[size - 1] == ch
- : foldCase(data[size - 1]) == foldCase(ch.unicode()));
- } else {
- return false;
- }
+ return qt_ends_with(*this, ch, cs);
}
/*!
@@ -10108,18 +10875,24 @@ bool QStringRef::endsWith(QChar ch, Qt::CaseSensitivity cs) const
*/
bool QStringRef::endsWith(QLatin1String str, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(isNull() ? 0 : unicode(), size(), str, cs);
+ return qt_ends_with(*this, str, cs);
}
/*!
+ \fn bool QStringRef::endsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \since 5.10
+ \overload endsWith()
+ \sa QString::endsWith(), startsWith()
+*/
+
+/*!
\since 4.8
\overload endsWith()
\sa QString::endsWith(), endsWith()
*/
bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(isNull() ? 0 : unicode(), size(),
- str.isNull() ? 0 : str.unicode(), str.size(), cs);
+ return qt_ends_with(*this, str, cs);
}
@@ -10254,101 +11027,148 @@ static inline int qt_find_latin1_string(const QChar *haystack, int size,
reinterpret_cast<const QChar*>(s.constData()), len, cs);
}
-static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
- const QChar *needle, int needleLen, Qt::CaseSensitivity cs)
+template <typename Haystack, typename Needle>
+bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
- if (!haystack)
- return !needle;
+ if (haystack.isNull())
+ return needle.isNull(); // historical behavior, consider changing in ### Qt 6.
+ const auto haystackLen = haystack.size();
+ const auto needleLen = needle.size();
if (haystackLen == 0)
return needleLen == 0;
if (needleLen > haystackLen)
return false;
- const ushort *h = reinterpret_cast<const ushort*>(haystack);
- const ushort *n = reinterpret_cast<const ushort*>(needle);
+ return qt_compare_strings(haystack.left(needleLen), needle, cs) == 0;
+}
- 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;
+static inline bool qt_starts_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
+{
+ return qt_starts_with_impl(haystack, needle, cs);
}
-static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
- QLatin1String needle, Qt::CaseSensitivity cs)
+static inline bool qt_starts_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
{
- if (!haystack)
- return !needle.latin1();
- if (haystackLen == 0)
- return !needle.latin1() || *needle.latin1() == 0;
- 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_starts_with_impl(haystack, needle, cs);
}
-static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
- const QChar *needle, int needleLen, Qt::CaseSensitivity cs)
+static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs)
{
- if (!haystack)
- return !needle;
+ return haystack.size()
+ && (cs == Qt::CaseSensitive ? haystack.front() == needle
+ : foldCase(haystack.front()) == foldCase(needle));
+}
+
+/*!
+ \fn bool qStartsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \fn bool qStartsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \fn bool qStartsWith(QLatin1String haystack, QStringview needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \fn bool qStartsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \relates QStringView
+
+ Returns \c true if \a haystack starts with \a needle,
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
+ otherwise the search is case-insensitive.
+
+ \sa qEndsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1String::endsWith()
+*/
+
+bool qStartsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_starts_with_impl(haystack, needle, cs);
+}
+
+bool qStartsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_starts_with_impl(haystack, needle, cs);
+}
+
+bool qStartsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_starts_with_impl(haystack, needle, cs);
+}
+
+bool qStartsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_starts_with_impl(haystack, needle, cs);
+}
+
+template <typename Haystack, typename Needle>
+bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ if (haystack.isNull())
+ return needle.isNull(); // historical behavior, consider changing in ### Qt 6.
+ const auto haystackLen = haystack.size();
+ const auto needleLen = needle.size();
if (haystackLen == 0)
return needleLen == 0;
- const int pos = haystackLen - needleLen;
- if (pos < 0)
+ if (haystackLen < needleLen)
return false;
- const ushort *h = reinterpret_cast<const ushort*>(haystack);
- const ushort *n = reinterpret_cast<const ushort*>(needle);
+ return qt_compare_strings(haystack.right(needleLen), needle, cs) == 0;
+}
- 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;
+static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
+{
+ return qt_ends_with_impl(haystack, needle, cs);
+}
+
+static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+{
+ return qt_ends_with_impl(haystack, needle, cs);
}
+static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs)
+{
+ return haystack.size()
+ && (cs == Qt::CaseSensitive ? haystack.back() == needle
+ : foldCase(haystack.back()) == foldCase(needle));
+}
+
+/*!
+ \fn bool qEndsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \fn bool qEndsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \fn bool qEndsWith(QLatin1String haystack, QStringview needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \fn bool qEndsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \since 5.10
+ \relates QStringView
-static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
- QLatin1String needle, Qt::CaseSensitivity cs)
+ Returns \c true if \a haystack ends with \a needle,
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
+ otherwise the search is case-insensitive.
+
+ \sa qEndsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1String::endsWith()
+*/
+
+bool qEndsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
- if (!haystack)
- return !needle.latin1();
- if (haystackLen == 0)
- return !needle.latin1() || *needle.latin1() == 0;
- const int slen = needle.size();
- 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_ends_with_impl(haystack, needle, cs);
+}
+
+bool qEndsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_ends_with_impl(haystack, needle, cs);
+}
+
+bool qEndsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_ends_with_impl(haystack, needle, cs);
+}
+
+bool qEndsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
+{
+ return qt_ends_with_impl(haystack, needle, cs);
}
/*!
@@ -10364,9 +11184,7 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
*/
QByteArray QStringRef::toLatin1() const
{
- if (isNull())
- return QByteArray();
- return QString::toLatin1_helper(unicode(), length());
+ return qt_convert_to_latin1(*this);
}
/*!
@@ -10403,14 +11221,7 @@ QByteArray QStringRef::toLatin1() const
*/
QByteArray QStringRef::toLocal8Bit() const
{
-#ifndef QT_NO_TEXTCODEC
- if (!isNull()) {
- QTextCodec *localeCodec = QTextCodec::codecForLocale();
- if (localeCodec)
- return localeCodec->fromUnicode(unicode(), length());
- }
-#endif // QT_NO_TEXTCODEC
- return toLatin1();
+ return qt_convert_to_local_8bit(*this);
}
/*!
@@ -10425,10 +11236,7 @@ QByteArray QStringRef::toLocal8Bit() const
*/
QByteArray QStringRef::toUtf8() const
{
- if (isNull())
- return QByteArray();
-
- return QUtf8::convertFromUnicode(constData(), length());
+ return qt_convert_to_utf8(*this);
}
/*!
@@ -10447,11 +11255,7 @@ QByteArray QStringRef::toUtf8() const
*/
QVector<uint> QStringRef::toUcs4() const
{
- QVector<uint> v(length());
- uint *a = v.data();
- int len = QString::toUcs4_helper(reinterpret_cast<const ushort *>(unicode()), length(), a);
- v.resize(len);
- return v;
+ return qt_convert_to_ucs4(*this);
}
/*!
@@ -10475,8 +11279,6 @@ QStringRef QStringRef::trimmed() const
QStringAlgorithms<const QStringRef>::trimmed_helper_positions(begin, end);
if (begin == cbegin() && end == cend())
return *this;
- if (begin == end)
- return QStringRef();
int position = m_position + (begin - cbegin());
return QStringRef(m_string, position, end - begin);
}
@@ -10709,7 +11511,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 109b68c544..d5301a396f 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -49,6 +49,9 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qrefcount.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qstringliteral.h>
+#include <QtCore/qstringalgorithms.h>
+#include <QtCore/qstringview.h>
#include <string>
#include <iterator>
@@ -90,6 +93,8 @@ class QLatin1String
public:
Q_DECL_CONSTEXPR inline QLatin1String() Q_DECL_NOTHROW : m_size(0), m_data(Q_NULLPTR) {}
Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s) Q_DECL_NOTHROW : m_size(s ? int(strlen(s)) : 0), m_data(s) {}
+ Q_DECL_CONSTEXPR explicit QLatin1String(const char *f, const char *l)
+ : QLatin1String(f, int(l - f)) {}
Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s, int sz) Q_DECL_NOTHROW : m_size(sz), m_data(s) {}
inline explicit QLatin1String(const QByteArray &s) Q_DECL_NOTHROW : m_size(int(qstrnlen(s.constData(), s.size()))), m_data(s.constData()) {}
@@ -97,17 +102,72 @@ 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); }
+ Q_DECL_CONSTEXPR QLatin1Char front() const Q_REQUIRED_RESULT { return at(0); }
+ Q_DECL_CONSTEXPR QLatin1Char back() const Q_REQUIRED_RESULT { return at(size() - 1); }
+
+ Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qStartsWith(*this, s, cs); }
+ Q_REQUIRED_RESULT bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qStartsWith(*this, s, cs); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR bool startsWith(QChar c) const Q_DECL_NOTHROW
+ { return !isEmpty() && front() == c; }
+ Q_REQUIRED_RESULT inline bool startsWith(QChar c, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
+ { return qStartsWith(*this, QStringView(&c, 1), cs); }
+
+ Q_REQUIRED_RESULT bool endsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qEndsWith(*this, s, cs); }
+ Q_REQUIRED_RESULT bool endsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qEndsWith(*this, s, cs); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR bool endsWith(QChar c) const Q_DECL_NOTHROW
+ { return !isEmpty() && back() == c; }
+ Q_REQUIRED_RESULT inline bool endsWith(QChar c, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
+ { return qEndsWith(*this, QStringView(&c, 1), cs); }
+
+ 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); }
+ Q_DECL_CONSTEXPR QLatin1String chopped(int n) const Q_REQUIRED_RESULT
+ { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QLatin1String(m_data, m_size - n); }
+
+ Q_DECL_RELAXED_CONSTEXPR void chop(int n)
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; }
+ Q_DECL_RELAXED_CONSTEXPR void truncate(int n)
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size = n; }
+
+ Q_REQUIRED_RESULT QLatin1String trimmed() const Q_DECL_NOTHROW { return qTrimmed(*this); }
inline bool operator==(const QString &s) const Q_DECL_NOTHROW;
inline bool operator!=(const QString &s) const Q_DECL_NOTHROW;
@@ -141,73 +201,13 @@ Q_DECLARE_TYPEINFO(QLatin1String, Q_MOVABLE_TYPE);
// Qt 4.x compatibility
typedef QLatin1String QLatin1Literal;
-
-typedef QTypedArrayData<ushort> QStringData;
-
-#if defined(Q_OS_WIN) && !defined(Q_COMPILER_UNICODE_STRINGS)
-// fall back to wchar_t if the a Windows compiler does not
-// support Unicode string literals, assuming wchar_t is 2 bytes
-// on that platform (sanity-checked by static_assert further below)
-
-#if defined(Q_CC_MSVC)
-# define QT_UNICODE_LITERAL_II(str) L##str
-#else
-# define QT_UNICODE_LITERAL_II(str) L"" str
-#endif
-typedef wchar_t qunicodechar;
-
-#else
-// all our supported compilers support Unicode string literals,
-// even if their Q_COMPILER_UNICODE_STRING has been revoked due
-// to lacking stdlib support. But QStringLiteral only needs the
-// core language feature, so just use u"" here unconditionally:
-
-#define QT_UNICODE_LITERAL_II(str) u"" str
-typedef char16_t qunicodechar;
-
-#endif
-
-Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
- "qunicodechar must typedef an integral type of size 2");
-
-#define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
-#define QStringLiteral(str) \
- ([]() Q_DECL_NOEXCEPT -> QString { \
- enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
- static const QStaticStringData<Size> qstring_literal = { \
- Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
- QT_UNICODE_LITERAL(str) }; \
- QStringDataPtr holder = { qstring_literal.data_ptr() }; \
- const QString qstring_literal_temp(holder); \
- return qstring_literal_temp; \
- }()) \
- /**/
-
-#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
- { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
- /**/
-
-#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \
- Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QStringData)) \
- /**/
-
-template <int N>
-struct QStaticStringData
-{
- QArrayData str;
- qunicodechar data[N + 1];
-
- QStringData *data_ptr() const
- {
- Q_ASSERT(str.ref.isStatic());
- return const_cast<QStringData *>(static_cast<const QStringData*>(&str));
- }
-};
-
-struct QStringDataPtr
-{
- QStringData *ptr;
-};
+//
+// QStringView members that require QLatin1String:
+//
+bool QStringView::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
+{ return qStartsWith(*this, s, cs); }
+bool QStringView::endsWith(QLatin1String s, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
+{ return qEndsWith(*this, s, cs); }
class Q_CORE_EXPORT QString
{
@@ -261,6 +261,11 @@ public:
const QChar operator[](uint i) const;
QCharRef operator[](uint i);
+ Q_REQUIRED_RESULT inline QChar front() const { return at(0); }
+ Q_REQUIRED_RESULT inline QCharRef front();
+ Q_REQUIRED_RESULT inline QChar back() const { return at(size() - 1); }
+ Q_REQUIRED_RESULT inline QCharRef back();
+
Q_REQUIRED_RESULT QString arg(qlonglong a, int fieldwidth=0, int base=10,
QChar fillChar = QLatin1Char(' ')) const;
Q_REQUIRED_RESULT QString arg(qulonglong a, int fieldwidth=0, int base=10,
@@ -283,8 +288,14 @@ public:
QChar fillChar = QLatin1Char(' ')) const;
Q_REQUIRED_RESULT QString arg(QChar a, int fieldWidth = 0,
QChar fillChar = QLatin1Char(' ')) const;
+#if QT_STRINGVIEW_LEVEL < 2
Q_REQUIRED_RESULT QString arg(const QString &a, int fieldWidth = 0,
QChar fillChar = QLatin1Char(' ')) const;
+#endif
+ Q_REQUIRED_RESULT QString arg(QStringView a, int fieldWidth = 0,
+ QChar fillChar = QLatin1Char(' ')) const;
+ Q_REQUIRED_RESULT QString arg(QLatin1String a, int fieldWidth = 0,
+ QChar fillChar = QLatin1Char(' ')) const;
Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2) const;
Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3) const;
Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3,
@@ -366,16 +377,29 @@ public:
Q_REQUIRED_RESULT QString left(int n) const;
Q_REQUIRED_RESULT QString right(int n) const;
Q_REQUIRED_RESULT QString mid(int position, int n = -1) const;
+ Q_REQUIRED_RESULT QString chopped(int n) const
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return left(size() - n); }
+
+
Q_REQUIRED_RESULT QStringRef leftRef(int n) const;
Q_REQUIRED_RESULT QStringRef rightRef(int n) const;
Q_REQUIRED_RESULT QStringRef midRef(int position, int n = -1) const;
+#if QT_STRINGVIEW_LEVEL < 2
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(const QStringRef &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+#endif
+ Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qStartsWith(*this, s, cs); }
bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+
+#if QT_STRINGVIEW_LEVEL < 2
bool endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool endsWith(const QStringRef &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+#endif
+ Q_REQUIRED_RESULT bool endsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qEndsWith(*this, s, cs); }
bool endsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
@@ -652,7 +676,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)
@@ -750,6 +774,7 @@ public:
inline void push_back(const QString &s) { append(s); }
inline void push_front(QChar c) { prepend(c); }
inline void push_front(const QString &s) { prepend(s); }
+ void shrink_to_fit() { squeeze(); }
static inline QString fromStdString(const std::string &s);
inline std::string toStdString() const;
@@ -850,6 +875,7 @@ private:
friend class QCharRef;
friend class QTextCodec;
friend class QStringRef;
+ friend class QStringView;
friend class QByteArray;
friend class QCollator;
friend struct QAbstractConcatenable;
@@ -877,6 +903,15 @@ public:
inline DataPtr &data_ptr() { return d; }
};
+//
+// QStringView inline members that require QString:
+//
+QString QStringView::toString() const
+{ return Q_ASSERT(size() == length()), QString(data(), length()); }
+
+//
+// QString inline members
+//
inline QString::QString(QLatin1String aLatin1) : d(fromLatin1_helper(aLatin1.latin1(), aLatin1.size()))
{ }
inline int QString::length() const
@@ -1112,6 +1147,8 @@ inline QCharRef QString::operator[](int i)
{ Q_ASSERT(i >= 0); return QCharRef(*this, i); }
inline QCharRef QString::operator[](uint i)
{ return QCharRef(*this, i); }
+inline QCharRef QString::front() { return operator[](0); }
+inline QCharRef QString::back() { return operator[](size() - 1); }
inline QString::iterator QString::begin()
{ detach(); return reinterpret_cast<QChar*>(d->data()); }
inline QString::const_iterator QString::begin() const
@@ -1433,6 +1470,8 @@ public:
Q_REQUIRED_RESULT QStringRef left(int n) const;
Q_REQUIRED_RESULT QStringRef right(int n) const;
Q_REQUIRED_RESULT QStringRef mid(int pos, int n = -1) const;
+ Q_REQUIRED_RESULT QStringRef chopped(int n) const
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return left(size() - n); }
void truncate(int pos) Q_DECL_NOTHROW { m_size = qBound(0, pos, m_size); }
void chop(int n) Q_DECL_NOTHROW
@@ -1445,15 +1484,23 @@ public:
bool isRightToLeft() const;
- bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qStartsWith(*this, s, cs); }
bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+#if QT_STRINGVIEW_LEVEL < 2
+ bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(const QStringRef &c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+#endif
- bool endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ Q_REQUIRED_RESULT bool endsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qEndsWith(*this, s, cs); }
bool endsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+#if QT_STRINGVIEW_LEVEL < 2
+ bool endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool endsWith(const QStringRef &c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+#endif
inline QStringRef &operator=(const QString *string);
@@ -1496,6 +1543,8 @@ public:
inline const QChar at(int i) const
{ Q_ASSERT(uint(i) < uint(size())); return m_string->at(i + m_position); }
QChar operator[](int i) const { return at(i); }
+ QChar front() const Q_REQUIRED_RESULT { return at(0); }
+ QChar back() const Q_REQUIRED_RESULT { return at(size() - 1); }
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
// ASCII compatibility
@@ -1610,7 +1659,7 @@ inline bool operator>=(const QStringRef &lhs, QLatin1String rhs) Q_DECL_NOTHROW
// QChar <> QString
inline bool operator==(QChar lhs, const QString &rhs) Q_DECL_NOTHROW
-{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) == 0; }
+{ return rhs.size() == 1 && lhs == rhs.front(); }
inline bool operator< (QChar lhs, const QString &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; }
inline bool operator> (QChar lhs, const QString &rhs) Q_DECL_NOTHROW
@@ -1629,7 +1678,7 @@ inline bool operator>=(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return !(
// QChar <> QStringRef
inline bool operator==(QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW
-{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) == 0; }
+{ return rhs.size() == 1 && lhs == rhs.front(); }
inline bool operator< (QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; }
inline bool operator> (QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW
@@ -1648,7 +1697,7 @@ inline bool operator>=(const QStringRef &lhs, QChar rhs) Q_DECL_NOTHROW { return
// QChar <> QLatin1String
inline bool operator==(QChar lhs, QLatin1String rhs) Q_DECL_NOTHROW
-{ return QString::compare_helper(&lhs, 1, rhs) == 0; }
+{ return rhs.size() == 1 && lhs == rhs.front(); }
inline bool operator< (QChar lhs, QLatin1String rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs) < 0; }
inline bool operator> (QChar lhs, QLatin1String rhs) Q_DECL_NOTHROW
@@ -1665,6 +1714,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/qstringalgorithms.h b/src/corelib/tools/qstringalgorithms.h
new file mode 100644
index 0000000000..e1b8b90428
--- /dev/null
+++ b/src/corelib/tools/qstringalgorithms.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+** 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 QSTRINGALGORITHMS_H
+#define QSTRINGALGORITHMS_H
+
+#include <QtCore/qnamespace.h>
+
+#if 0
+#pragma qt_class(QStringAlgorithms)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+class QLatin1String;
+class QStringView;
+template <typename T> class QVector;
+
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int qCompareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int qCompareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int qCompareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int qCompareStrings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+
+
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qStartsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qStartsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qStartsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qStartsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qEndsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qEndsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qEndsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool qEndsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) Q_DECL_NOTHROW;
+
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QStringView qTrimmed(QStringView s) Q_DECL_NOTHROW;
+Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QLatin1String qTrimmed(QLatin1String s) Q_DECL_NOTHROW;
+
+Q_REQUIRED_RESULT Q_CORE_EXPORT QByteArray qConvertToLatin1(QStringView str);
+Q_REQUIRED_RESULT Q_CORE_EXPORT QByteArray qConvertToUtf8(QStringView str);
+Q_REQUIRED_RESULT Q_CORE_EXPORT QByteArray qConvertToLocal8Bit(QStringView str);
+Q_REQUIRED_RESULT Q_CORE_EXPORT QVector<uint> qConvertToUcs4(QStringView str);
+
+QT_END_NAMESPACE
+
+#endif // QSTRINGALGORTIHMS_H
diff --git a/src/corelib/tools/qstringalgorithms_p.h b/src/corelib/tools/qstringalgorithms_p.h
index c5470bc7ad..4bcf697f78 100644
--- a/src/corelib/tools/qstringalgorithms_p.h
+++ b/src/corelib/tools/qstringalgorithms_p.h
@@ -89,14 +89,12 @@ template <typename StringType> struct QStringAlgorithms
static inline void trimmed_helper_positions(const Char *&begin, const Char *&end)
{
+ // skip white space from end
+ while (begin < end && isSpace(end[-1]))
+ --end;
// skip white space from start
while (begin < end && isSpace(*begin))
begin++;
- // skip white space from end
- if (begin < end) {
- while (begin < end && isSpace(end[-1]))
- end--;
- }
}
static inline StringType trimmed_helper(StringType &str)
diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h
index 9a40abcfed..5c6d990314 100644
--- a/src/corelib/tools/qstringbuilder.h
+++ b/src/corelib/tools/qstringbuilder.h
@@ -303,7 +303,7 @@ template <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
template <> struct QConcatenable<const char *> : private QAbstractConcatenable
{
- typedef char const *type;
+ typedef const char *type;
typedef QByteArray ConvertTo;
enum { ExactSize = false };
static int size(const char *a) { return qstrlen(a); }
@@ -320,6 +320,11 @@ template <> struct QConcatenable<const char *> : private QAbstractConcatenable
}
};
+template <> struct QConcatenable<char *> : QConcatenable<const char*>
+{
+ typedef char *type;
+};
+
template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
{
typedef QByteArray type;
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..8b1a6a1cd3 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, qssize_t 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/qstringliteral.h b/src/corelib/tools/qstringliteral.h
new file mode 100644
index 0000000000..6a1a74a80e
--- /dev/null
+++ b/src/corelib/tools/qstringliteral.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Intel Corporation.
+** 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 QSTRINGLITERAL_H
+#define QSTRINGLITERAL_H
+
+#include <QtCore/qarraydata.h>
+
+#if 0
+#pragma qt_class(QStringLiteral)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+typedef QTypedArrayData<ushort> QStringData;
+
+#if defined(Q_OS_WIN) && !defined(Q_COMPILER_UNICODE_STRINGS)
+// fall back to wchar_t if the a Windows compiler does not
+// support Unicode string literals, assuming wchar_t is 2 bytes
+// on that platform (sanity-checked by static_assert further below)
+
+#if defined(Q_CC_MSVC)
+# define QT_UNICODE_LITERAL_II(str) L##str
+#else
+# define QT_UNICODE_LITERAL_II(str) L"" str
+#endif
+typedef wchar_t qunicodechar;
+
+#else
+// all our supported compilers support Unicode string literals,
+// even if their Q_COMPILER_UNICODE_STRING has been revoked due
+// to lacking stdlib support. But QStringLiteral only needs the
+// core language feature, so just use u"" here unconditionally:
+
+#define QT_UNICODE_LITERAL_II(str) u"" str
+typedef char16_t qunicodechar;
+
+#endif
+
+Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
+ "qunicodechar must typedef an integral type of size 2");
+
+#define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
+#define QStringLiteral(str) \
+ ([]() Q_DECL_NOEXCEPT -> QString { \
+ enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
+ static const QStaticStringData<Size> qstring_literal = { \
+ Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
+ QT_UNICODE_LITERAL(str) }; \
+ QStringDataPtr holder = { qstring_literal.data_ptr() }; \
+ const QString qstring_literal_temp(holder); \
+ return qstring_literal_temp; \
+ }()) \
+ /**/
+
+#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
+ { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
+ /**/
+
+#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \
+ Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QStringData)) \
+ /**/
+
+#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
+
+template <int N>
+struct QStaticStringData
+{
+ QArrayData str;
+ qunicodechar data[N + 1];
+
+ QStringData *data_ptr() const
+ {
+ Q_ASSERT(str.ref.isStatic());
+ return const_cast<QStringData *>(static_cast<const QStringData*>(&str));
+ }
+};
+
+struct QStringDataPtr
+{
+ QStringData *ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSTRINGLITERAL_H
diff --git a/src/corelib/tools/qstringview.cpp b/src/corelib/tools/qstringview.cpp
new file mode 100644
index 0000000000..8eefc6d814
--- /dev/null
+++ b/src/corelib/tools/qstringview.cpp
@@ -0,0 +1,777 @@
+/****************************************************************************
+**
+** 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 with a read-only subset of the QString API.
+ \reentrant
+ \ingroup tools
+ \ingroup string-processing
+
+ A QStringView references a contiguous 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 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 qssize_t. Provided for compatibility with the STL.
+
+ Unlike other Qt classes, QStringView uses qssize_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(const Char *str, qssize_t 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 *first, const Char *last)
+
+ Constructs a string view on \a first with length (\a last - \a first).
+
+ The range \c{[first,last)} must remain valid for the lifetime of
+ this string view object.
+
+ Passing \c nullptr as \a first is safe if \a last is nullptr, too,
+ and results in a null string view.
+
+ The behavior is undefined if \a last precedes \a first, or \a first
+ is \c nullptr and \a last is not.
+
+ 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{Char(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 qssize_t 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[](qssize_t 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(qssize_t 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(qssize_t 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(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QStringView QStringView::mid(qssize_t start, qssize_t 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(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QStringView QStringView::left(qssize_t 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(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QStringView QStringView::right(qssize_t 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(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QStringView QStringView::chopped(qssize_t length) const
+
+ Returns the substring of length size() - \a length starting at the
+ beginning of this object.
+
+ Same as \c{left(size() - length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), left(), right(), chop(), truncate()
+*/
+
+/*!
+ \fn void QStringView::truncate(qssize_t length)
+
+ Truncates this string view to length \a length.
+
+ Same as \c{*this = left(length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), left(), right(), chopped(), chop()
+*/
+
+/*!
+ \fn void QStringView::chop(qssize_t length)
+
+ Truncates this string view by \a length characters.
+
+ Same as \c{*this = left(size() - length)}.
+
+ \note The behavior is undefined when \a length < 0 or \a length > size().
+
+ \sa mid(), left(), right(), chopped(), truncate()
+*/
+
+/*!
+ \fn QStringView QStringView::trimmed() const
+
+ Strips leading and trailing whitespace and returns the result.
+
+ Whitespace means any character for which QChar::isSpace() returns
+ \c true. This includes the ASCII characters '\\t', '\\n', '\\v',
+ '\\f', '\\r', and ' '.
+
+ \sa qTrimmed()
+*/
+
+/*!
+ \fn bool QStringView::startsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \fn bool QStringView::startsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
+ \fn bool QStringView::startsWith(QChar ch) const
+ \fn bool QStringView::startsWith(QChar ch, Qt::CaseSensitivity cs) const
+
+ Returns \c true if this string-view starts with string-view \a str,
+ Latin-1 string \a l1, or character \a ch, respectively;
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
+ otherwise the search is case-insensitive.
+
+ \sa endsWith(), qStartsWith()
+*/
+
+/*!
+ \fn bool QStringView::endsWith(QStringView str, Qt::CaseSensitivity cs) const
+ \fn bool QStringView::endsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
+ \fn bool QStringView::endsWith(QChar ch) const
+ \fn bool QStringView::endsWith(QChar ch, Qt::CaseSensitivity cs) const
+
+ Returns \c true if this string-view ends with string-view \a str,
+ Latin-1 string \a l1, or character \a ch, respectively;
+ otherwise returns \c false.
+
+ If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
+ otherwise the search is case-insensitive.
+
+ \sa startsWith(), qEndsWith()
+*/
+
+/*!
+ \fn QByteArray QStringView::toLatin1() const
+
+ Returns a Latin-1 representation of the string as a QByteArray.
+
+ The behavior is undefined if the string contains non-Latin1 characters.
+
+ \sa toUtf8(), toLocal8Bit(), QTextCodec, qConvertToLatin1()
+*/
+
+/*!
+ \fn QByteArray QStringView::toLocal8Bit() const
+
+ Returns a local 8-bit representation of the string as a QByteArray.
+
+ QTextCodec::codecForLocale() is used to perform the conversion from
+ Unicode. If the locale's encoding could not be determined, this function
+ does the same as toLatin1().
+
+ The behavior is undefined if the string contains characters not
+ supported by the locale's 8-bit encoding.
+
+ \sa toLatin1(), toUtf8(), QTextCodec, qConvertToLocal8Bit()
+*/
+
+/*!
+ \fn QByteArray QStringView::toUtf8() const
+
+ Returns a UTF-8 representation of the string as a QByteArray.
+
+ UTF-8 is a Unicode codec and can represent all characters in a Unicode
+ string like QString.
+
+ \sa toLatin1(), toLocal8Bit(), QTextCodec, qConvertToUtf8()
+*/
+
+/*!
+ \fn QVector<uint> QStringView::toUcs4() const
+
+ Returns a UCS-4/UTF-32 representation of the string as a QVector<uint>.
+
+ UCS-4 is a Unicode codec and therefore it is lossless. All characters from
+ this string will be encoded in UCS-4. Any invalid sequence of code units in
+ this string is replaced by the Unicode replacement character
+ (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}).
+
+ The returned vector is not 0-terminated.
+
+ \sa toUtf8(), toLatin1(), toLocal8Bit(), QTextCodec
+*/
+
+/*!
+ \fn qToStringViewIgnoringNull(const QStringLike &s);
+ \since 5.10
+ \internal
+
+ Convert \a s to a QStringView ignoring \c{s.isNull()}.
+
+ Returns a string-view that references \a{s}' data, but is never null.
+
+ This is a faster way to convert a QString or QStringRef to a QStringView,
+ if null QStrings can legitimately be treated as empty ones.
+
+ \sa QString::isNull(), QStringRef::isNull(), QStringView
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qstringview.h b/src/corelib/tools/qstringview.h
new file mode 100644
index 0000000000..24be441b00
--- /dev/null
+++ b/src/corelib/tools/qstringview.h
@@ -0,0 +1,305 @@
+/****************************************************************************
+**
+** 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 QSTRINGVIEW_H
+#define QSTRINGVIEW_H
+
+#ifndef QT_STRINGVIEW_LEVEL
+# define QT_STRINGVIEW_LEVEL 1
+#endif
+
+#include <QtCore/qchar.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstringliteral.h>
+#include <QtCore/qstringalgorithms.h>
+
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+class QStringRef;
+
+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_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
+{
+public:
+#if defined(Q_OS_WIN) && !defined(Q_COMPILER_UNICODE_STRINGS)
+ typedef wchar_t storage_type;
+#else
+ typedef char16_t storage_type;
+#endif
+ typedef const QChar value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef qssize_t 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 qssize_t lengthHelperArray(const Char (&)[N]) Q_DECL_NOTHROW
+ {
+ return qssize_t(N - 1);
+ }
+ template <typename Char>
+ static Q_DECL_RELAXED_CONSTEXPR qssize_t lengthHelperPointer(const Char *str) Q_DECL_NOTHROW
+ {
+ qssize_t result = 0;
+ while (*str++)
+ ++result;
+ return result;
+ }
+ static Q_DECL_RELAXED_CONSTEXPR qssize_t lengthHelperPointer(const QChar *str) Q_DECL_NOTHROW
+ {
+ qssize_t 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() {}
+
+ template <typename Char, if_compatible_char<Char> = true>
+ Q_DECL_CONSTEXPR QStringView(const Char *str, qssize_t len)
+ : m_size((Q_ASSERT(len >= 0), Q_ASSERT(str || !len), len)),
+ m_data(castHelper(str)) {}
+
+ template <typename Char, if_compatible_char<Char> = true>
+ Q_DECL_CONSTEXPR QStringView(const Char *f, const Char *l)
+ : QStringView(f, l - f) {}
+
+#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(), qssize_t(str.size())) {}
+#endif
+
+ template <typename StdBasicString, if_compatible_string<StdBasicString> = true>
+ QStringView(const StdBasicString &str) Q_DECL_NOTHROW
+ : QStringView(str.data(), qssize_t(str.size())) {}
+
+ Q_REQUIRED_RESULT inline QString toString() const; // defined in qstring.h
+
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR qssize_t size() const Q_DECL_NOTHROW { return m_size; }
+ Q_REQUIRED_RESULT const_pointer data() const Q_DECL_NOTHROW { return reinterpret_cast<const_pointer>(m_data); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR const storage_type *utf16() const Q_DECL_NOTHROW { return m_data; }
+
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QChar operator[](qssize_t n) const
+ { return Q_ASSERT(n >= 0), Q_ASSERT(n < size()), QChar(m_data[n]); }
+
+ //
+ // QString API
+ //
+
+ Q_REQUIRED_RESULT QByteArray toLatin1() const { return qConvertToLatin1(*this); }
+ Q_REQUIRED_RESULT QByteArray toUtf8() const { return qConvertToUtf8(*this); }
+ Q_REQUIRED_RESULT QByteArray toLocal8Bit() const { return qConvertToLocal8Bit(*this); }
+ Q_REQUIRED_RESULT inline QVector<uint> toUcs4() const; // defined in qvector.h
+
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QChar at(qssize_t n) const { return (*this)[n]; }
+
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QStringView mid(qssize_t pos) const
+ { return Q_ASSERT(pos >= 0), Q_ASSERT(pos <= size()), QStringView(m_data + pos, m_size - pos); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QStringView mid(qssize_t pos, qssize_t n) const
+ { return Q_ASSERT(pos >= 0), Q_ASSERT(n >= 0), Q_ASSERT(pos + n <= size()), QStringView(m_data + pos, n); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QStringView left(qssize_t n) const
+ { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QStringView(m_data, n); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QStringView right(qssize_t n) const
+ { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QStringView(m_data + m_size - n, n); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QStringView chopped(qssize_t n) const
+ { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QStringView(m_data, m_size - n); }
+
+ Q_DECL_RELAXED_CONSTEXPR void truncate(qssize_t n)
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size = n; }
+ Q_DECL_RELAXED_CONSTEXPR void chop(qssize_t n)
+ { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; }
+
+ Q_REQUIRED_RESULT QStringView trimmed() const Q_DECL_NOTHROW { return qTrimmed(*this); }
+
+ Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qStartsWith(*this, s, cs); }
+ Q_REQUIRED_RESULT inline bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW;
+ Q_REQUIRED_RESULT bool startsWith(QChar c) const Q_DECL_NOTHROW
+ { return !empty() && front() == c; }
+ Q_REQUIRED_RESULT bool startsWith(QChar c, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
+ { return qStartsWith(*this, QStringView(&c, 1), cs); }
+
+ Q_REQUIRED_RESULT bool endsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW
+ { return qEndsWith(*this, s, cs); }
+ Q_REQUIRED_RESULT inline bool endsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_DECL_NOTHROW;
+ Q_REQUIRED_RESULT bool endsWith(QChar c) const Q_DECL_NOTHROW
+ { return !empty() && back() == c; }
+ Q_REQUIRED_RESULT bool endsWith(QChar c, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW
+ { return qEndsWith(*this, QStringView(&c, 1), cs); }
+
+ //
+ // STL compatibility API:
+ //
+ Q_REQUIRED_RESULT const_iterator begin() const Q_DECL_NOTHROW { return data(); }
+ Q_REQUIRED_RESULT const_iterator end() const Q_DECL_NOTHROW { return data() + size(); }
+ Q_REQUIRED_RESULT const_iterator cbegin() const Q_DECL_NOTHROW { return begin(); }
+ Q_REQUIRED_RESULT const_iterator cend() const Q_DECL_NOTHROW { return end(); }
+ Q_REQUIRED_RESULT const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); }
+ Q_REQUIRED_RESULT const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); }
+ Q_REQUIRED_RESULT const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return rbegin(); }
+ Q_REQUIRED_RESULT const_reverse_iterator crend() const Q_DECL_NOTHROW { return rend(); }
+
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR bool empty() const Q_DECL_NOTHROW { return size() == 0; }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QChar front() const { return Q_ASSERT(!empty()), QChar(m_data[0]); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QChar back() const { return Q_ASSERT(!empty()), QChar(m_data[m_size - 1]); }
+
+ //
+ // Qt compatibility API:
+ //
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR bool isNull() const Q_DECL_NOTHROW { return !m_data; }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR bool isEmpty() const Q_DECL_NOTHROW { return empty(); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR int length() const /* not nothrow! */
+ { return Q_ASSERT(int(size()) == size()), int(size()); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QChar first() const { return front(); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QChar last() const { return back(); }
+private:
+ qssize_t m_size;
+ const storage_type *m_data;
+};
+Q_DECLARE_TYPEINFO(QStringView, Q_PRIMITIVE_TYPE);
+
+template <typename QStringLike, typename std::enable_if<
+ std::is_same<QStringLike, QString>::value || std::is_same<QStringLike, QStringRef>::value,
+ bool>::type = true>
+inline QStringView qToStringViewIgnoringNull(const QStringLike &s) Q_DECL_NOTHROW
+{ return QStringView(s.data(), s.size()); }
+
+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..90311ac55b 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
@@ -234,9 +231,9 @@ public:
inline const T &front() const { return first(); }
inline T &back() { return last(); }
inline const T &back() const { return last(); }
+ void shrink_to_fit() { squeeze(); }
private:
- friend class QPodList<T, Prealloc>;
void realloc(int size, int alloc);
int a; // capacity
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 127afcd069..be2bdeda07 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -190,6 +190,12 @@
\overload
*/
+/*! \fn void QVarLengthArray::shrink_to_fit()
+ \since 5.10
+
+ Same as squeeze(). Provided for STL-compatibility.
+*/
+
/*! \fn bool QVarLengthArray::isEmpty() const
Returns \c true if the array has size 0; otherwise returns \c false.
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 57e80ae125..2d12a95b4b 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -147,8 +147,8 @@ public:
void remove(int i, int n);
inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(d->begin()); }
inline void removeLast();
- inline T takeFirst() { Q_ASSERT(!isEmpty()); T r = first(); removeFirst(); return r; }
- inline T takeLast() { Q_ASSERT(!isEmpty()); T r = last(); removeLast(); return r; }
+ T takeFirst() { Q_ASSERT(!isEmpty()); T r = std::move(first()); removeFirst(); return r; }
+ T takeLast() { Q_ASSERT(!isEmpty()); T r = std::move(last()); removeLast(); return r; }
QVector<T> &fill(const T &t, int size = -1);
@@ -180,7 +180,7 @@ public:
return true;
}
int length() const { return size(); }
- T takeAt(int i) { T t = at(i); remove(i); return t; }
+ T takeAt(int i) { T t = std::move((*this)[i]); remove(i); return t; }
void move(int from, int to)
{
Q_ASSERT_X(from >= 0 && from < size(), "QVector::move(int,int)", "'from' is out-of-range");
@@ -268,6 +268,7 @@ public:
inline const_reference front() const { return first(); }
inline reference back() { return last(); }
inline const_reference back() const { return last(); }
+ void shrink_to_fit() { squeeze(); }
// comfort
QVector<T> &operator+=(const QVector<T> &l);
@@ -994,6 +995,8 @@ Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPointF>;
Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QVector<QPoint>;
#endif
+QVector<uint> QStringView::toUcs4() const { return qConvertToUcs4(*this); }
+
QT_END_NAMESPACE
#endif // QVECTOR_H
diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc
index 0ea47b1a1a..61fb3d494d 100644
--- a/src/corelib/tools/qvector.qdoc
+++ b/src/corelib/tools/qvector.qdoc
@@ -1124,6 +1124,13 @@
\overload
*/
+/*! \fn void QVector::shrink_to_fit()
+ \since 5.10
+
+ This function is provided for STL compatibility. It is equivalent
+ to squeeze().
+*/
+
/*! \fn bool QVector::empty() const
This function is provided for STL compatibility. It is equivalent
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 97e5da8b3c..0f237bce87 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -406,10 +406,8 @@ QString QVersionNumber::toString() const
return version;
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
- \fn QVersionNumber QVersionNumber::fromString(const QString &string,
- int *suffixIndex)
-
Constructs a QVersionNumber from a specially formatted \a string of
non-negative decimal numbers delimited by '.'.
@@ -423,14 +421,53 @@ QString QVersionNumber::toString() const
*/
QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixIndex)
{
- QVector<int> seg;
+ return fromString(QLatin1String(string.toLatin1()), suffixIndex);
+}
+#endif
+
+/*!
+ \since 5.10
+ \overload
+
+ Constructs a QVersionNumber from a specially formatted \a string of
+ non-negative decimal numbers delimited by '.'.
+
+ Once the numerical segments have been parsed, the remainder of the string
+ is considered to be the suffix string. The start index of that string will be
+ stored in \a suffixIndex if it is not null.
+
+ \snippet qversionnumber/main.cpp 3
+
+ \sa isNull()
+*/
+QVersionNumber QVersionNumber::fromString(QStringView string, int *suffixIndex)
+{
+ return fromString(QLatin1String(string.toLatin1()), suffixIndex);
+}
+
+/*!
+ \since 5.10
+ \overload
- const QByteArray cString(string.toLatin1());
+ Constructs a QVersionNumber from a specially formatted \a string of
+ non-negative decimal numbers delimited by '.'.
+
+ Once the numerical segments have been parsed, the remainder of the string
+ is considered to be the suffix string. The start index of that string will be
+ stored in \a suffixIndex if it is not null.
+
+ \snippet qversionnumber/main.cpp 3-latin1-1
+
+ \sa isNull()
+*/
+QVersionNumber QVersionNumber::fromString(QLatin1String string, int *suffixIndex)
+{
+ QVector<int> seg;
- const char *start = cString.constData();
+ const char *start = string.begin();
const char *end = start;
const char *lastGoodEnd = start;
- const char *endOfString = cString.constData() + cString.size();
+ const char *endOfString = string.end();
do {
bool ok = false;
@@ -443,7 +480,7 @@ QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixInde
} while (start < endOfString && (end < endOfString && *end == '.'));
if (suffixIndex)
- *suffixIndex = int(lastGoodEnd - cString.constData());
+ *suffixIndex = int(lastGoodEnd - string.begin());
return QVersionNumber(qMove(seg));
}
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index d3cf743a67..3836bc2119 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -280,7 +280,11 @@ public:
Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
Q_REQUIRED_RESULT Q_CORE_EXPORT QString toString() const;
+#if QT_STRINGVIEW_LEVEL < 2
Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex = Q_NULLPTR);
+#endif
+ Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, int *suffixIndex = nullptr);
+ Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, int *suffixIndex = nullptr);
private:
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index b93ec824ed..3d6cc97205 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 \
@@ -58,11 +57,14 @@ HEADERS += \
tools/qsize.h \
tools/qstack.h \
tools/qstring.h \
+ tools/qstringalgorithms.h \
tools/qstringalgorithms_p.h \
tools/qstringbuilder.h \
tools/qstringiterator_p.h \
tools/qstringlist.h \
+ tools/qstringliteral.h \
tools/qstringmatcher.h \
+ tools/qstringview.h \
tools/qtextboundaryfinder.h \
tools/qtimeline.h \
tools/qtools_p.h \
@@ -107,6 +109,7 @@ SOURCES += \
tools/qstring.cpp \
tools/qstringbuilder.cpp \
tools/qstringlist.cpp \
+ tools/qstringview.cpp \
tools/qtextboundaryfinder.cpp \
tools/qtimeline.cpp \
tools/qunicodetools.cpp \
diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp
index af35193b13..195466e803 100644
--- a/src/corelib/xml/qxmlstream.cpp
+++ b/src/corelib/xml/qxmlstream.cpp
@@ -775,8 +775,8 @@ QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
tagStackStringStorage.reserve(32);
tagStackStringStorageSize = 0;
NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
- namespaceDeclaration.prefix = addToStringStorage(QLatin1String("xml"));
- namespaceDeclaration.namespaceUri = addToStringStorage(QLatin1String("http://www.w3.org/XML/1998/namespace"));
+ namespaceDeclaration.prefix = addToStringStorage(QStringViewLiteral("xml"));
+ namespaceDeclaration.namespaceUri = addToStringStorage(QStringViewLiteral("http://www.w3.org/XML/1998/namespace"));
initialTagStackStringStorageSize = tagStackStringStorageSize;
}
@@ -1558,7 +1558,7 @@ QStringRef QXmlStreamReaderPrivate::namespaceForPrefix(const QStringRef &prefix)
#if 1
if (namespaceProcessing && !prefix.isEmpty())
- raiseWellFormedError(QXmlStream::tr("Namespace prefix '%1' not declared").arg(prefix.toString()));
+ raiseWellFormedError(QXmlStream::tr("Namespace prefix '%1' not declared").arg(prefix));
#endif
return QStringRef();
@@ -1636,7 +1636,7 @@ void QXmlStreamReaderPrivate::resolveTag()
if (attributes[j].name() == attribute.name()
&& attributes[j].namespaceUri() == attribute.namespaceUri()
&& (namespaceProcessing || attributes[j].qualifiedName() == attribute.qualifiedName()))
- raiseWellFormedError(QXmlStream::tr("Attribute '%1' redefined.").arg(attribute.qualifiedName().toString()));
+ raiseWellFormedError(QXmlStream::tr("Attribute '%1' redefined.").arg(attribute.qualifiedName()));
}
}
@@ -1798,20 +1798,19 @@ void QXmlStreamReaderPrivate::startDocument()
QStringRef value(symString(attrib.value));
if (prefix.isEmpty() && key == QLatin1String("encoding")) {
- const QString name(value.toString());
documentEncoding = value;
if(hasStandalone)
err = QXmlStream::tr("The standalone pseudo attribute must appear after the encoding.");
- if(!QXmlUtils::isEncName(name))
- err = QXmlStream::tr("%1 is an invalid encoding name.").arg(name);
+ if (!QXmlUtils::isEncName(value))
+ err = QXmlStream::tr("%1 is an invalid encoding name.").arg(value);
else {
#ifdef QT_NO_TEXTCODEC
readBuffer = QString::fromLatin1(rawReadBuffer.data(), nbytesread);
#else
- QTextCodec *const newCodec = QTextCodec::codecForName(name.toLatin1());
+ QTextCodec *const newCodec = QTextCodec::codecForName(value.toLatin1());
if (!newCodec)
- err = QXmlStream::tr("Encoding %1 is unsupported").arg(name);
+ err = QXmlStream::tr("Encoding %1 is unsupported").arg(value);
else if (newCodec != codec && !lockEncoding) {
codec = newCodec;
delete decoder;
diff --git a/src/corelib/xml/qxmlstream.g b/src/corelib/xml/qxmlstream.g
index 567d36d4b9..73085bda8a 100644
--- a/src/corelib/xml/qxmlstream.g
+++ b/src/corelib/xml/qxmlstream.g
@@ -201,23 +201,22 @@ public:
QXmlStreamSimpleStack<NamespaceDeclaration> namespaceDeclarations;
QString tagStackStringStorage;
int tagStackStringStorageSize;
+ int initialTagStackStringStorageSize;
bool tagsDone;
inline QStringRef addToStringStorage(const QStringRef &s) {
- int pos = tagStackStringStorageSize;
- int sz = s.size();
- if (pos != tagStackStringStorage.size())
- tagStackStringStorage.resize(pos);
- tagStackStringStorage.insert(pos, s.unicode(), sz);
- tagStackStringStorageSize += sz;
- return QStringRef(&tagStackStringStorage, pos, sz);
+ return addToStringStorage(qToStringViewIgnoringNull(s));
}
inline QStringRef addToStringStorage(const QString &s) {
+ return addToStringStorage(qToStringViewIgnoringNull(s));
+ }
+ QStringRef addToStringStorage(QStringView s)
+ {
int pos = tagStackStringStorageSize;
int sz = s.size();
if (pos != tagStackStringStorage.size())
tagStackStringStorage.resize(pos);
- tagStackStringStorage.insert(pos, s.unicode(), sz);
+ tagStackStringStorage.append(s.data(), sz);
tagStackStringStorageSize += sz;
return QStringRef(&tagStackStringStorage, pos, sz);
}
@@ -455,7 +454,7 @@ public:
short token;
- ushort token_char;
+ uint token_char;
uint filterCarriageReturn();
inline uint getChar();
@@ -466,7 +465,7 @@ public:
void putStringLiteral(const QString &s);
void putReplacement(const QString &s);
void putReplacementInAttributeValue(const QString &s);
- ushort getChar_helper();
+ uint getChar_helper();
bool scanUntil(const char *str, short tokenToInject = -1);
bool scanString(const char *str, short tokenToInject, bool requireSpace = true);
@@ -525,10 +524,8 @@ bool QXmlStreamReaderPrivate::parse()
prefix.clear();
qualifiedName.clear();
namespaceUri.clear();
- if (publicNamespaceDeclarations.size())
- publicNamespaceDeclarations.clear();
- if (attributes.size())
- attributes.resize(0);
+ publicNamespaceDeclarations.clear();
+ attributes.clear();
if (isEmptyElement) {
setType(QXmlStreamReader::EndElement);
Tag &tag = tagStack_pop();
@@ -553,7 +550,7 @@ bool QXmlStreamReaderPrivate::parse()
dtdName.clear();
dtdPublicId.clear();
dtdSystemId.clear();
- // fall through
+ Q_FALLTHROUGH();
case QXmlStreamReader::Comment:
case QXmlStreamReader::Characters:
isCDATA = false;
@@ -579,13 +576,13 @@ bool QXmlStreamReaderPrivate::parse()
documentVersion.clear();
documentEncoding.clear();
#ifndef QT_NO_TEXTCODEC
- if (decoder->hasFailure()) {
+ if (decoder && decoder->hasFailure()) {
raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content."));
readBuffer.clear();
return false;
}
#endif
- // fall through
+ Q_FALLTHROUGH();
default:
clearTextBuffer();
;
@@ -610,8 +607,8 @@ bool QXmlStreamReaderPrivate::parse()
if (token == -1 && - TERMINAL_COUNT != action_index[act]) {
uint cu = getChar();
token = NOTOKEN;
- token_char = cu;
- if (cu & 0xff0000) {
+ token_char = cu == ~0U ? cu : ushort(cu);
+ if ((cu != ~0U) && (cu & 0xff0000)) {
token = cu >> 16;
} else switch (token_char) {
case 0xfffe:
@@ -629,8 +626,8 @@ bool QXmlStreamReaderPrivate::parse()
} else {
break;
}
- // fall through
- case '\0': {
+ Q_FALLTHROUGH();
+ case ~0U: {
token = EOF_SYMBOL;
if (!tagsDone && !inParseEntity) {
int a = t_action(act, token);
@@ -644,6 +641,7 @@ bool QXmlStreamReaderPrivate::parse()
case '\n':
++lineNumber;
lastLineStart = characterOffset + readBufferPos;
+ Q_FALLTHROUGH();
case ' ':
case '\t':
token = SPACE;
@@ -1127,7 +1125,7 @@ entity_decl ::= entity_decl_external NDATA name space_opt RANGLE;
if (entityDeclaration.parameter)
raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration."));
}
- //fall through
+ Q_FALLTHROUGH();
./
entity_decl ::= entity_decl_external space_opt RANGLE;
@@ -1164,12 +1162,12 @@ processing_instruction ::= LANGLE QUESTIONMARK name space;
processingInstructionTarget = symString(3);
if (scanUntil("?>")) {
processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2);
- const QString piTarget(processingInstructionTarget.toString());
- if (!piTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) {
+ if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) {
raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document."));
}
- else if(!QXmlUtils::isNCName(piTarget))
- raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.").arg(piTarget));
+ else if (!QXmlUtils::isNCName(processingInstructionTarget))
+ raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.")
+ .arg(processingInstructionTarget));
} else if (type != QXmlStreamReader::Invalid){
resume($rule_number);
return false;
@@ -1182,7 +1180,7 @@ processing_instruction ::= LANGLE QUESTIONMARK name QUESTIONMARK RANGLE;
case $rule_number:
setType(QXmlStreamReader::ProcessingInstruction);
processingInstructionTarget = symString(3);
- if (!processingInstructionTarget.toString().compare(QLatin1String("xml"), Qt::CaseInsensitive))
+ if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive))
raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name."));
break;
./
@@ -1281,7 +1279,7 @@ scan_content_char ::= content_char;
/.
case $rule_number:
isWhitespace = false;
- // fall through
+ Q_FALLTHROUGH();
./
scan_content_char ::= SPACE;
@@ -1379,8 +1377,8 @@ literal_content ::= literal_content_start;
public_literal ::= literal;
/.
case $rule_number: {
- if (!QXmlUtils::isPublicID(symString(1).toString())) {
- raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1).toString()));
+ if (!QXmlUtils::isPublicID(symString(1))) {
+ raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1)));
resume($rule_number);
return false;
}
@@ -1567,7 +1565,7 @@ empty_element_tag ::= stag_start attribute_list_opt SLASH RANGLE;
/.
case $rule_number:
isEmptyElement = true;
- // fall through
+ Q_FALLTHROUGH();
./
@@ -1669,7 +1667,7 @@ pereference ::= PERCENT name SEMICOLON;
clearSym();
}
} else if (entitiesMustBeDeclared()) {
- raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2).toString()));
+ raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2)));
}
} break;
./
diff --git a/src/corelib/xml/qxmlstream_p.h b/src/corelib/xml/qxmlstream_p.h
index 9ef95c1fbe..8ef6e4b8fe 100644
--- a/src/corelib/xml/qxmlstream_p.h
+++ b/src/corelib/xml/qxmlstream_p.h
@@ -701,20 +701,18 @@ public:
bool tagsDone;
inline QStringRef addToStringStorage(const QStringRef &s) {
- int pos = tagStackStringStorageSize;
- int sz = s.size();
- if (pos != tagStackStringStorage.size())
- tagStackStringStorage.resize(pos);
- tagStackStringStorage.insert(pos, s.unicode(), sz);
- tagStackStringStorageSize += sz;
- return QStringRef(&tagStackStringStorage, pos, sz);
+ return addToStringStorage(qToStringViewIgnoringNull(s));
}
inline QStringRef addToStringStorage(const QString &s) {
+ return addToStringStorage(qToStringViewIgnoringNull(s));
+ }
+ QStringRef addToStringStorage(QStringView s)
+ {
int pos = tagStackStringStorageSize;
int sz = s.size();
if (pos != tagStackStringStorage.size())
tagStackStringStorage.resize(pos);
- tagStackStringStorage.insert(pos, s.unicode(), sz);
+ tagStackStringStorage.append(s.data(), sz);
tagStackStringStorageSize += sz;
return QStringRef(&tagStackStringStorage, pos, sz);
}
@@ -1508,12 +1506,12 @@ bool QXmlStreamReaderPrivate::parse()
processingInstructionTarget = symString(3);
if (scanUntil("?>")) {
processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2);
- const QString piTarget(processingInstructionTarget.toString());
- if (!piTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) {
+ if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) {
raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document."));
}
- else if(!QXmlUtils::isNCName(piTarget))
- raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.").arg(piTarget));
+ else if (!QXmlUtils::isNCName(processingInstructionTarget))
+ raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.")
+ .arg(processingInstructionTarget));
} else if (type != QXmlStreamReader::Invalid){
resume(96);
return false;
@@ -1523,7 +1521,7 @@ bool QXmlStreamReaderPrivate::parse()
case 97:
setType(QXmlStreamReader::ProcessingInstruction);
processingInstructionTarget = symString(3);
- if (!processingInstructionTarget.toString().compare(QLatin1String("xml"), Qt::CaseInsensitive))
+ if (!processingInstructionTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive))
raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name."));
break;
@@ -1637,8 +1635,8 @@ bool QXmlStreamReaderPrivate::parse()
break;
case 175: {
- if (!QXmlUtils::isPublicID(symString(1).toString())) {
- raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1).toString()));
+ if (!QXmlUtils::isPublicID(symString(1))) {
+ raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1)));
resume(175);
return false;
}
@@ -1845,7 +1843,7 @@ bool QXmlStreamReaderPrivate::parse()
clearSym();
}
} else if (entitiesMustBeDeclared()) {
- raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2).toString()));
+ raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2)));
}
} break;
diff --git a/src/corelib/xml/qxmlutils.cpp b/src/corelib/xml/qxmlutils.cpp
index 23caae2935..01c84251fd 100644
--- a/src/corelib/xml/qxmlutils.cpp
+++ b/src/corelib/xml/qxmlutils.cpp
@@ -227,19 +227,22 @@ bool QXmlUtils::isBaseChar(const QChar c)
\sa {http://www.w3.org/TR/REC-xml/#NT-EncName},
{Extensible Markup Language (XML) 1.0 (Fourth Edition), [81] EncName}
*/
-bool QXmlUtils::isEncName(const QString &encName)
+bool QXmlUtils::isEncName(QStringView encName)
{
// Valid encoding names are given by "[A-Za-z][A-Za-z0-9._\\-]*"
- const ushort *c = encName.utf16();
- int l = encName.length();
- if (l < 1 || !((c[0] >= 'a' && c[0] <= 'z') || (c[0] >= 'A' && c[0] <= 'Z')))
+ if (encName.isEmpty())
return false;
- for (int i = 1; i < l; ++i) {
- if ((c[i] >= 'a' && c[i] <= 'z')
- || (c[i] >= 'A' && c[i] <= 'Z')
- || (c[i] >= '0' && c[i] <= '9')
- || c[i] == '.' || c[i] == '_' || c[i] == '-')
+ const auto first = encName.front().unicode();
+ if (!((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')))
+ return false;
+ for (QChar ch : encName.mid(1)) {
+ const auto cp = ch.unicode();
+ if ((cp >= 'a' && cp <= 'z')
+ || (cp >= 'A' && cp <= 'Z')
+ || (cp >= '0' && cp <= '9')
+ || cp == '.' || cp == '_' || cp == '-') {
continue;
+ }
return false;
}
return true;
@@ -310,13 +313,10 @@ bool QXmlUtils::isNameChar(const QChar c)
\sa {http://www.w3.org/TR/REC-xml/#NT-PubidLiteral},
{Extensible Markup Language (XML) 1.0 (Fourth Edition), [12] PubidLiteral}
*/
-bool QXmlUtils::isPublicID(const QString &candidate)
+bool QXmlUtils::isPublicID(QStringView candidate)
{
- const int len = candidate.length();
-
- for(int i = 0; i < len; ++i)
- {
- const ushort cp = candidate.at(i).unicode();
+ for (QChar ch : candidate) {
+ const ushort cp = ch.unicode();
if ((cp >= 'a' && cp <= 'z')
|| (cp >= 'A' && cp <= 'Z')
@@ -369,7 +369,7 @@ bool QXmlUtils::isPublicID(const QString &candidate)
\sa {http://www.w3.org/TR/REC-xml-names/#NT-NCName},
{W3CNamespaces in XML 1.0 (Second Edition), [4] NCName}
*/
-bool QXmlUtils::isNCName(const QStringRef &ncName)
+bool QXmlUtils::isNCName(QStringView ncName)
{
if(ncName.isEmpty())
return false;
@@ -379,10 +379,7 @@ bool QXmlUtils::isNCName(const QStringRef &ncName)
if(!QXmlUtils::isLetter(first) && first.unicode() != '_' && first.unicode() != ':')
return false;
- const int len = ncName.size();
- for(int i = 0; i < len; ++i)
- {
- const QChar at = ncName.at(i);
+ for (QChar at : ncName) {
if(!QXmlUtils::isNameChar(at) || at == QLatin1Char(':'))
return false;
}
diff --git a/src/corelib/xml/qxmlutils_p.h b/src/corelib/xml/qxmlutils_p.h
index 6db347b3ee..db6bddd5be 100644
--- a/src/corelib/xml/qxmlutils_p.h
+++ b/src/corelib/xml/qxmlutils_p.h
@@ -68,13 +68,12 @@ class QXmlCharRange;
class Q_CORE_EXPORT QXmlUtils
{
public:
- static bool isEncName(const QString &encName);
+ static bool isEncName(QStringView encName);
static bool isChar(const QChar c);
static bool isNameChar(const QChar c);
static bool isLetter(const QChar c);
- static bool isNCName(const QStringRef &ncName);
- static inline bool isNCName(const QString &ncName) { return isNCName(QStringRef(&ncName)); }
- static bool isPublicID(const QString &candidate);
+ static bool isNCName(QStringView ncName);
+ static bool isPublicID(QStringView candidate);
private:
typedef const QXmlCharRange *RangeIter;