summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/configure.json27
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h14
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm14
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp19
-rw-r--r--src/corelib/doc/src/objectmodel/signalsandslots.qdoc3
-rw-r--r--src/corelib/global/global.pri23
-rw-r--r--src/corelib/global/qcompilerdetection.h12
-rw-r--r--src/corelib/global/qflags.h11
-rw-r--r--src/corelib/global/qfloat16.cpp130
-rw-r--r--src/corelib/global/qfloat16.h259
-rw-r--r--src/corelib/global/qfloat16_p.h95
-rw-r--r--src/corelib/global/qglobal.cpp365
-rw-r--r--src/corelib/global/qglobal.h62
-rw-r--r--src/corelib/global/qglobal_p.h32
-rw-r--r--src/corelib/global/qhooks.cpp2
-rw-r--r--src/corelib/global/qlibraryinfo.cpp2
-rw-r--r--src/corelib/global/qlogging.cpp6
-rw-r--r--src/corelib/global/qnamespace.h9
-rw-r--r--src/corelib/global/qnamespace.qdoc23
-rw-r--r--src/corelib/global/qnumeric_p.h4
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp491
-rw-r--r--src/corelib/global/qoperatingsystemversion.h129
-rw-r--r--src/corelib/global/qoperatingsystemversion_darwin.mm56
-rw-r--r--src/corelib/global/qoperatingsystemversion_p.h87
-rw-r--r--src/corelib/global/qoperatingsystemversion_win.cpp171
-rw-r--r--src/corelib/global/qprocessordetection.h7
-rw-r--r--src/corelib/global/qsysinfo.h55
-rw-r--r--src/corelib/global/qsystemdetection.h1
-rw-r--r--src/corelib/global/qtypeinfo.h11
-rw-r--r--src/corelib/global/qtypetraits.h55
-rw-r--r--src/corelib/io/io.pri4
-rw-r--r--src/corelib/io/qdatastream.cpp53
-rw-r--r--src/corelib/io/qdatastream.h295
-rw-r--r--src/corelib/io/qdebug.h12
-rw-r--r--src/corelib/io/qdir.cpp67
-rw-r--r--src/corelib/io/qdir.h2
-rw-r--r--src/corelib/io/qfileinfo.cpp18
-rw-r--r--src/corelib/io/qfileselector.cpp13
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp30
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp53
-rw-r--r--src/corelib/io/qfilesystementry.cpp2
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp7
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h2
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp53
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h10
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp286
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h15
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp4
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp27
-rw-r--r--src/corelib/io/qlockfile_unix.cpp1
-rw-r--r--src/corelib/io/qloggingregistry.cpp90
-rw-r--r--src/corelib/io/qloggingregistry_p.h7
-rw-r--r--src/corelib/io/qprocess.cpp6
-rw-r--r--src/corelib/io/qprocess.h15
-rw-r--r--src/corelib/io/qprocess_darwin.mm58
-rw-r--r--src/corelib/io/qprocess_p.h6
-rw-r--r--src/corelib/io/qprocess_unix.cpp62
-rw-r--r--src/corelib/io/qprocess_win.cpp49
-rw-r--r--src/corelib/io/qsavefile.cpp20
-rw-r--r--src/corelib/io/qsavefile.h7
-rw-r--r--src/corelib/io/qsettings.cpp250
-rw-r--r--src/corelib/io/qsettings_mac.cpp20
-rw-r--r--src/corelib/io/qsettings_p.h18
-rw-r--r--src/corelib/io/qsettings_win.cpp31
-rw-r--r--src/corelib/io/qstorageinfo.cpp22
-rw-r--r--src/corelib/io/qstorageinfo.h3
-rw-r--r--src/corelib/io/qstorageinfo_p.h1
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp53
-rw-r--r--src/corelib/io/qtemporarydir.cpp27
-rw-r--r--src/corelib/io/qtemporarydir.h1
-rw-r--r--src/corelib/io/qtextstream.cpp15
-rw-r--r--src/corelib/io/qurl.cpp9
-rw-r--r--src/corelib/io/qurl.h4
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp2
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.cpp29
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.h25
-rw-r--r--src/corelib/itemmodels/qstringlistmodel.h2
-rw-r--r--src/corelib/kernel/kernel.pri9
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.h2
-rw-r--r--src/corelib/kernel/qcore_foundation.mm72
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm54
-rw-r--r--src/corelib/kernel/qcore_mac_p.h6
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp95
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h5
-rw-r--r--src/corelib/kernel/qcoreapplication_win.cpp85
-rw-r--r--src/corelib/kernel/qcoreevent.cpp1
-rw-r--r--src/corelib/kernel/qcoreevent.h2
-rw-r--r--src/corelib/kernel/qdeadlinetimer.cpp108
-rw-r--r--src/corelib/kernel/qdeadlinetimer.h32
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf.mm3
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp10
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h2
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp12
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h14
-rw-r--r--src/corelib/kernel/qmetaobject_p.h12
-rw-r--r--src/corelib/kernel/qmetatype.cpp110
-rw-r--r--src/corelib/kernel/qmetatype.h8
-rw-r--r--src/corelib/kernel/qmetatype_p.h2
-rw-r--r--src/corelib/kernel/qobject.cpp142
-rw-r--r--src/corelib/kernel/qobject.h29
-rw-r--r--src/corelib/kernel/qobjectdefs.h36
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h9
-rw-r--r--src/corelib/kernel/qppsobject.cpp3
-rw-r--r--src/corelib/kernel/qppsobject_p.h1
-rw-r--r--src/corelib/kernel/qsharedmemory_win.cpp32
-rw-r--r--src/corelib/kernel/qsystemsemaphore_systemv.cpp26
-rw-r--r--src/corelib/kernel/qtcore_eval.cpp2
-rw-r--r--src/corelib/kernel/qtimer.h16
-rw-r--r--src/corelib/kernel/qvariant.cpp19
-rw-r--r--src/corelib/kernel/qwineventnotifier.h2
-rw-r--r--src/corelib/mimetypes/qmimeglobpattern_p.h6
-rw-r--r--src/corelib/mimetypes/qmimetypeparser.cpp3
-rw-r--r--src/corelib/plugin/qelfparser_p.cpp48
-rw-r--r--src/corelib/plugin/qlibrary_unix.cpp10
-rw-r--r--src/corelib/plugin/quuid.cpp4
-rw-r--r--src/corelib/statemachine/qfinalstate_p.h34
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp2
-rw-r--r--src/corelib/thread/qgenericatomic.h24
-rw-r--r--src/corelib/thread/qmutex.cpp15
-rw-r--r--src/corelib/thread/qmutex.h12
-rw-r--r--src/corelib/thread/qthread.cpp8
-rw-r--r--src/corelib/thread/qthread_unix.cpp8
-rw-r--r--src/corelib/thread/qthreadpool.cpp55
-rw-r--r--src/corelib/thread/qthreadpool.h5
-rw-r--r--src/corelib/thread/qthreadpool_p.h3
-rw-r--r--src/corelib/tools/qarraydata.cpp51
-rw-r--r--src/corelib/tools/qarraydata.h11
-rw-r--r--src/corelib/tools/qarraydataops.h14
-rw-r--r--src/corelib/tools/qbytearray.cpp163
-rw-r--r--src/corelib/tools/qbytearray.h17
-rw-r--r--src/corelib/tools/qbytearraymatcher.cpp108
-rw-r--r--src/corelib/tools/qbytearraymatcher.h81
-rw-r--r--src/corelib/tools/qchar.cpp4
-rw-r--r--src/corelib/tools/qcollator.h2
-rw-r--r--src/corelib/tools/qcollator_icu.cpp5
-rw-r--r--src/corelib/tools/qcollator_macx.cpp7
-rw-r--r--src/corelib/tools/qcollator_p.h9
-rw-r--r--src/corelib/tools/qcollator_posix.cpp2
-rw-r--r--src/corelib/tools/qcollator_win.cpp5
-rw-r--r--src/corelib/tools/qdatetime.cpp77
-rw-r--r--src/corelib/tools/qdatetime_p.h7
-rw-r--r--src/corelib/tools/qeasingcurve.h2
-rw-r--r--src/corelib/tools/qhash.cpp25
-rw-r--r--src/corelib/tools/qhash.h1
-rw-r--r--src/corelib/tools/qlist.h1
-rw-r--r--src/corelib/tools/qlocale.cpp74
-rw-r--r--src/corelib/tools/qlocale.h4
-rw-r--r--src/corelib/tools/qlocale.qdoc11
-rw-r--r--src/corelib/tools/qlocale_mac.mm33
-rw-r--r--src/corelib/tools/qlocale_p.h7
-rw-r--r--src/corelib/tools/qlocale_win.cpp15
-rw-r--r--src/corelib/tools/qmap.h5
-rw-r--r--src/corelib/tools/qregularexpression.cpp565
-rw-r--r--src/corelib/tools/qringbuffer.cpp1
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h4
-rw-r--r--src/corelib/tools/qsimd_p.h5
-rw-r--r--src/corelib/tools/qstring.cpp199
-rw-r--r--src/corelib/tools/qstring.h69
-rw-r--r--src/corelib/tools/qstring_compat.cpp2
-rw-r--r--src/corelib/tools/qstringbuilder.h22
-rw-r--r--src/corelib/tools/qtimezone.h12
-rw-r--r--src/corelib/tools/qtimezoneprivate.cpp249
-rw-r--r--src/corelib/tools/qtimezoneprivate_android.cpp54
-rw-r--r--src/corelib/tools/qtimezoneprivate_icu.cpp4
-rw-r--r--src/corelib/tools/qtimezoneprivate_mac.mm7
-rw-r--r--src/corelib/tools/qtimezoneprivate_p.h34
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp139
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp4
-rw-r--r--src/corelib/tools/qvarlengtharray.h15
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc28
-rw-r--r--src/corelib/tools/qvector.h8
-rw-r--r--src/corelib/tools/qvsnprintf.cpp2
-rw-r--r--src/corelib/tools/tools.pri3
-rw-r--r--src/corelib/xml/qxmlutils_p.h2
174 files changed, 5154 insertions, 2174 deletions
diff --git a/src/corelib/configure.json b/src/corelib/configure.json
index 6da3b61a2d..c6c5c93ddb 100644
--- a/src/corelib/configure.json
+++ b/src/corelib/configure.json
@@ -84,11 +84,11 @@
"-ldl"
]
},
- "pcre": {
- "label": "PCRE",
- "test": "unix/pcre",
+ "pcre2": {
+ "label": "PCRE2",
+ "test": "unix/pcre2",
"sources": [
- "-lpcre16"
+ "-lpcre2-16"
]
},
"pps": {
@@ -301,14 +301,14 @@
"condition": "features.textcodec",
"output": [ "publicFeature", "feature" ]
},
- "system-pcre": {
- "label": "Using system PCRE",
+ "system-pcre2": {
+ "label": "Using system PCRE2",
"disable": "input.pcre == 'qt'",
"enable": "input.pcre == 'system'",
- "condition": "libs.pcre",
+ "condition": "libs.pcre2",
"output": [
"privateFeature",
- { "type": "privateConfig", "negative": true, "name": "pcre" }
+ { "type": "privateConfig", "negative": true, "name": "pcre2" }
]
},
"poll_ppoll": {
@@ -436,9 +436,16 @@
"label": "QProcess",
"purpose": "Supports external process invocation.",
"section": "File I/O",
- "condition": "!config.winrt && !config.uikit && !config.integrity && !config.vxworks",
+ "condition": "features.processenvironment && !config.winrt && !config.uikit && !config.integrity && !config.vxworks",
"output": [ "publicFeature", "feature" ]
},
+ "processenvironment": {
+ "label": "QProcessEnvironment",
+ "purpose": "Provides a higher-level abstraction of environment variables.",
+ "section": "File I/O",
+ "condition": "!config.winrt && !config.integrity",
+ "output": [ "publicFeature" ]
+ },
"temporaryfile": {
"label": "QTemporaryFile",
"purpose": "Provides an I/O device that operates on temporary files.",
@@ -624,7 +631,7 @@ Please apply the patch corresponding to your Standard Library vendor, found in
"args": "qqnx_pps",
"condition": "config.qnx"
},
- "system-pcre"
+ "system-pcre2"
]
}
]
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
index 9734f99d50..bb44782ac5 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2016 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** 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
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
index 8abd576259..7c40330de0 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2016 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** 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
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
index 9fd52517c2..c12ed147db 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
@@ -48,14 +48,6 @@
**
****************************************************************************/
-//! [0]
-QLineEdit *lineEdit = static_cast<QLineEdit *>(
- qt_find_obj_child(myWidget, "QLineEdit", "my line edit"));
-if (lineEdit)
- lineEdit->setText("Default");
-//! [0]
-
-
//! [1]
QObject *obj = new QPushButton;
obj->metaObject()->className(); // returns "QPushButton"
@@ -164,6 +156,17 @@ MyObject::MyObject(QObject *parent)
startTimer(50); // 50-millisecond timer
startTimer(1000); // 1-second timer
startTimer(60000); // 1-minute timer
+
+ using namespace std::chrono;
+ startTimer(milliseconds(50));
+ startTimer(seconds(1));
+ startTimer(minutes(1));
+
+ // since C++14 we can use std::chrono::duration literals, e.g.:
+ startTimer(100ms);
+ startTimer(5s);
+ startTimer(2min);
+ startTimer(1h);
}
void MyObject::timerEvent(QTimerEvent *event)
diff --git a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
index 6366350cde..ed61511c62 100644
--- a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
+++ b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
@@ -364,9 +364,6 @@
connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });
\endcode
- Note that if your compiler does not support C++11 variadic templates,
- this syntax only works if the signal and slot have 6 arguments or less.
-
The other way to connect a signal to a slot is to use QObject::connect()
and the \c{SIGNAL} and \c{SLOT} macros.
The rule about whether to
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index 36655ca1dd..f162dd95dd 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -2,6 +2,8 @@
HEADERS += \
global/qglobal.h \
+ global/qoperatingsystemversion.h \
+ global/qoperatingsystemversion_p.h \
global/qsystemdetection.h \
global/qcompilerdetection.h \
global/qprocessordetection.h \
@@ -9,6 +11,8 @@ HEADERS += \
global/qendian.h \
global/qnumeric_p.h \
global/qnumeric.h \
+ global/qfloat16_p.h \
+ global/qfloat16.h \
global/qglobalstatic.h \
global/qlibraryinfo.h \
global/qlogging.h \
@@ -27,11 +31,16 @@ SOURCES += \
global/qlibraryinfo.cpp \
global/qmalloc.cpp \
global/qnumeric.cpp \
+ global/qfloat16.cpp \
+ global/qoperatingsystemversion.cpp \
global/qlogging.cpp \
global/qhooks.cpp
VERSIONTAGGING_SOURCES = global/qversiontagging.cpp
+darwin: SOURCES += global/qoperatingsystemversion_darwin.mm
+win32: SOURCES += global/qoperatingsystemversion_win.cpp
+
# qlibraryinfo.cpp includes qconfig.cpp
INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global
@@ -70,3 +79,17 @@ gcc:ltcg {
} else {
SOURCES += $$VERSIONTAGGING_SOURCES
}
+
+# On AARCH64 the fp16 extension is mandatory, so we don't need the conversion tables.
+!contains(QT_ARCH, "arm64") {
+ QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h
+
+ qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables)
+
+ qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT}
+ qfloat16_tables.output = global/qfloat16tables.cpp
+ qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES
+ qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE
+ qfloat16_tables.variable_out = SOURCES
+ QMAKE_EXTRA_COMPILERS += qfloat16_tables
+}
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index eacb7a04d7..5497b9e14a 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -172,7 +172,11 @@
/* Clang also masquerades as GCC */
# if defined(__apple_build_version__)
# /* http://en.wikipedia.org/wiki/Xcode#Toolchain_Versions */
-# if __apple_build_version__ >= 7000053
+# if __apple_build_version__ >= 8020041
+# define Q_CC_CLANG 309
+# elif __apple_build_version__ >= 8000038
+# define Q_CC_CLANG 308
+# elif __apple_build_version__ >= 7000053
# define Q_CC_CLANG 306
# elif __apple_build_version__ >= 6000051
# define Q_CC_CLANG 305
@@ -354,6 +358,7 @@
# elif defined(__ghs)
# define Q_CC_GHS
# define Q_DECL_DEPRECATED __attribute__ ((__deprecated__))
+# define Q_PACKED __attribute__ ((__packed__))
# define Q_FUNC_INFO __PRETTY_FUNCTION__
# define Q_TYPEOF(expr) __typeof__(expr)
# define Q_ALIGNOF(type) __alignof__(type)
@@ -627,10 +632,7 @@
# define Q_COMPILER_ALIGNAS
# define Q_COMPILER_ALIGNOF
# define Q_COMPILER_INHERITING_CONSTRUCTORS
-# ifndef Q_OS_OSX
-// C++11 thread_local is broken on OS X (Clang doesn't support it either)
-# define Q_COMPILER_THREAD_LOCAL
-# endif
+# define Q_COMPILER_THREAD_LOCAL
# define Q_COMPILER_UDL
# endif
# ifdef _MSC_VER
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index b871c90c9d..feeb488acd 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -42,15 +42,14 @@
#ifndef QFLAGS_H
#define QFLAGS_H
-#include <QtCore/qtypeinfo.h>
-#include <QtCore/qtypetraits.h>
-
#ifdef Q_COMPILER_INITIALIZER_LISTS
#include <initializer_list>
#endif
QT_BEGIN_NAMESPACE
+class QDataStream;
+
class QFlag
{
int i;
@@ -94,8 +93,12 @@ class QFlags
Q_STATIC_ASSERT_X((sizeof(Enum) <= sizeof(int)),
"QFlags uses an int as storage, so an enum with underlying "
"long long will overflow.");
+ Q_STATIC_ASSERT_X((std::is_enum<Enum>::value), "QFlags is only usable on enumeration types.");
+
struct Private;
typedef int (Private::*Zero);
+ template <typename E> friend QDataStream &operator>>(QDataStream &, QFlags<E> &);
+ template <typename E> friend QDataStream &operator<<(QDataStream &, QFlags<E>);
public:
#if defined(Q_CC_MSVC) || defined(Q_QDOC)
// see above for MSVC
@@ -103,7 +106,7 @@ public:
typedef int Int;
#else
typedef typename std::conditional<
- QtPrivate::QIsUnsignedEnum<Enum>::value,
+ std::is_unsigned<typename std::underlying_type<Enum>::type>::value,
unsigned int,
signed int
>::type Int;
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
new file mode 100644
index 0000000000..1de1ae65fb
--- /dev/null
+++ b/src/corelib/global/qfloat16.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 by Southwest Research Institute (R)
+** Contact: http://www.qt-project.org/legal
+**
+** 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 "qfloat16_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*! \headerfile <QFloat16>
+
+ This header file provides support for half-precision (16-bit) floating
+ point data with the class \c qfloat16. It is fully compliant with IEEE
+ 754 as a storage type. This implies that any arithmetic operation on a
+ \c qfloat16 instance results in the value first being converted to a
+ \c float. This conversion to and from \c float is performed by hardware
+ when possible, but on processors that do not natively support half-precision,
+ the conversion is performed through a sequence of lookup table operations.
+
+ \c qfloat16 should be treated as if it were a POD (plain old data) type.
+ Consequently, none of the supported operations need any elaboration beyond
+ stating that it supports all arithmetic operators incident to floating point
+ types.
+
+ \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>
+
+ \sa qIsInf
+*/
+Q_REQUIRED_RESULT bool qIsInf(qfloat16 f) Q_DECL_NOTHROW { return qt_is_inf(f); }
+
+/*!
+ Returns true if the \c qfloat16 \a {f} is not a number (NaN).
+ \relates <QFloat16>
+
+ \sa qIsNaN
+*/
+Q_REQUIRED_RESULT bool qIsNaN(qfloat16 f) Q_DECL_NOTHROW { return qt_is_nan(f); }
+
+/*!
+ Returns true if the \c qfloat16 \a {f} is a finite number.
+ \relates <QFloat16>
+
+ \sa qIsFinite
+*/
+Q_REQUIRED_RESULT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW { return qt_is_finite(f); }
+
+/*! \fn int qRound(qfloat16 value)
+ \relates <QFloat16>
+
+ Rounds \a value to the nearest integer.
+
+ \sa qRound
+*/
+
+/*! \fn qint64 qRound64(qfloat16 value)
+ \relates <QFloat16>
+
+ Rounds \a value to the nearest 64-bit integer.
+
+ \sa qRound64
+*/
+
+/*! \fn bool qFuzzyCompare(qfloat16 p1, qfloat16 p2)
+ \relates <QFloat16>
+
+ Compares the floating point value \a p1 and \a p2 and
+ returns \c true if they are considered equal, otherwise \c false.
+
+ The two numbers are compared in a relative way, where the
+ exactness is stronger the smaller the numbers are.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
new file mode 100644
index 0000000000..3b54719f4f
--- /dev/null
+++ b/src/corelib/global/qfloat16.h
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 by Southwest Research Institute (R)
+** Contact: http://www.qt-project.org/legal
+**
+** 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 QFLOAT16_H
+#define QFLOAT16_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <string.h>
+
+#if defined __F16C__
+#include <immintrin.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if 0
+#pragma qt_class(QFloat16)
+#pragma qt_no_master_include
+#endif
+
+class qfloat16
+{
+public:
+#ifndef Q_QDOC
+ Q_DECL_CONSTEXPR inline qfloat16() Q_DECL_NOTHROW : b16(0) { }
+ inline qfloat16(float f) Q_DECL_NOTHROW;
+ inline operator float() const Q_DECL_NOTHROW;
+ inline operator double() const Q_DECL_NOTHROW;
+ inline operator long double() const Q_DECL_NOTHROW;
+#endif
+
+private:
+ quint16 b16;
+
+ Q_CORE_EXPORT static const quint32 mantissatable[];
+ Q_CORE_EXPORT static const quint32 exponenttable[];
+ Q_CORE_EXPORT static const quint32 offsettable[];
+ Q_CORE_EXPORT static const quint32 basetable[];
+ Q_CORE_EXPORT static const quint32 shifttable[];
+
+ friend bool qIsNull(qfloat16 f) Q_DECL_NOTHROW;
+ friend qfloat16 operator-(qfloat16 a) Q_DECL_NOTHROW;
+};
+
+Q_DECLARE_TYPEINFO(qfloat16, Q_PRIMITIVE_TYPE);
+
+Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsInf(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
+Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsNaN(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
+Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
+
+// The remainder of these utility functions complement qglobal.h
+inline Q_REQUIRED_RESULT int qRound(qfloat16 d) Q_DECL_NOTHROW
+{ return qRound(static_cast<float>(d)); }
+
+inline Q_REQUIRED_RESULT qint64 qRound64(qfloat16 d) Q_DECL_NOTHROW
+{ return qRound64(static_cast<float>(d)); }
+
+inline Q_REQUIRED_RESULT bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) Q_DECL_NOTHROW
+{
+ float f1 = static_cast<float>(p1);
+ float f2 = static_cast<float>(p2);
+ // The significand precision for IEEE754 half precision is
+ // 11 bits (10 explicitly stored), or approximately 3 decimal
+ // digits. In selecting the fuzzy comparison factor of 102.5f
+ // (that is, (2^10+1)/10) below, we effectively select a
+ // window of about 1 (least significant) decimal digit about
+ // which the two operands can vary and still return true.
+ return (qAbs(f1 - f2) * 102.5f <= qMin(qAbs(f1), qAbs(f2)));
+}
+
+inline Q_REQUIRED_RESULT bool qIsNull(qfloat16 f) Q_DECL_NOTHROW
+{
+ return (f.b16 & static_cast<quint16>(0x7fff)) == 0;
+}
+
+inline int qIntCast(qfloat16 f) Q_DECL_NOTHROW
+{ return int(static_cast<float>(f)); }
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wc99-extensions")
+QT_WARNING_DISABLE_GCC("-Wold-style-cast")
+inline qfloat16::qfloat16(float f) Q_DECL_NOTHROW
+{
+#if defined(QT_COMPILER_SUPPORTS_F16C) && (defined(__F16C__) || defined(__AVX2__))
+ __m128 packsingle = _mm_set_ss(f);
+ __m128i packhalf = _mm_cvtps_ph(packsingle, 0);
+ b16 = _mm_extract_epi16(packhalf, 0);
+#elif defined (__ARM_FP16_FORMAT_IEEE)
+ __fp16 f16 = f;
+ memcpy(&b16, &f16, sizeof(quint16));
+#else
+ quint32 u;
+ memcpy(&u, &f, sizeof(quint32));
+ b16 = basetable[(u >> 23) & 0x1ff]
+ + ((u & 0x007fffff) >> shifttable[(u >> 23) & 0x1ff]);
+#endif
+}
+QT_WARNING_POP
+
+inline qfloat16::operator float() const Q_DECL_NOTHROW
+{
+#if defined(QT_COMPILER_SUPPORTS_F16C) && (defined(__F16C__) || defined(__AVX2__))
+ __m128i packhalf = _mm_cvtsi32_si128(b16);
+ __m128 packsingle = _mm_cvtph_ps(packhalf);
+ return _mm_cvtss_f32(packsingle);
+#elif defined (__ARM_FP16_FORMAT_IEEE)
+ __fp16 f16;
+ memcpy(&f16, &b16, sizeof(quint16));
+ return f16;
+#else
+ quint32 u = mantissatable[offsettable[b16 >> 10] + (b16 & 0x3ff)]
+ + exponenttable[b16 >> 10];
+ float f;
+ memcpy(&f, &u, sizeof(quint32));
+ return f;
+#endif
+}
+
+inline qfloat16::operator double() const Q_DECL_NOTHROW
+{
+ return static_cast<double>(float(*this));
+}
+
+inline qfloat16::operator long double() const Q_DECL_NOTHROW
+{
+ return static_cast<long double>(float(*this));
+}
+
+inline qfloat16 operator-(qfloat16 a) Q_DECL_NOTHROW
+{
+ qfloat16 f;
+ f.b16 = a.b16 ^ quint16(0x8000);
+ return f;
+}
+
+inline qfloat16 operator+(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) + static_cast<float>(b)); }
+inline qfloat16 operator-(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) - static_cast<float>(b)); }
+inline qfloat16 operator*(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) * static_cast<float>(b)); }
+inline qfloat16 operator/(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) / static_cast<float>(b)); }
+
+#define QF16_MAKE_ARITH_OP_FP(FP, OP) \
+ inline FP operator OP(qfloat16 lhs, FP rhs) Q_DECL_NOTHROW { return static_cast<FP>(lhs) OP rhs; } \
+ inline FP operator OP(FP lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<FP>(rhs); }
+#define QF16_MAKE_ARITH_OP_EQ_FP(FP, OP_EQ, OP) \
+ inline qfloat16& operator OP_EQ(qfloat16& lhs, FP rhs) Q_DECL_NOTHROW { lhs = qfloat16(static_cast<FP>(lhs) OP rhs); return lhs; }
+#define QF16_MAKE_ARITH_OP(FP) \
+ QF16_MAKE_ARITH_OP_FP(FP, +) \
+ QF16_MAKE_ARITH_OP_FP(FP, -) \
+ QF16_MAKE_ARITH_OP_FP(FP, *) \
+ QF16_MAKE_ARITH_OP_FP(FP, /) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, +=, +) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, -=, -) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, *=, *) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, /=, /)
+QF16_MAKE_ARITH_OP(long double)
+QF16_MAKE_ARITH_OP(double)
+QF16_MAKE_ARITH_OP(float)
+#undef QF16_MAKE_ARITH_OP
+#undef QF16_MAKE_ARITH_OP_FP
+
+#define QF16_MAKE_ARITH_OP_INT(OP) \
+ inline double operator OP(qfloat16 lhs, int rhs) Q_DECL_NOTHROW { return static_cast<double>(lhs) OP rhs; } \
+ inline double operator OP(int lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<double>(rhs); }
+QF16_MAKE_ARITH_OP_INT(+)
+QF16_MAKE_ARITH_OP_INT(-)
+QF16_MAKE_ARITH_OP_INT(*)
+QF16_MAKE_ARITH_OP_INT(/)
+#undef QF16_MAKE_ARITH_OP_INT
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
+QT_WARNING_DISABLE_GCC("-Wfloat-equal")
+
+inline bool operator>(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) > static_cast<float>(b); }
+inline bool operator<(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) < static_cast<float>(b); }
+inline bool operator>=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) >= static_cast<float>(b); }
+inline bool operator<=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) <= static_cast<float>(b); }
+inline bool operator==(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) == static_cast<float>(b); }
+inline bool operator!=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) != static_cast<float>(b); }
+
+#define QF16_MAKE_BOOL_OP_FP(FP, OP) \
+ inline bool operator OP(qfloat16 lhs, FP rhs) Q_DECL_NOTHROW { return static_cast<FP>(lhs) OP rhs; } \
+ inline bool operator OP(FP lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<FP>(rhs); }
+#define QF16_MAKE_BOOL_OP(FP) \
+ QF16_MAKE_BOOL_OP_FP(FP, <) \
+ QF16_MAKE_BOOL_OP_FP(FP, >) \
+ QF16_MAKE_BOOL_OP_FP(FP, >=) \
+ QF16_MAKE_BOOL_OP_FP(FP, <=) \
+ QF16_MAKE_BOOL_OP_FP(FP, ==) \
+ QF16_MAKE_BOOL_OP_FP(FP, !=)
+QF16_MAKE_BOOL_OP(long double)
+QF16_MAKE_BOOL_OP(double)
+QF16_MAKE_BOOL_OP(float)
+#undef QF16_MAKE_BOOL_OP
+#undef QF16_MAKE_BOOL_OP_FP
+
+#define QF16_MAKE_BOOL_OP_INT(OP) \
+ inline bool operator OP(qfloat16 a, int b) Q_DECL_NOTHROW { return static_cast<float>(a) OP b; } \
+ inline bool operator OP(int a, qfloat16 b) Q_DECL_NOTHROW { return a OP static_cast<float>(b); }
+QF16_MAKE_BOOL_OP_INT(>)
+QF16_MAKE_BOOL_OP_INT(<)
+QF16_MAKE_BOOL_OP_INT(>=)
+QF16_MAKE_BOOL_OP_INT(<=)
+QF16_MAKE_BOOL_OP_INT(==)
+QF16_MAKE_BOOL_OP_INT(!=)
+#undef QF16_MAKE_BOOL_OP_INT
+
+QT_WARNING_POP
+
+/*!
+ \internal
+*/
+inline Q_REQUIRED_RESULT bool qFuzzyIsNull(qfloat16 f) Q_DECL_NOTHROW
+{
+ return qAbs(static_cast<float>(f)) <= 0.001f;
+}
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(qfloat16)
+
+#endif // QFLOAT16_H
diff --git a/src/corelib/global/qfloat16_p.h b/src/corelib/global/qfloat16_p.h
new file mode 100644
index 0000000000..ae52e64435
--- /dev/null
+++ b/src/corelib/global/qfloat16_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 by Southwest Research Institute (R)
+** Contact: http://www.qt-project.org/legal
+**
+** 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 QFLOAT16_P_H
+#define QFLOAT16_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/qfloat16.h>
+#include <QtCore/qsysinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline bool qt_is_inf(qfloat16 d) Q_DECL_NOTHROW
+{
+ bool is_inf;
+ uchar *ch = (uchar *)&d;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ is_inf = (ch[0] & 0x7c) == 0x7c;
+ else
+ is_inf = (ch[1] & 0x7c) == 0x7c;
+ return is_inf;
+}
+
+static inline bool qt_is_nan(qfloat16 d) Q_DECL_NOTHROW
+{
+ bool is_nan;
+ uchar *ch = (uchar *)&d;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ is_nan = (ch[0] & 0x7c) == 0x7c && (ch[0] & 0x02) != 0;
+ else
+ is_nan = (ch[1] & 0x7c) == 0x7c && (ch[1] & 0x02) != 0;
+ return is_nan;
+}
+
+static inline bool qt_is_finite(qfloat16 d) Q_DECL_NOTHROW
+{
+ bool is_finite;
+ uchar *ch = (uchar *)&d;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ is_finite = (ch[0] & 0x7c) != 0x7c;
+ else
+ is_finite = (ch[1] & 0x7c) != 0x7c;
+ return is_finite;
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QFLOAT16_P_H
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 9a779305d2..c37503f3db 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -45,6 +45,8 @@
#include "qthreadstorage.h"
#include "qdir.h"
#include "qdatetime.h"
+#include "qoperatingsystemversion.h"
+#include "qoperatingsystemversion_p.h"
#include <private/qlocale_tools_p.h>
#include <qmutex.h>
@@ -956,7 +958,8 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\snippet code/src_corelib_global_qglobal.cpp 53
- \sa qConstOverload(), qNonConstOverload()
+ \sa qConstOverload(), qNonConstOverload(), {Differences between String-Based
+ and Functor-Based Connections}
*/
/*! \fn auto qConstOverload(T memberFunctionPointer)
@@ -967,7 +970,8 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\snippet code/src_corelib_global_qglobal.cpp 54
- \sa qOverload, qNonConstOverload
+ \sa qOverload, qNonConstOverload, {Differences between String-Based
+ and Functor-Based Connections}
*/
/*! \fn auto qNonConstOverload(T memberFunctionPointer)
@@ -978,7 +982,8 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\snippet code/src_corelib_global_qglobal.cpp 54
- \sa qOverload, qNonConstOverload
+ \sa qOverload, qNonConstOverload, {Differences between String-Based
+ and Functor-Based Connections}
*/
/*!
@@ -1064,10 +1069,6 @@ bool qSharedBuild() Q_DECL_NOTHROW
on which the application is compiled.
\li \l ByteOrder specifies whether the platform is big-endian or
little-endian.
- \li \l WindowsVersion specifies the version of the Windows operating
- system on which the application is run.
- \li \l MacintoshVersion specifies the version of the Macintosh
- operating system on which the application is run.
\endlist
Some constants are defined only on certain platforms. You can use
@@ -1088,12 +1089,14 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\variable QSysInfo::WindowsVersion
\brief the version of the Windows operating system on which the
application is run.
*/
/*!
+ \deprecated
\fn QSysInfo::WindowsVersion QSysInfo::windowsVersion()
\since 4.4
@@ -1103,12 +1106,14 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\variable QSysInfo::MacintoshVersion
\brief the version of the Macintosh operating system on which
the application is run.
*/
/*!
+ \deprecated
\fn QSysInfo::MacVersion QSysInfo::macVersion()
Returns the version of Darwin (\macos or iOS) on which the
@@ -1126,6 +1131,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\enum QSysInfo::WinVersion
This enum provides symbolic names for the various versions of the
@@ -1182,6 +1188,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\enum QSysInfo::MacVersion
This enum provides symbolic names for the various versions of the
@@ -1335,13 +1342,6 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
- \macro Q_OS_WINPHONE
- \relates <QtGlobal>
-
- Defined on Windows Phone 8.
-*/
-
-/*!
\macro Q_OS_CYGWIN
\relates <QtGlobal>
@@ -1941,6 +1941,19 @@ bool qSharedBuild() Q_DECL_NOTHROW
disable functions deprecated in Qt 5.1 and earlier. In any release, set
QT_DISABLE_DEPRECATED_BEFORE=0x000000 to enable any functions, including the ones
deprecated in Qt 5.0
+
+ \sa QT_DEPRECATED_WARNINGS
+ */
+
+
+/*!
+ \macro QT_DEPRECATED_WARNINGS
+ \relates <QtGlobal>
+
+ If this macro is defined, the compiler will generate warnings if API declared as
+ deprecated by Qt is used.
+
+ \sa QT_DISABLE_DEPRECATED_BEFORE
*/
#if defined(QT_BUILD_QMAKE)
@@ -1956,28 +1969,34 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include "qnamespace.h"
QT_END_INCLUDE_NAMESPACE
+#if QT_DEPRECATED_SINCE(5, 9)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QSysInfo::MacVersion QSysInfo::macVersion()
{
- const QAppleOperatingSystemVersion version = qt_apple_os_version(); // qtcore_mac_objc.mm
+ const auto version = QOperatingSystemVersion::current();
#if defined(Q_OS_OSX)
- return QSysInfo::MacVersion(Q_MV_OSX(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_OSX(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_IOS)
- return QSysInfo::MacVersion(Q_MV_IOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_IOS(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_TVOS)
- return QSysInfo::MacVersion(Q_MV_TVOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_TVOS(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_WATCHOS)
- return QSysInfo::MacVersion(Q_MV_WATCHOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_WATCHOS(version.majorVersion(), version.minorVersion()));
#else
return QSysInfo::MV_Unknown;
#endif
}
const QSysInfo::MacVersion QSysInfo::MacintoshVersion = QSysInfo::macVersion();
+QT_WARNING_POP
+#endif
-#ifdef Q_OS_OSX
-static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple_os_version())
+#ifdef Q_OS_DARWIN
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
{
- if (version.major == 10) {
- switch (version.minor) {
+#ifdef Q_OS_MACOS
+ if (version.majorVersion() == 10) {
+ switch (version.minorVersion()) {
case 9:
return "Mavericks";
case 10:
@@ -1989,6 +2008,9 @@ static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple
}
}
// unknown, future version
+#else
+ Q_UNUSED(version);
+#endif
return 0;
}
#endif
@@ -2029,140 +2051,33 @@ QWindowsSockInit::~QWindowsSockInit()
Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
# endif // QT_BOOTSTRAPPED
-#ifdef Q_OS_WINRT
-static inline HMODULE moduleHandleForFunction(LPCVOID address)
-{
- // This is a widely used, decades-old technique for retrieving the handle
- // of a module and is effectively equivalent to GetModuleHandleEx
- // (which is unavailable on WinRT)
- MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 };
- if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0)
- return 0;
- return reinterpret_cast<HMODULE>(mbi.AllocationBase);
-}
-#endif
-
-static inline OSVERSIONINFOEX determineWinOsVersion()
-{
- OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0};
-
-#define GetProcAddressA GetProcAddress
-
- // GetModuleHandle is not supported in WinRT and linking to it at load time
- // will not pass the Windows App Certification Kit... but it exists and is functional,
- // so use some unusual but widely used techniques to get a pointer to it
-#ifdef Q_OS_WINRT
- // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL
- HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery));
- if (Q_UNLIKELY(!kernelModule))
- return result;
-
- // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs)
- typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR);
- GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>(
- GetProcAddressA(kernelModule, "GetModuleHandleW"));
- if (Q_UNLIKELY(!pGetModuleHandle))
- return result;
-#else
-#define pGetModuleHandle GetModuleHandleW
-#endif
-
-#ifndef Q_OS_WINCE
- HMODULE ntdll = pGetModuleHandle(L"ntdll.dll");
- if (Q_UNLIKELY(!ntdll))
- return result;
-
- // NTSTATUS is not defined on WinRT
- typedef LONG NTSTATUS;
- typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
-
- // RtlGetVersion is documented public API but we must load it dynamically
- // because linking to it at load time will not pass the Windows App Certification Kit
- // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
- RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
- GetProcAddressA(ntdll, "RtlGetVersion"));
- if (Q_UNLIKELY(!pRtlGetVersion))
- return result;
-
- // GetVersionEx() has been deprecated in Windows 8.1 and will return
- // only Windows 8 from that version on, so use the kernel API function.
- pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS
-#else // !Q_OS_WINCE
- GetVersionEx(&result);
-#endif
- return result;
-}
-
-static OSVERSIONINFOEX winOsVersion()
-{
- OSVERSIONINFOEX realResult = determineWinOsVersion();
-#ifdef QT_DEBUG
- {
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) {
- OSVERSIONINFOEX result = realResult;
- result.dwMajorVersion = 0;
- result.dwMinorVersion = 0;
-
- // Erase any build number and service pack information
- result.dwBuildNumber = 0;
- result.szCSDVersion[0] = L'\0';
- result.wServicePackMajor = 0;
- result.wServicePackMinor = 0;
-
- const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE");
- if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 1;
- } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 2;
- } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 3;
- } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") {
- result.dwMajorVersion = 10;
- } else {
- return realResult;
- }
-
- if (winVerOverride == "2008_R2"
- || winVerOverride == "2012"
- || winVerOverride == "2012_R2"
- || winVerOverride == "2016") {
- // If the current host OS is a domain controller and the override OS
- // is also a server type OS, preserve that information
- if (result.wProductType == VER_NT_WORKSTATION)
- result.wProductType = VER_NT_SERVER;
- } else {
- // Any other OS must be a workstation OS type
- result.wProductType = VER_NT_WORKSTATION;
- }
- }
- }
-#endif
- return realResult;
-}
-
+#if QT_DEPRECATED_SINCE(5, 9)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QSysInfo::WinVersion QSysInfo::windowsVersion()
{
- const OSVERSIONINFOEX osver = winOsVersion();
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1)
+ const auto version = QOperatingSystemVersion::current();
+ if (version.majorVersion() == 6 && version.minorVersion() == 1)
return QSysInfo::WV_WINDOWS7;
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
+ if (version.majorVersion() == 6 && version.minorVersion() == 2)
return QSysInfo::WV_WINDOWS8;
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3)
+ if (version.majorVersion() == 6 && version.minorVersion() == 3)
return QSysInfo::WV_WINDOWS8_1;
- if (osver.dwMajorVersion == 10 && osver.dwMinorVersion == 0)
+ if (version.majorVersion() == 10 && version.minorVersion() == 0)
return QSysInfo::WV_WINDOWS10;
return QSysInfo::WV_NT_based;
}
+const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion();
+QT_WARNING_POP
+#endif
static QString winSp_helper()
{
- const qint16 major = winOsVersion().wServicePackMajor;
+ const auto osv = qWindowsVersionInfo();
+ const qint16 major = osv.wServicePackMajor;
if (major) {
QString sp = QStringLiteral(" SP ") + QString::number(major);
- const qint16 minor = winOsVersion().wServicePackMinor;
+ const qint16 minor = osv.wServicePackMinor;
if (minor)
sp += QLatin1Char('.') + QString::number(minor);
@@ -2171,9 +2086,10 @@ static QString winSp_helper()
return QString();
}
-static const char *winVer_helper()
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
{
- const OSVERSIONINFOEX osver = winOsVersion();
+ Q_UNUSED(version);
+ const OSVERSIONINFOEX osver = qWindowsVersionInfo();
const bool workstation = osver.wProductType == VER_NT_WORKSTATION;
#define Q_WINVER(major, minor) (major << 8 | minor)
@@ -2192,8 +2108,6 @@ static const char *winVer_helper()
return 0;
}
-const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion();
-
#endif
#if defined(Q_OS_UNIX)
# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
@@ -2374,6 +2288,68 @@ static bool findUnixOsVersion(QUnixOSVersion &v)
# endif // USE_ETC_OS_RELEASE
#endif // Q_OS_UNIX
+#ifdef Q_OS_ANDROID
+static const char *osVer_helper(QOperatingSystemVersion)
+{
+/* Data:
+
+
+
+Cupcake
+Donut
+Eclair
+Eclair
+Eclair
+Froyo
+Gingerbread
+Gingerbread
+Honeycomb
+Honeycomb
+Honeycomb
+Ice Cream Sandwich
+Ice Cream Sandwich
+Jelly Bean
+Jelly Bean
+Jelly Bean
+KitKat
+KitKat
+Lollipop
+Lollipop
+Marshmallow
+Nougat
+Nougat
+ */
+ static const char versions_string[] =
+ "\0"
+ "Cupcake\0"
+ "Donut\0"
+ "Eclair\0"
+ "Froyo\0"
+ "Gingerbread\0"
+ "Honeycomb\0"
+ "Ice Cream Sandwich\0"
+ "Jelly Bean\0"
+ "KitKat\0"
+ "Lollipop\0"
+ "Marshmallow\0"
+ "Nougat\0"
+ "\0";
+
+ static const int versions_indices[] = {
+ 0, 0, 0, 1, 9, 15, 15, 15,
+ 22, 28, 28, 40, 40, 40, 50, 50,
+ 69, 69, 69, 80, 80, 87, 87, 96,
+ 108, 108, -1
+ };
+
+ static const int versions_count = (sizeof versions_indices) / (sizeof versions_indices[0]);
+
+ // https://source.android.com/source/build-numbers.html
+ // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
+ const int sdk_int = QJNIObjectPrivate::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT");
+ return &versions_string[versions_indices[qBound(0, sdk_int, versions_count - 1)]];
+}
+#endif
/*!
\since 5.4
@@ -2622,9 +2598,9 @@ QString QSysInfo::kernelType()
QString QSysInfo::kernelVersion()
{
#ifdef Q_OS_WIN
- const OSVERSIONINFOEX osver = winOsVersion();
- return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion))
- + QLatin1Char('.') + QString::number(int(osver.dwBuildNumber));
+ const auto osver = QOperatingSystemVersion::current();
+ return QString::number(osver.majorVersion()) + QLatin1Char('.') + QString::number(osver.minorVersion())
+ + QLatin1Char('.') + QString::number(osver.microVersion());
#else
struct utsname u;
if (uname(&u) == 0)
@@ -2664,8 +2640,8 @@ QString QSysInfo::kernelVersion()
\b{FreeBSD note}: this function returns "debian" for Debian/kFreeBSD and
"unknown" otherwise.
- \b{Windows note}: this function returns "winphone" for builds for Windows
- Phone, "winrt" for WinRT builds, and "windows" for normal desktop builds.
+ \b{Windows note}: this function "winrt" for WinRT builds, and "windows"
+ for normal desktop builds.
For other Unix-type systems, this function usually returns "unknown".
@@ -2674,9 +2650,7 @@ QString QSysInfo::kernelVersion()
QString QSysInfo::productType()
{
// similar, but not identical to QFileSelectorPrivate::platformSelectors
-#if defined(Q_OS_WINPHONE)
- return QStringLiteral("winphone");
-#elif defined(Q_OS_WINRT)
+#if defined(Q_OS_WINRT)
return QStringLiteral("winrt");
#elif defined(Q_OS_WIN)
return QStringLiteral("windows");
@@ -2719,8 +2693,23 @@ QString QSysInfo::productType()
version could not be determined, this function returns "unknown".
It will return the Android, iOS, \macos, Windows full-product
- versions on those systems. In particular, on OS X, iOS and Windows, the
- returned string is similar to the macVersion() or windowsVersion() enums.
+ versions on those systems.
+
+ Typical returned values are (note: list not exhaustive):
+ \list
+ \li "2016.09" (Amazon Linux AMI 2016.09)
+ \li "7.1" (Android Nougat)
+ \li "25" (Fedora 25)
+ \li "10.1" (iOS 10.1)
+ \li "10.12" (macOS Sierra)
+ \li "10.0" (tvOS 10)
+ \li "16.10" (Ubuntu 16.10)
+ \li "3.1" (watchOS 3.1)
+ \li "7 SP 1" (Windows 7 Service Pack 1)
+ \li "8.1" (Windows 8.1)
+ \li "10" (Windows 10)
+ \li "Server 2016" (Windows Server 2016)
+ \endlist
On Linux systems, it will try to determine the distribution version and will
return that. This is also done on Debian/kFreeBSD, so this function will
@@ -2737,20 +2726,17 @@ QString QSysInfo::productType()
*/
QString QSysInfo::productVersion()
{
-#if defined(Q_OS_MAC)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- return QString::number(version.major) + QLatin1Char('.') + QString::number(version.minor);
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+ const auto version = QOperatingSystemVersion::current();
+ return QString::number(version.majorVersion()) + QLatin1Char('.') + QString::number(version.minorVersion());
#elif defined(Q_OS_WIN)
- const char *version = winVer_helper();
+ const char *version = osVer_helper();
if (version) {
const QLatin1Char spaceChar(' ');
return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
}
// fall through
-// Android should not fall through to the Unix code
-#elif defined(Q_OS_ANDROID)
- return QJNIObjectPrivate::getStaticObjectField("android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString();
#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
QUnixOSVersion unixOsVersion;
findUnixOsVersion(unixOsVersion);
@@ -2778,44 +2764,21 @@ QString QSysInfo::productVersion()
*/
QString QSysInfo::prettyProductName()
{
-#if defined(Q_OS_IOS)
- return QLatin1String("iOS ") + productVersion();
-#elif defined(Q_OS_TVOS)
- return QLatin1String("tvOS ") + productVersion();
-#elif defined(Q_OS_WATCHOS)
- return QLatin1String("watchOS ") + productVersion();
-#elif defined(Q_OS_MACOS)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- const char *name = osxVer_helper(version);
- if (name) {
- return (version.major == 10 && version.minor < 12
- ? QLatin1String("OS X ")
- : QLatin1String("macOS "))
- + QLatin1String(name)
- + QLatin1String(" (") + QString::number(version.major)
- + QLatin1Char('.') + QString::number(version.minor)
- + QLatin1Char(')');
- } else {
- return QLatin1String("macOS ")
- + QString::number(version.major) + QLatin1Char('.')
- + QString::number(version.minor);
- }
-#elif defined(Q_OS_WINPHONE)
- return QLatin1String("Windows Phone ") + QLatin1String(winVer_helper());
-#elif defined(Q_OS_WIN)
- const char *name = winVer_helper();
- const OSVERSIONINFOEX osver = winOsVersion();
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
+ const auto version = QOperatingSystemVersion::current();
+ const char *name = osVer_helper(version);
if (name)
- return QLatin1String("Windows ") + QLatin1String(name) + winSp_helper()
- + QLatin1String(" (") + QString::number(osver.dwMajorVersion)
- + QLatin1Char('.') + QString::number(osver.dwMinorVersion)
+ return version.name() + QLatin1Char(' ') + QLatin1String(name)
+# if defined(Q_OS_WIN)
+ + winSp_helper()
+# endif
+ + QLatin1String(" (") + QString::number(version.majorVersion())
+ + QLatin1Char('.') + QString::number(version.minorVersion())
+ QLatin1Char(')');
- else
- return QLatin1String("Windows ")
- + QString::number(osver.dwMajorVersion) + QLatin1Char('.')
- + QString::number(osver.dwMinorVersion);
-#elif defined(Q_OS_ANDROID)
- return QLatin1String("Android ") + productVersion();
+ else
+ return version.name() + QLatin1Char(' ')
+ + QString::number(version.majorVersion()) + QLatin1Char('.')
+ + QString::number(version.minorVersion());
#elif defined(Q_OS_HAIKU)
return QLatin1String("Haiku ") + productVersion();
#elif defined(Q_OS_UNIX)
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index b4245ac8f6..9ac29acd16 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -44,6 +44,7 @@
#ifdef __cplusplus
# include <type_traits>
# include <cstddef>
+# include <utility>
#endif
#include <stddef.h>
@@ -915,19 +916,57 @@ 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; }
+// prevent rvalue arguments:
+template <typename T>
+void qAsConst(const T &&) Q_DECL_EQ_DELETE;
+
#ifndef QT_NO_FOREACH
+namespace QtPrivate {
+
template <typename T>
class QForeachContainer {
- QForeachContainer &operator=(const QForeachContainer &) Q_DECL_EQ_DELETE;
+ Q_DISABLE_COPY(QForeachContainer)
public:
- QForeachContainer(const T &t) : c(t), i(c.begin()), e(c.end()) {}
- QForeachContainer(T &&t) : c(std::move(t)), i(c.begin()), e(c.end()) {}
- const T c;
+ QForeachContainer(const T &t) : c(t), i(qAsConst(c).begin()), e(qAsConst(c).end()) {}
+ QForeachContainer(T &&t) : c(std::move(t)), i(qAsConst(c).begin()), e(qAsConst(c).end()) {}
+
+ QForeachContainer(QForeachContainer &&other)
+ : c(std::move(other.c)),
+ i(qAsConst(c).begin()),
+ e(qAsConst(c).end()),
+ control(std::move(other.control))
+ {
+ }
+
+ QForeachContainer &operator=(QForeachContainer &&other)
+ {
+ c = std::move(other.c);
+ i = qAsConst(c).begin();
+ e = qAsConst(c).end();
+ control = std::move(other.control);
+ return *this;
+ }
+
+ T c;
typename T::const_iterator i, e;
int control = 1;
};
+template<typename T>
+QForeachContainer<typename std::decay<T>::type> qMakeForeachContainer(T &&t)
+{
+ return QForeachContainer<typename std::decay<T>::type>(std::forward<T>(t));
+}
+
+}
// Explanation of the control word:
// - it's initialized to 1
// - that means both the inner and outer loops start
@@ -938,7 +977,7 @@ public:
// - if there was a break inside the inner loop, it will exit with control still
// set to 1; in that case, the outer loop will invert it to 0 and will exit too
#define Q_FOREACH(variable, container) \
-for (QForeachContainer<typename std::remove_reference<decltype(container)>::type> _container_((container)); \
+for (auto _container_ = QtPrivate::qMakeForeachContainer(container); \
_container_.control && _container_.i != _container_.e; \
++_container_.i, _container_.control ^= 1) \
for (variable = *_container_.i; _container_.control; _container_.control = 0)
@@ -966,8 +1005,8 @@ template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelpe
friend class Class##Private;
#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
- inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); } \
- inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(Dptr); } \
+ inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr)); } \
+ inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr)); } \
friend class Class##Private;
#define Q_DECLARE_PUBLIC(Class) \
@@ -1105,17 +1144,8 @@ template <typename T> struct QEnableIf<true, T> { typedef T Type; };
template <bool B, typename T, typename F> struct QConditional { typedef T Type; };
template <typename T, typename F> struct QConditional<false, T, F> { typedef F Type; };
-
-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; }
-// prevent rvalue arguments:
-template <typename T>
-void qAsConst(const T &&) Q_DECL_EQ_DELETE;
-
QT_END_NAMESPACE
// We need to keep QTypeInfo, QSysInfo, QFlags, qDebug & family in qglobal.h for compatibility with Qt 4.
diff --git a/src/corelib/global/qglobal_p.h b/src/corelib/global/qglobal_p.h
index b8f9e5fbf7..b1d2836783 100644
--- a/src/corelib/global/qglobal_p.h
+++ b/src/corelib/global/qglobal_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $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 http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** 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 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** 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.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** 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$
**
diff --git a/src/corelib/global/qhooks.cpp b/src/corelib/global/qhooks.cpp
index 7b9a3db30d..bbddb1cbf1 100644
--- a/src/corelib/global/qhooks.cpp
+++ b/src/corelib/global/qhooks.cpp
@@ -67,7 +67,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = {
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
// When this fails and the change was intentional, adjust the test and
// adjust this value here.
- 15
+ 16
};
Q_STATIC_ASSERT(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 03ee0730db..b4ba0b5b2e 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -663,6 +663,8 @@ QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
+ QLatin1String("Arguments");
return settings->value(key).toStringList();
}
+#else
+ Q_UNUSED(platformName);
#endif // !QT_BUILD_QMAKE && !QT_NO_SETTINGS
return QStringList();
}
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 6b90a47388..e525869733 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -197,7 +197,7 @@ static bool willLogToConsole()
# elif defined(Q_OS_UNIX)
// if /dev/tty exists, we can only open it if we have a controlling TTY
int devtty = qt_safe_open("/dev/tty", O_RDONLY);
- if (devtty == -1 && (errno == ENOENT || errno == EPERM)) {
+ if (devtty == -1 && (errno == ENOENT || errno == EPERM || errno == ENXIO)) {
// no /dev/tty, fall back to isatty on stderr
return isatty(STDERR_FILENO);
} else if (devtty != -1) {
@@ -1445,12 +1445,14 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
now.start();
uint ms = now.msecsSinceReference();
message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
+#if QT_CONFIG(datestring)
} else if (timeFormat.isEmpty()) {
message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
} else {
message.append(QDateTime::currentDateTime().toString(timeFormat));
+#endif // QT_CONFIG(datestring)
}
-#endif
+#endif // !QT_BOOTSTRAPPED
} else if (token == ifCategoryTokenC) {
if (!context.category || (strcmp(context.category, "default") == 0))
skip = true;
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index a30344995e..da44c01594 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -472,6 +472,8 @@ public:
WA_AlwaysStackOnTop = 128,
+ WA_TabletTracking = 129,
+
// Add new attributes before this line
WA_AttributeCount
};
@@ -505,6 +507,7 @@ public:
AA_SynthesizeMouseForUnhandledTabletEvents = 24,
AA_CompressHighFrequencyEvents = 25,
AA_DontCheckOpenGLContextThreadAffinity = 26,
+ AA_DisableShaderDiskCache = 27,
// Add new attributes before this line
AA_AttributeCount
@@ -1655,6 +1658,11 @@ public:
};
Q_DECLARE_FLAGS(MouseEventFlags, MouseEventFlag)
+ enum ChecksumType {
+ ChecksumIso3309,
+ ChecksumItuV41
+ };
+
#ifndef Q_QDOC
// NOTE: Generally, do not add QT_Q_ENUM if a corresponding Q_Q_FLAG exists.
QT_Q_ENUM(ScrollBarPolicy)
@@ -1739,6 +1747,7 @@ public:
QT_Q_ENUM(ScrollPhase)
QT_Q_ENUM(MouseEventSource)
QT_Q_FLAG(MouseEventFlag)
+ QT_Q_ENUM(ChecksumType)
QT_Q_ENUM(TabFocusBehavior)
#endif // Q_DOC
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 59fa0b519c..404bbfe65a 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -254,6 +254,15 @@
\l{QOpenGLContext::makeCurrent}{makeCurrent()}. This value has been
added in Qt 5.8.
+ \value AA_DisableShaderDiskCache Disables caching of shader program binaries
+ on disk. By default Qt Quick, QPainter's OpenGL backend, and any
+ application using QOpenGLShaderProgram with one of its
+ \e addCacheableShaderFromSource overloads will employ a disk-based
+ \l{Caching Program Binaries}{program binary cache} in either the shared
+ or per-process cache storage location, on systems that support
+ \e glProgramBinary(). In the unlikely event of this being problematic,
+ set this attribute to disable all disk-based caching of shaders.
+
The following values are obsolete:
\value AA_ImmediateWidgetCreation This attribute is no longer fully
@@ -1130,6 +1139,9 @@
\value WA_StyleSheet Indicates that the widget is styled using a
\l{Qt Style Sheets}{style sheet}.
+ \value WA_TabletTracking Indicates that the widget has tablet
+ tracking enabled. See QWidget::tabletTracking.
+
\value WA_TranslucentBackground Indicates that the widget should have a
translucent background, i.e., any non-opaque regions of the widgets will be
translucent because the widget will have an alpha channel. Setting this
@@ -3146,3 +3158,14 @@
\omitvalue MouseEventFlagMask
*/
+
+/*!
+ \enum Qt::ChecksumType
+ \since 5.9
+
+ This enum describes the possible standards used by qChecksum().
+
+ \value ChecksumIso3309 Checksum calculation based on ISO 3309.
+
+ \value ChecksumItuV41 Checksum calculation based on ITU-V.41.
+*/
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 06658b422d..2291675501 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -167,7 +167,7 @@ static inline bool qt_is_finite(float f)
// Unsigned overflow math
//
namespace {
-template <typename T> inline typename QtPrivate::QEnableIf<std::is_unsigned<T>::value, bool>::Type
+template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
add_overflow(T v1, T v2, T *r)
{
// unsigned additions are well-defined
@@ -175,7 +175,7 @@ add_overflow(T v1, T v2, T *r)
return v1 > T(v1 + v2);
}
-template <typename T> inline typename QtPrivate::QEnableIf<std::is_unsigned<T>::value, bool>::Type
+template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
mul_overflow(T v1, T v2, T *r)
{
// use the next biggest type
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
new file mode 100644
index 0000000000..bed08f0000
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -0,0 +1,491 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion.h"
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
+#include "qoperatingsystemversion_p.h"
+#endif
+
+#include <qversionnumber.h>
+
+#if defined(Q_OS_ANDROID)
+#include <private/qjni_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOperatingSystemVersion
+ \inmodule QtCore
+ \since 5.9
+ \brief The QOperatingSystemVersion class provides information about the
+ operating system version.
+
+ Unlike other version functions in QSysInfo, QOperatingSystemVersion provides
+ access to the full version number that \a developers typically use to vary
+ behavior or determine whether to enable APIs or features based on the
+ operating system version (as opposed to the kernel version number or
+ marketing version).
+
+ This class is also a complete replacement for QSysInfo::macVersion and
+ QSysInfo::windowsVersion, additionally providing access to the third (micro)
+ version number component.
+
+ Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS),
+ and Windows are supported.
+
+ The \a majorVersion(), \a minorVersion(), and \a microVersion() functions
+ return the parts of the operating system version number based on:
+
+ \table
+ \header
+ \li Platforms
+ \li Value
+ \row
+ \li Android
+ \li result of parsing
+ \l{https://developer.android.com/reference/android/os/Build.VERSION.html#RELEASE}{android.os.Build.VERSION.RELEASE}
+ using QVersionNumber, with a fallback to
+ \l{https://developer.android.com/reference/android/os/Build.VERSION.html#SDK_INT}{android.os.Build.VERSION.SDK_INT}
+ to determine the major and minor version component if the former
+ fails
+ \row
+ \li Apple Platforms
+ \li majorVersion, minorVersion, and patchVersion from
+ \l{https://developer.apple.com/reference/foundation/nsprocessinfo/1410906-operatingsystemversion?language=objc}{NSProcessInfo.operatingSystemVersion}
+ \row
+ \li Windows
+ \li dwMajorVersion, dwMinorVersion, and dwBuildNumber from
+ \l{https://msdn.microsoft.com/en-us/library/mt723418.aspx}{RtlGetVersion} -
+ note that this function ALWAYS return the version number of the
+ underlying operating system, as opposed to the shim underneath
+ GetVersionEx that hides the real version number if the
+ application is not manifested for that version of the OS
+ \endtable
+
+ Because QOperatingSystemVersion stores both a version number and an OS type, the OS type
+ can be taken into account when performing comparisons. For example, on a macOS system running
+ macOS Sierra (v10.12), the following expression will return \c false even though the
+ major version number component of the object on the left hand side of the expression (10) is
+ greater than that of the object on the right (9):
+
+ \code
+ QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)
+ \endcode
+
+ This allows expressions for multiple operating systems to be joined with a logical OR operator
+ and still work as expected. For example:
+
+ \code
+ auto current = QOperatingSystemVersion::current();
+ if (current >= QOperatingSystemVersion::OSXYosemite ||
+ current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) {
+ // returns true on macOS >= 10.10 and iOS >= 8.0, but false on macOS < 10.10 and iOS < 8.0
+ }
+ \endcode
+
+ A more naive comparison algorithm might incorrectly return true on all versions of macOS,
+ including Mac OS 9. This behavior is achieved by overloading the comparison operators to return
+ \c false whenever the OS types of the QOperatingSystemVersion instances being compared do not
+ match. Be aware that due to this it can be the case \c x >= y and \c x < y are BOTH \c false
+ for the same instances of \c x and \c y.
+*/
+
+/*!
+ \enum QOperatingSystemVersion::OSType
+
+ This enum provides symbolic names for the various operating
+ system families supported by QOperatingSystemVersion.
+
+ \value Android The Google Android operating system.
+ \value IOS The Apple iOS operating system.
+ \value MacOS The Apple macOS operating system.
+ \value TvOS The Apple tvOS operating system.
+ \value WatchOS The Apple watchOS operating system.
+ \value Windows The Microsoft Windows operating system.
+
+ \value Unknown An unknown or unsupported operating system.
+*/
+
+/*!
+ \fn QOperatingSystemVersion::QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1)
+
+ Constructs a QOperatingSystemVersion consisting of the OS type \a osType, and
+ major, minor, and micro version numbers \a vmajor, \a vminor and \a vmicro, respectively.
+*/
+
+/*!
+ \fn QOperatingSystemVersion QOperatingSystemVersion::current()
+
+ Returns a QOperatingSystemVersion indicating the current OS and its version number.
+*/
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ QOperatingSystemVersion version;
+ version.m_os = currentType();
+#if defined(Q_OS_ANDROID)
+#ifndef QT_BOOTSTRAPPED
+ const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField(
+ "android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString());
+ if (!v.isNull()) {
+ version.m_major = v.majorVersion();
+ version.m_minor = v.minorVersion();
+ version.m_micro = v.microVersion();
+ return version;
+ }
+#endif
+
+ version.m_major = -1;
+ version.m_minor = -1;
+
+ static const int versions[][2] = {
+ { 1, 0 }, // API level 1
+ { 1, 1 }, // API level 2
+ { 1, 5 }, // API level 3
+ { 1, 6 }, // API level 4
+ { 2, 0 }, // API level 5
+ { 2, 0 }, // API level 6
+ { 2, 1 }, // API level 7
+ { 2, 2 }, // API level 8
+ { 2, 3 }, // API level 9
+ { 2, 3 }, // API level 10
+ { 3, 0 }, // API level 11
+ { 3, 1 }, // API level 12
+ { 3, 2 }, // API level 13
+ { 4, 0 }, // API level 14
+ { 4, 0 }, // API level 15
+ { 4, 1 }, // API level 16
+ { 4, 2 }, // API level 17
+ { 4, 3 }, // API level 18
+ { 4, 4 }, // API level 19
+ { 4, 4 }, // API level 20
+ { 5, 0 }, // API level 21
+ { 5, 1 }, // API level 22
+ { 6, 0 }, // API level 23
+ { 7, 0 }, // API level 24
+ { 7, 1 }, // API level 25
+ };
+
+ // This will give us at least the first 2 version components
+ const size_t versionIdx = size_t(QJNIObjectPrivate::getStaticField<jint>(
+ "android/os/Build$VERSION", "SDK_INT")) - 1;
+ if (versionIdx < sizeof(versions) / sizeof(versions[0])) {
+ version.m_major = versions[versionIdx][0];
+ version.m_minor = versions[versionIdx][1];
+ }
+
+ // API level 6 was exactly version 2.0.1
+ version.m_micro = versionIdx == 5 ? 1 : -1;
+#else
+ version.m_major = -1;
+ version.m_minor = -1;
+ version.m_micro = -1;
+#endif
+ return version;
+}
+#endif
+
+static inline int compareVersionComponents(int lhs, int rhs)
+{
+ return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0;
+}
+
+int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1,
+ const QOperatingSystemVersion &v2)
+{
+ if (v1.m_major == v2.m_major) {
+ if (v1.m_minor == v2.m_minor) {
+ return compareVersionComponents(v1.m_micro, v2.m_micro);
+ }
+ return compareVersionComponents(v1.m_minor, v2.m_minor);
+ }
+ return compareVersionComponents(v1.m_major, v2.m_major);
+}
+
+/*!
+ \fn int QOperatingSystemVersion::majorVersion() const
+
+ Returns the major version number, that is, the first segment of the
+ operating system's version number.
+
+ See the main class documentation for what the major version number is on a given
+ operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa minorVersion(), microVersion()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::minorVersion() const
+
+ Returns the minor version number, that is, the second segment of the
+ operating system's version number.
+
+ See the main class documentation for what the minor version number is on a given
+ operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa majorVersion(), microVersion()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::microVersion() const
+
+ Returns the micro version number, that is, the third segment of the
+ operating system's version number.
+
+ See the main class documentation for what the micro version number is on a given
+ operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa majorVersion(), minorVersion()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::segmentCount() const
+
+ Returns the number of integers stored in the version number.
+*/
+
+/*!
+ \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::type() const
+
+ Returns the OS type identified by the QOperatingSystemVersion.
+
+ \sa name()
+*/
+
+/*!
+ \fn QString QOperatingSystemVersion::name() const
+
+ Returns a string representation of the OS type identified by the QOperatingSystemVersion.
+
+ \sa type()
+*/
+QString QOperatingSystemVersion::name() const
+{
+ switch (type()) {
+ case QOperatingSystemVersion::Windows:
+ return QStringLiteral("Windows");
+ case QOperatingSystemVersion::MacOS: {
+ if (majorVersion() < 10)
+ return QStringLiteral("Mac OS");
+ if (majorVersion() == 10 && minorVersion() < 8)
+ return QStringLiteral("Mac OS X");
+ if (majorVersion() == 10 && minorVersion() < 12)
+ return QStringLiteral("OS X");
+ return QStringLiteral("macOS");
+ }
+ case QOperatingSystemVersion::IOS: {
+ if (majorVersion() < 4)
+ return QStringLiteral("iPhone OS");
+ return QStringLiteral("iOS");
+ }
+ case QOperatingSystemVersion::TvOS:
+ return QStringLiteral("tvOS");
+ case QOperatingSystemVersion::WatchOS:
+ return QStringLiteral("watchOS");
+ case QOperatingSystemVersion::Android:
+ return QStringLiteral("Android");
+ case QOperatingSystemVersion::Unknown:
+ default:
+ return QString();
+ }
+}
+
+/*!
+ \fn bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
+
+ Returns whether the OS type identified by the QOperatingSystemVersion
+ matches any of the OS types in \a types.
+*/
+bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
+{
+ for (const auto &t : qAsConst(types)) {
+ if (type() == t)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \variable QOperatingSystemVersion::Windows7
+ \brief a version corresponding to Windows 7 (version 6.1).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows7 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 1);
+
+/*!
+ \variable QOperatingSystemVersion::Windows8
+ \brief a version corresponding to Windows 8 (version 6.2).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows8 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 2);
+
+/*!
+ \variable QOperatingSystemVersion::Windows8_1
+ \brief a version corresponding to Windows 8.1 (version 6.3).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows8_1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 3);
+
+/*!
+ \variable QOperatingSystemVersion::Windows10
+ \brief a version corresponding to Windows 10 (version 10.0).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10);
+
+/*!
+ \variable QOperatingSystemVersion::OSXMavericks
+ \brief a version corresponding to OS X Mavericks (version 10.9).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXMavericks =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 9);
+
+/*!
+ \variable QOperatingSystemVersion::OSXYosemite
+ \brief a version corresponding to OS X Yosemite (version 10.10).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXYosemite =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10);
+
+/*!
+ \variable QOperatingSystemVersion::OSXElCapitan
+ \brief a version corresponding to OS X El Capitan (version 10.11).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXElCapitan =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 11);
+
+/*!
+ \variable QOperatingSystemVersion::MacOSSierra
+ \brief a version corresponding to macOS Sierra (version 10.12).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 12);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean
+ \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 1);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean_MR1
+ \brief a version corresponding to Android Jelly Bean, maintenance release 1
+ (version 4.2, API level 17).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 2);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean_MR2
+ \brief a version corresponding to Android Jelly Bean, maintenance release 2
+ (version 4.3, API level 18).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR2 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 3);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidKitKat
+ \brief a version corresponding to Android KitKat (versions 4.4 & 4.4W, API levels 19 & 20).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidKitKat =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 4);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidLollipop
+ \brief a version corresponding to Android Lollipop (version 5.0, API level 21).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidLollipop_MR1
+ \brief a version corresponding to Android Lollipop, maintenance release 1
+ (version 5.1, API level 22).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop_MR1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 1);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidMarshmallow
+ \brief a version corresponding to Android Marshmallow (version 6.0, API level 23).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidMarshmallow =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 6, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidNougat
+ \brief a version corresponding to Android Nougat (version 7.0, API level 24).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidNougat_MR1
+ \brief a version corresponding to Android Nougat, maintenance release 1
+ (version 7.0, API level 25).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat_MR1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 1);
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
new file mode 100644
index 0000000000..cc14d701e1
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+#ifndef QOPERATINGSYSTEMVERSION_H
+#define QOPERATINGSYSTEMVERSION_H
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+class QVersionNumber;
+
+class Q_CORE_EXPORT QOperatingSystemVersion
+{
+public:
+ enum OSType {
+ Unknown = 0,
+ Windows,
+ MacOS,
+ IOS,
+ TvOS,
+ WatchOS,
+ Android
+ };
+
+ static const QOperatingSystemVersion Windows7;
+ static const QOperatingSystemVersion Windows8;
+ static const QOperatingSystemVersion Windows8_1;
+ static const QOperatingSystemVersion Windows10;
+
+ static const QOperatingSystemVersion OSXMavericks;
+ static const QOperatingSystemVersion OSXYosemite;
+ static const QOperatingSystemVersion OSXElCapitan;
+ static const QOperatingSystemVersion MacOSSierra;
+
+ static const QOperatingSystemVersion AndroidJellyBean;
+ static const QOperatingSystemVersion AndroidJellyBean_MR1;
+ static const QOperatingSystemVersion AndroidJellyBean_MR2;
+ static const QOperatingSystemVersion AndroidKitKat;
+ static const QOperatingSystemVersion AndroidLollipop;
+ static const QOperatingSystemVersion AndroidLollipop_MR1;
+ static const QOperatingSystemVersion AndroidMarshmallow;
+ static const QOperatingSystemVersion AndroidNougat;
+ static const QOperatingSystemVersion AndroidNougat_MR1;
+
+ QOperatingSystemVersion(const QOperatingSystemVersion &other) = default;
+ Q_DECL_CONSTEXPR QOperatingSystemVersion(OSType osType,
+ int vmajor, int vminor = -1, int vmicro = -1)
+ : m_os(osType),
+ m_major(qMax(-1, vmajor)),
+ m_minor(vmajor < 0 ? -1 : qMax(-1, vminor)),
+ m_micro(vmajor < 0 || vminor < 0 ? -1 : qMax(-1, vmicro))
+ { }
+
+ static QOperatingSystemVersion current();
+
+ Q_DECL_CONSTEXPR int majorVersion() const { return m_major; }
+ Q_DECL_CONSTEXPR int minorVersion() const { return m_minor; }
+ Q_DECL_CONSTEXPR int microVersion() const { return m_micro; }
+
+ Q_DECL_CONSTEXPR int segmentCount() const
+ { return m_micro >= 0 ? 3 : m_minor >= 0 ? 2 : m_major >= 0 ? 1 : 0; }
+
+ bool isAnyOfType(std::initializer_list<OSType> types) const;
+ Q_DECL_CONSTEXPR OSType type() const { return m_os; }
+ QString name() const;
+
+ friend bool operator>(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) > 0; }
+
+ friend bool operator>=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) >= 0; }
+
+ friend bool operator<(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) < 0; }
+
+ friend bool operator<=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) <= 0; }
+
+private:
+ QOperatingSystemVersion() = default;
+ OSType m_os;
+ int m_major;
+ int m_minor;
+ int m_micro;
+
+ static int compare(const QOperatingSystemVersion &v1, const QOperatingSystemVersion &v2);
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPERATINGSYSTEMVERSION_H
diff --git a/src/corelib/global/qoperatingsystemversion_darwin.mm b/src/corelib/global/qoperatingsystemversion_darwin.mm
new file mode 100644
index 0000000000..d8b927ff5d
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_darwin.mm
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion_p.h"
+#import <Foundation/Foundation.h>
+
+QT_BEGIN_NAMESPACE
+
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
+ QOperatingSystemVersion v;
+ v.m_os = currentType();
+ v.m_major = osv.majorVersion;
+ v.m_minor = osv.minorVersion;
+ v.m_micro = osv.patchVersion;
+ return v;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion_p.h b/src/corelib/global/qoperatingsystemversion_p.h
new file mode 100644
index 0000000000..78d0daf0c6
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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 QOPERATINGSYSTEMVERSION_P_H
+#define QOPERATINGSYSTEMVERSION_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 "qoperatingsystemversion.h"
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+OSVERSIONINFOEX qWindowsVersionInfo();
+#endif
+
+static inline QOperatingSystemVersion::OSType currentType()
+{
+#if defined(Q_OS_WIN)
+ return QOperatingSystemVersion::Windows;
+#elif defined(Q_OS_MACOS)
+ return QOperatingSystemVersion::MacOS;
+#elif defined(Q_OS_IOS)
+ return QOperatingSystemVersion::IOS;
+#elif defined(Q_OS_TVOS)
+ return QOperatingSystemVersion::TvOS;
+#elif defined(Q_OS_WATCHOS)
+ return QOperatingSystemVersion::WatchOS;
+#elif defined(Q_OS_ANDROID)
+ return QOperatingSystemVersion::Android;
+#else
+ return QOperatingSystemVersion::Unknown;
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif // QOPERATINGSYSTEMVERSION_P_H
diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp
new file mode 100644
index 0000000000..060ca2f7da
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_win.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion_p.h"
+#include <qt_windows.h>
+#include <qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WINRT
+static inline HMODULE moduleHandleForFunction(LPCVOID address)
+{
+ // This is a widely used, decades-old technique for retrieving the handle
+ // of a module and is effectively equivalent to GetModuleHandleEx
+ // (which is unavailable on WinRT)
+ MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 };
+ if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0)
+ return 0;
+ return reinterpret_cast<HMODULE>(mbi.AllocationBase);
+}
+#endif
+
+static inline OSVERSIONINFOEX determineWinOsVersion()
+{
+ OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0};
+
+#define GetProcAddressA GetProcAddress
+
+ // GetModuleHandle is not supported in WinRT and linking to it at load time
+ // will not pass the Windows App Certification Kit... but it exists and is functional,
+ // so use some unusual but widely used techniques to get a pointer to it
+#ifdef Q_OS_WINRT
+ // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL
+ HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery));
+ if (Q_UNLIKELY(!kernelModule))
+ return result;
+
+ // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs)
+ typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR);
+ GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>(
+ GetProcAddressA(kernelModule, "GetModuleHandleW"));
+ if (Q_UNLIKELY(!pGetModuleHandle))
+ return result;
+#else
+#define pGetModuleHandle GetModuleHandleW
+#endif
+
+#ifndef Q_OS_WINCE
+ HMODULE ntdll = pGetModuleHandle(L"ntdll.dll");
+ if (Q_UNLIKELY(!ntdll))
+ return result;
+
+ // NTSTATUS is not defined on WinRT
+ typedef LONG NTSTATUS;
+ typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
+
+ // RtlGetVersion is documented public API but we must load it dynamically
+ // because linking to it at load time will not pass the Windows App Certification Kit
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
+ RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
+ GetProcAddressA(ntdll, "RtlGetVersion"));
+ if (Q_UNLIKELY(!pRtlGetVersion))
+ return result;
+
+ // GetVersionEx() has been deprecated in Windows 8.1 and will return
+ // only Windows 8 from that version on, so use the kernel API function.
+ pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS
+#else // !Q_OS_WINCE
+ GetVersionEx(&result);
+#endif
+ return result;
+}
+
+OSVERSIONINFOEX qWindowsVersionInfo()
+{
+ OSVERSIONINFOEX realResult = determineWinOsVersion();
+#ifdef QT_DEBUG
+ {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) {
+ OSVERSIONINFOEX result = realResult;
+ result.dwMajorVersion = 0;
+ result.dwMinorVersion = 0;
+
+ // Erase any build number and service pack information
+ result.dwBuildNumber = 0;
+ result.szCSDVersion[0] = L'\0';
+ result.wServicePackMajor = 0;
+ result.wServicePackMinor = 0;
+
+ const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE");
+ if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 1;
+ } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 2;
+ } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 3;
+ } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") {
+ result.dwMajorVersion = 10;
+ } else {
+ return realResult;
+ }
+
+ if (winVerOverride == "2008_R2"
+ || winVerOverride == "2012"
+ || winVerOverride == "2012_R2"
+ || winVerOverride == "2016") {
+ // If the current host OS is a domain controller and the override OS
+ // is also a server type OS, preserve that information
+ if (result.wProductType == VER_NT_WORKSTATION)
+ result.wProductType = VER_NT_SERVER;
+ } else {
+ // Any other OS must be a workstation OS type
+ result.wProductType = VER_NT_WORKSTATION;
+ }
+ }
+ }
+#endif
+ return realResult;
+}
+
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ QOperatingSystemVersion v;
+ v.m_os = currentType();
+ const OSVERSIONINFOEX osv = qWindowsVersionInfo();
+ v.m_major = osv.dwMajorVersion;
+ v.m_minor = osv.dwMinorVersion;
+ v.m_micro = osv.dwBuildNumber;
+ return v;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h
index 55fcb37093..ed11e013f2 100644
--- a/src/corelib/global/qprocessordetection.h
+++ b/src/corelib/global/qprocessordetection.h
@@ -107,14 +107,17 @@
# define Q_PROCESSOR_ARM __TARGET_ARCH_ARM
# elif defined(_M_ARM) && _M_ARM > 1
# define Q_PROCESSOR_ARM _M_ARM
-# elif defined(__ARM64_ARCH_8__) || defined(__aarch64__)
+# elif defined(__ARM64_ARCH_8__) \
+ || defined(__aarch64__) \
+ || defined(__CORE_CORTEXAV8__) // GHS-specific for INTEGRITY
# define Q_PROCESSOR_ARM 8
# elif defined(__ARM_ARCH_7__) \
|| defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7R__) \
|| defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7S__) \
- || defined(_ARM_ARCH_7)
+ || defined(_ARM_ARCH_7) \
+ || defined(__CORE_CORTEXA__) // GHS-specific for INTEGRITY
# define Q_PROCESSOR_ARM 7
# elif defined(__ARM_ARCH_6__) \
|| defined(__ARM_ARCH_6J__) \
diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h
index 23f412aa6a..f443ab4b93 100644
--- a/src/corelib/global/qsysinfo.h
+++ b/src/corelib/global/qsysinfo.h
@@ -49,6 +49,23 @@ QT_BEGIN_NAMESPACE
System information
*/
+/*
+ * GCC (5-7) has a regression that causes it to emit wrong deprecated warnings:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77849
+ *
+ * Try to work around it by defining our own macro.
+ */
+
+#ifdef QT_SYSINFO_DEPRECATED_X
+#error "QT_SYSINFO_DEPRECATED_X already defined"
+#endif
+
+#ifdef Q_CC_GNU
+#define QT_SYSINFO_DEPRECATED_X(x)
+#else
+#define QT_SYSINFO_DEPRECATED_X(x) QT_DEPRECATED_X(x)
+#endif
+
class QString;
class Q_CORE_EXPORT QSysInfo {
public:
@@ -79,7 +96,8 @@ public:
# endif
};
#endif
- enum WinVersion {
+#if QT_DEPRECATED_SINCE(5, 9)
+ enum QT_DEPRECATED_X("Use QOperatingSystemVersion") WinVersion {
WV_None = 0x0000,
WV_32s = 0x0001,
@@ -117,19 +135,12 @@ public:
WV_CE_6 = 0x0400,
WV_CE_based = 0x0f00
};
-#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
- static const WinVersion WindowsVersion;
- static WinVersion windowsVersion();
-#else
- static const WinVersion WindowsVersion = WV_None;
- static WinVersion windowsVersion() { return WV_None; }
-#endif
#define Q_MV_OSX(major, minor) (major == 10 ? minor + 2 : (major == 9 ? 1 : 0))
#define Q_MV_IOS(major, minor) (QSysInfo::MV_IOS | major << 4 | minor)
#define Q_MV_TVOS(major, minor) (QSysInfo::MV_TVOS | major << 4 | minor)
#define Q_MV_WATCHOS(major, minor) (QSysInfo::MV_WATCHOS | major << 4 | minor)
- enum MacVersion {
+ enum QT_DEPRECATED_X("Use QOperatingSystemVersion") MacVersion {
MV_None = 0xffff,
MV_Unknown = 0x0000,
@@ -198,13 +209,29 @@ public:
MV_WATCHOS_2_2 = Q_MV_WATCHOS(2, 2),
MV_WATCHOS_3_0 = Q_MV_WATCHOS(3, 0)
};
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_INTEL(1478)
+QT_WARNING_DISABLE_INTEL(1786)
+QT_WARNING_DISABLE_MSVC(4996)
+#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion();
+#else
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion = WV_None;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion() { return WV_None; }
+#endif
#if defined(Q_OS_MAC)
- static const MacVersion MacintoshVersion;
- static MacVersion macVersion();
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion();
#else
- static const MacVersion MacintoshVersion = MV_None;
- static MacVersion macVersion() { return MV_None; }
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion = MV_None;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion() { return MV_None; }
#endif
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(5, 9)
static QString buildCpuArchitecture();
static QString currentCpuArchitecture();
@@ -219,5 +246,7 @@ public:
static QString machineHostName();
};
+#undef QT_SYSINFO_DEPRECATED_X
+
QT_END_NAMESPACE
#endif // QSYSINFO_H
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index 3b486b8f6f..3133b4a719 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -134,7 +134,6 @@
# define WINAPI_FAMILY_PC_APP WINAPI_FAMILY_APP
# endif
# if defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP
-# define Q_OS_WINPHONE
# define Q_OS_WINRT
# elif WINAPI_FAMILY==WINAPI_FAMILY_PC_APP
# define Q_OS_WINRT
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index 8aa5cb4fb4..7031021e16 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -58,9 +58,10 @@ class QTypeInfo
{
public:
enum {
+ isSpecialized = std::is_enum<T>::value, // don't require every enum to be marked manually
isPointer = false,
isIntegral = std::is_integral<T>::value,
- isComplex = true,
+ isComplex = !isIntegral && !std::is_enum<T>::value,
isStatic = true,
isRelocatable = std::is_enum<T>::value,
isLarge = (sizeof(T)>sizeof(void*)),
@@ -74,6 +75,7 @@ class QTypeInfo<void>
{
public:
enum {
+ isSpecialized = true,
isPointer = false,
isIntegral = false,
isComplex = false,
@@ -90,6 +92,7 @@ class QTypeInfo<T*>
{
public:
enum {
+ isSpecialized = true,
isPointer = true,
isIntegral = false,
isComplex = false,
@@ -124,7 +127,7 @@ struct QTypeInfoQuery : public QTypeInfo<T>
// if QTypeInfo<T>::isRelocatable exists, use it
template <typename T>
-struct QTypeInfoQuery<T, typename QtPrivate::QEnableIf<QTypeInfo<T>::isRelocatable || true>::Type> : public QTypeInfo<T>
+struct QTypeInfoQuery<T, typename std::enable_if<QTypeInfo<T>::isRelocatable || true>::type> : public QTypeInfo<T>
{};
/*!
@@ -152,6 +155,7 @@ class QTypeInfoMerger
{
public:
enum {
+ isSpecialized = true,
isComplex = QTypeInfoQuery<T1>::isComplex || QTypeInfoQuery<T2>::isComplex
|| QTypeInfoQuery<T3>::isComplex || QTypeInfoQuery<T4>::isComplex,
isStatic = QTypeInfoQuery<T1>::isStatic || QTypeInfoQuery<T2>::isStatic
@@ -173,6 +177,7 @@ class QTypeInfo< CONTAINER<T> > \
{ \
public: \
enum { \
+ isSpecialized = true, \
isPointer = false, \
isIntegral = false, \
isComplex = true, \
@@ -201,6 +206,7 @@ class QTypeInfo< CONTAINER<K, V> > \
{ \
public: \
enum { \
+ isSpecialized = true, \
isPointer = false, \
isIntegral = false, \
isComplex = true, \
@@ -241,6 +247,7 @@ class QTypeInfo<TYPE > \
{ \
public: \
enum { \
+ isSpecialized = true, \
isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0), \
isStatic = (((FLAGS) & (Q_MOVABLE_TYPE | Q_PRIMITIVE_TYPE)) == 0), \
isRelocatable = !isStatic || ((FLAGS) & Q_RELOCATABLE_TYPE), \
diff --git a/src/corelib/global/qtypetraits.h b/src/corelib/global/qtypetraits.h
index 9773db919b..35e407e2de 100644
--- a/src/corelib/global/qtypetraits.h
+++ b/src/corelib/global/qtypetraits.h
@@ -37,6 +37,12 @@
**
****************************************************************************/
+// ### Qt 6: remove this header
+//
+// This header is deliberately empty. Although it did not contain any public API,
+// it was accidentally made public in Qt 5. So: do not remove it for the moment
+// being, to prevent #include breaks in downstreams.
+
#include "QtCore/qglobal.h"
#ifndef QTYPETRAITS_H
@@ -44,53 +50,6 @@
QT_BEGIN_NAMESPACE
-namespace QtPrivate {
-
-//
-// Define QIsUnsignedEnum, QIsSignedEnum -
-// std::is_signed, std::is_unsigned does not work for enum's
-//
-
-// a metafunction to invert an integral_constant:
-template <typename T>
-struct not_
- : std::integral_constant<bool, !T::value> {};
-
-// Checks whether a type is unsigned (T must be convertible to unsigned int):
-template <typename T>
-struct QIsUnsignedEnum
- : std::integral_constant<bool, (T(0) < T(-1))> {};
-
-// Checks whether a type is signed (T must be convertible to int):
-template <typename T>
-struct QIsSignedEnum
- : not_< QIsUnsignedEnum<T> > {};
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint8>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint8>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint8>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint8>::value));
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint16>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint16>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint16>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint16>::value));
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint32>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint32>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint32>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint32>::value));
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint64>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint64>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint64>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint64>::value));
-
-} // namespace QtPrivate
-
QT_END_NAMESPACE
+
#endif // QTYPETRAITS_H
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index b5bfec8857..b0cac59f42 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -93,7 +93,7 @@ SOURCES += \
io/qloggingcategory.cpp \
io/qloggingregistry.cpp
-qtConfig(process) {
+qtConfig(processenvironment) {
SOURCES += \
io/qprocess.cpp
HEADERS += \
@@ -154,6 +154,8 @@ win32 {
}
mac {
SOURCES += io/qstorageinfo_mac.cpp
+ qtConfig(processenvironment): \
+ OBJECTIVE_SOURCES += io/qprocess_darwin.mm
OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
osx {
OBJECTIVE_SOURCES += io/qfilesystemwatcher_fsevents.mm
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
index b4eb98e062..9a42fb4a37 100644
--- a/src/corelib/io/qdatastream.cpp
+++ b/src/corelib/io/qdatastream.cpp
@@ -42,6 +42,7 @@
#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
#include "qbuffer.h"
+#include "qfloat16.h"
#include "qstring.h"
#include <stdio.h>
#include <ctype.h>
@@ -448,6 +449,9 @@ QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
The default is DoublePrecision.
+ Note that this property does not affect the serialization or deserialization of \c qfloat16
+ instances.
+
\warning This property must be set to the same value on the object that writes and the object
that reads the data stream.
@@ -557,6 +561,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_5_6 Version 17 (Qt 5.6)
\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
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
@@ -766,6 +771,17 @@ int QDataStream::readBlock(char *data, int len)
}
/*!
+ \fn QDataStream &QDataStream::operator>>(std::nullptr &ptr)
+ \since 5.9
+ \overload
+
+ Simulates reading a \c{std::nullptr_t} from the stream into \a ptr and
+ returns a reference to the stream. This function does not actually read
+ anything from the stream, as \c{std::nullptr_t} values are stored as 0
+ bytes.
+*/
+
+/*!
\fn QDataStream &QDataStream::operator>>(quint8 &i)
\overload
@@ -972,6 +988,20 @@ QDataStream &QDataStream::operator>>(double &f)
/*!
\overload
+ \since 5.9
+
+ Reads a floating point number from the stream into \a f,
+ using the standard IEEE 754 format. Returns a reference to the
+ stream.
+*/
+QDataStream &QDataStream::operator>>(qfloat16 &f)
+{
+ return *this >> reinterpret_cast<qint16&>(f);
+}
+
+
+/*!
+ \overload
Reads the '\\0'-terminated string \a s from the stream and returns
a reference to the stream.
@@ -1065,6 +1095,15 @@ int QDataStream::readRawData(char *s, int len)
QDataStream write functions
*****************************************************************************/
+/*!
+ \fn QDataStream &QDataStream::operator<<(std::nullptr ptr)
+ \since 5.9
+ \overload
+
+ Simulates writing a \c{std::nullptr_t}, \a ptr, to the stream and returns a
+ reference to the stream. This function does not actually write anything to
+ the stream, as \c{std::nullptr_t} values are stored as 0 bytes.
+*/
/*!
\fn QDataStream &QDataStream::operator<<(quint8 i)
@@ -1259,6 +1298,19 @@ QDataStream &QDataStream::operator<<(double f)
/*!
+ \fn QDataStream &QDataStream::operator<<(qfloat16 f)
+ \overload
+ \since 5.9
+
+ Writes a floating point number, \a f, to the stream using
+ the standard IEEE 754 format. Returns a reference to the stream.
+*/
+QDataStream &QDataStream::operator<<(qfloat16 f)
+{
+ return *this << reinterpret_cast<qint16&>(f);
+}
+
+/*!
\overload
Writes the '\\0'-terminated string \a s to the stream and returns a
@@ -1281,7 +1333,6 @@ QDataStream &QDataStream::operator<<(const char *s)
return *this;
}
-
/*!
Writes the length specifier \a len and the buffer \a s to the
stream and returns a reference to the stream.
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index ac58677b77..575607e147 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -50,7 +50,7 @@
QT_BEGIN_NAMESPACE
-
+class qfloat16;
class QByteArray;
class QIODevice;
@@ -95,10 +95,11 @@ public:
Qt_5_6 = 17,
Qt_5_7 = Qt_5_6,
Qt_5_8 = Qt_5_7,
-#if QT_VERSION >= 0x050900
+ Qt_5_9 = Qt_5_8,
+#if QT_VERSION >= 0x050a00
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
- Qt_DefaultCompiledVersion = Qt_5_8
+ Qt_DefaultCompiledVersion = Qt_5_9
};
enum ByteOrder {
@@ -151,8 +152,10 @@ public:
QDataStream &operator>>(quint32 &i);
QDataStream &operator>>(qint64 &i);
QDataStream &operator>>(quint64 &i);
+ QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
QDataStream &operator>>(bool &i);
+ QDataStream &operator>>(qfloat16 &f);
QDataStream &operator>>(float &f);
QDataStream &operator>>(double &f);
QDataStream &operator>>(char *&str);
@@ -165,7 +168,9 @@ public:
QDataStream &operator<<(quint32 i);
QDataStream &operator<<(qint64 i);
QDataStream &operator<<(quint64 i);
+ QDataStream &operator<<(std::nullptr_t) { return *this; }
QDataStream &operator<<(bool i);
+ QDataStream &operator<<(qfloat16 f);
QDataStream &operator<<(float f);
QDataStream &operator<<(double f);
QDataStream &operator<<(const char *str);
@@ -222,6 +227,98 @@ private:
QDataStream::Status oldStatus;
};
+template <typename Container>
+QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ c.reserve(n);
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::value_type t;
+ s >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c.append(t);
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &readListBasedContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::value_type t;
+ s >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c << t;
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::key_type k;
+ typename Container::mapped_type t;
+ s >> k >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c.insertMulti(k, t);
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
+{
+ s << quint32(c.size());
+ for (const typename Container::value_type &t : c)
+ s << t;
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
+{
+ s << quint32(c.size());
+ // Deserialization should occur in the reverse order.
+ // Otherwise, value() will return the least recently inserted
+ // value instead of the most recently inserted one.
+ auto it = c.constEnd();
+ auto begin = c.constBegin();
+ while (it != begin) {
+ --it;
+ s << it.key() << it.value();
+ }
+
+ return s;
+}
+
} // QtPrivate namespace
/*****************************************************************************
@@ -264,210 +361,84 @@ inline QDataStream &QDataStream::operator<<(quint32 i)
inline QDataStream &QDataStream::operator<<(quint64 i)
{ return *this << qint64(i); }
-template <typename T>
-QDataStream& operator>>(QDataStream& s, QList<T>& l)
-{
- QtPrivate::StreamStateSaver stateSaver(&s);
+template <typename Enum>
+inline QDataStream &operator<<(QDataStream &s, QFlags<Enum> e)
+{ return s << e.i; }
- l.clear();
- quint32 c;
- s >> c;
- l.reserve(c);
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
+template <typename Enum>
+inline QDataStream &operator>>(QDataStream &s, QFlags<Enum> &e)
+{ return s >> e.i; }
- return s;
+template <typename T>
+inline QDataStream &operator>>(QDataStream &s, QList<T> &l)
+{
+ return QtPrivate::readArrayBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QList<T> &l)
{
- s << quint32(l.size());
- for (int i = 0; i < l.size(); ++i)
- s << l.at(i);
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template <typename T>
-QDataStream& operator>>(QDataStream& s, QLinkedList<T>& l)
+inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- l.clear();
- quint32 c;
- s >> c;
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
-
- return s;
+ return QtPrivate::readListBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QLinkedList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l)
{
- s << quint32(l.size());
- typename QLinkedList<T>::ConstIterator it = l.constBegin();
- for(; it != l.constEnd(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template<typename T>
-QDataStream& operator>>(QDataStream& s, QVector<T>& v)
+inline QDataStream &operator>>(QDataStream &s, QVector<T> &v)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- v.clear();
- quint32 c;
- s >> c;
- v.resize(c);
- for(quint32 i = 0; i < c; ++i) {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- v.clear();
- break;
- }
- v[i] = t;
- }
-
- return s;
+ return QtPrivate::readArrayBasedContainer(s, v);
}
template<typename T>
-QDataStream& operator<<(QDataStream& s, const QVector<T>& v)
+inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v)
{
- s << quint32(v.size());
- for (typename QVector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, v);
}
template <typename T>
-QDataStream &operator>>(QDataStream &in, QSet<T> &set)
+inline QDataStream &operator>>(QDataStream &s, QSet<T> &set)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- set.clear();
- quint32 c;
- in >> c;
- for (quint32 i = 0; i < c; ++i) {
- T t;
- in >> t;
- if (in.status() != QDataStream::Ok) {
- set.clear();
- break;
- }
- set << t;
- }
-
- return in;
+ return QtPrivate::readListBasedContainer(s, set);
}
template <typename T>
-QDataStream& operator<<(QDataStream &out, const QSet<T> &set)
+inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set)
{
- out << quint32(set.size());
- typename QSet<T>::const_iterator i = set.constBegin();
- while (i != set.constEnd()) {
- out << *i;
- ++i;
- }
- return out;
+ return QtPrivate::writeSequentialContainer(s, set);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash<Key, T> &hash)
+inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- hash.clear();
- quint32 n;
- in >> n;
-
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- Key k;
- T t;
- in >> k >> t;
- hash.insertMulti(k, t);
- }
-
- if (in.status() != QDataStream::Ok)
- hash.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash)
+inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
{
- out << quint32(hash.size());
- typename QHash<Key, T>::ConstIterator it = hash.end();
- typename QHash<Key, T>::ConstIterator begin = hash.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, hash);
}
-#ifdef Q_QDOC
+
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<Key, T> &map)
-#else
-template <class aKey, class aT>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<aKey, aT> &map)
-#endif
+inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- map.clear();
- quint32 n;
- in >> n;
-
- map.detach();
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- aKey key;
- aT value;
- in >> key >> value;
- map.insertMulti(key, value);
- }
- if (in.status() != QDataStream::Ok)
- map.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
+inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
{
- out << quint32(map.size());
- typename QMap<Key, T>::ConstIterator it = map.end();
- typename QMap<Key, T>::ConstIterator begin = map.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, map);
}
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index abc2abeaec..61059dd694 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -365,7 +365,7 @@ Q_CORE_EXPORT QDebug qt_QMetaEnum_debugOperator(QDebug&, int value, const QMetaO
Q_CORE_EXPORT QDebug qt_QMetaEnum_flagDebugOperator(QDebug &dbg, quint64 value, const QMetaObject *meta, const char *name);
template<typename T>
-typename QtPrivate::QEnableIf<QtPrivate::IsQEnumHelper<T>::Value, QDebug>::Type
+typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, QDebug>::type
operator<<(QDebug dbg, T value)
{
const QMetaObject *obj = qt_getEnumMetaObject(value);
@@ -374,9 +374,9 @@ operator<<(QDebug dbg, T value)
}
template <class T>
-inline typename QtPrivate::QEnableIf<
+inline typename std::enable_if<
QtPrivate::IsQEnumHelper<T>::Value || QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
- QDebug>::Type
+ QDebug>::type
qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
{
const QMetaObject *obj = qt_getEnumMetaObject(T());
@@ -385,9 +385,9 @@ qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
}
template <class T>
-inline typename QtPrivate::QEnableIf<
+inline typename std::enable_if<
!QtPrivate::IsQEnumHelper<T>::Value && !QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
- QDebug>::Type
+ QDebug>::type
qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
#else // !QT_NO_QOBJECT && !Q_QDOC
template <class T>
@@ -402,7 +402,7 @@ template<typename T>
inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
{
// We have to use an indirection otherwise specialisation of some other overload of the
- // operator<< the compiler would try to instantiate QFlags<T> for the QEnableIf
+ // operator<< the compiler would try to instantiate QFlags<T> for the std::enable_if
return qt_QMetaEnum_flagDebugOperator_helper(debug, flags);
}
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 437f774547..6d144cb65d 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -1843,6 +1843,26 @@ bool QDir::exists(const QString &name) const
}
/*!
+ Returns whether the directory is empty.
+
+ Equivalent to \c{count() == 0} with filters
+ \c{QDir::AllEntries | QDir::NoDotAndDotDot}, but faster as it just checks
+ whether the directory contains at least one entry.
+
+ \note Unless you set the \a filters flags to include \c{QDir::NoDotAndDotDot}
+ (as the default value does), no directory is empty.
+
+ \sa count(), entryList(), setFilter()
+ \since 5.9
+*/
+bool QDir::isEmpty(Filters filters) const
+{
+ const auto d = d_ptr.constData();
+ QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters);
+ return !it.hasNext();
+}
+
+/*!
Returns a list of the root directories on this system.
On Windows this returns a list of QFileInfo objects containing "C:/",
@@ -2085,11 +2105,11 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
return name;
int i = len - 1;
- QVarLengthArray<QChar> outVector(len);
+ QVarLengthArray<ushort> outVector(len);
int used = len;
- QChar *out = outVector.data();
- const QChar *p = name.unicode();
- const QChar *prefix = p;
+ ushort *out = outVector.data();
+ const ushort *p = name.utf16();
+ const ushort *prefix = p;
int up = 0;
const int prefixLength = rootLength(name, allowUncPaths);
@@ -2097,39 +2117,39 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
i -= prefixLength;
// replicate trailing slash (i > 0 checks for emptiness of input string p)
- if (i > 0 && p[i].unicode() == '/') {
- out[--used].unicode() = '/';
+ if (i > 0 && p[i] == '/') {
+ out[--used] = '/';
--i;
}
while (i >= 0) {
// remove trailing slashes
- if (p[i].unicode() == '/') {
+ if (p[i] == '/') {
--i;
continue;
}
// remove current directory
- if (p[i].unicode() == '.' && (i == 0 || p[i-1].unicode() == '/')) {
+ if (p[i] == '.' && (i == 0 || p[i-1] == '/')) {
--i;
continue;
}
// detect up dir
- if (i >= 1 && p[i].unicode() == '.' && p[i-1].unicode() == '.'
- && (i == 1 || (i >= 2 && p[i-2].unicode() == '/'))) {
+ if (i >= 1 && p[i] == '.' && p[i-1] == '.'
+ && (i == 1 || (i >= 2 && p[i-2] == '/'))) {
++up;
i -= 2;
continue;
}
// prepend a slash before copying when not empty
- if (!up && used != len && out[used].unicode() != '/')
- out[--used] = QLatin1Char('/');
+ if (!up && used != len && out[used] != '/')
+ out[--used] = '/';
// skip or copy
while (i >= 0) {
- if (p[i].unicode() == '/') { // do not copy slashes
+ if (p[i] == '/') { // do not copy slashes
--i;
break;
}
@@ -2151,17 +2171,17 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
// add remaining '..'
while (up) {
- if (used != len && out[used].unicode() != '/') // is not empty and there isn't already a '/'
- out[--used] = QLatin1Char('/');
- out[--used] = QLatin1Char('.');
- out[--used] = QLatin1Char('.');
+ if (used != len && out[used] != '/') // is not empty and there isn't already a '/'
+ out[--used] = '/';
+ out[--used] = '.';
+ out[--used] = '.';
--up;
}
bool isEmpty = used == len;
if (prefixLength) {
- if (!isEmpty && out[used].unicode() == '/') {
+ if (!isEmpty && out[used] == '/') {
// Eventhough there is a prefix the out string is a slash. This happens, if the input
// string only consists of a prefix followed by one or more slashes. Just skip the slash.
++used;
@@ -2172,18 +2192,19 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
if (isEmpty) {
// After resolving the input path, the resulting string is empty (e.g. "foo/.."). Return
// a dot in that case.
- out[--used] = QLatin1Char('.');
- } else if (out[used].unicode() == '/') {
+ out[--used] = '.';
+ } else if (out[used] == '/') {
// After parsing the input string, out only contains a slash. That happens whenever all
// parts are resolved and there is a trailing slash ("./" or "foo/../" for example).
// Prepend a dot to have the correct return value.
- out[--used] = QLatin1Char('.');
+ out[--used] = '.';
}
}
// If path was not modified return the original value
- QString ret = (used == 0 ? name : QString(out + used, len - used));
- return ret;
+ if (used == 0)
+ return name;
+ return QString::fromUtf16(out + used, len - used);
}
static QString qt_cleanPath(const QString &path, bool *ok)
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index ef7ec2c701..950a26f327 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -144,6 +144,8 @@ public:
void setSorting(SortFlags sort);
uint count() const;
+ bool isEmpty(Filters filters = Filters(AllEntries | NoDotAndDotDot)) const;
+
QString operator[](int) const;
static QStringList nameFiltersFromString(const QString &nameFilter);
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 5acee25d02..12fd7d3048 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -1295,7 +1295,7 @@ qint64 QFileInfo::size() const
}
/*!
- Returns the date and time when the file was created.
+ Returns the date and local time when the file was created.
On most Unix systems, this function returns the time of the last
status change. A status change occurs when the file is created,
@@ -1316,13 +1316,13 @@ QDateTime QFileInfo::created() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::CreationTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::CreationTime))
return QDateTime();
- return d->metaData.creationTime();
+ return d->metaData.creationTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::CreationTime);
+ return d->getFileTime(QAbstractFileEngine::CreationTime).toLocalTime();
}
/*!
- Returns the date and time when the file was last modified.
+ Returns the date and local time when the file was last modified.
\sa created(), lastRead()
*/
@@ -1335,13 +1335,13 @@ QDateTime QFileInfo::lastModified() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ModificationTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ModificationTime))
return QDateTime();
- return d->metaData.modificationTime();
+ return d->metaData.modificationTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::ModificationTime);
+ return d->getFileTime(QAbstractFileEngine::ModificationTime).toLocalTime();
}
/*!
- Returns the date and time when the file was last read (accessed).
+ Returns the date and local time when the file was last read (accessed).
On platforms where this information is not available, returns the
same as lastModified().
@@ -1357,9 +1357,9 @@ QDateTime QFileInfo::lastRead() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::AccessTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::AccessTime))
return QDateTime();
- return d->metaData.accessTime();
+ return d->metaData.accessTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::AccessTime);
+ return d->getFileTime(QAbstractFileEngine::AccessTime).toLocalTime();
}
/*!
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index 22995db07d..9db67f2f9b 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -133,9 +133,9 @@ QFileSelectorPrivate::QFileSelectorPrivate()
With those files available, you would select a different file on the android platform,
but only if the locale was en_GB.
- QFileSelector will not attempt to select if the base file does not exist. For error handling in
- the case no valid selectors are present, it is recommended to have a default or error-handling
- file in the base file location even if you expect selectors to be present for all deployments.
+ For error handling in the case no valid selectors are present, it is recommended to have a default or
+ error-handling file in the base file location even if you expect selectors to be present for all
+ deployments.
In a future version, some may be marked as deploy-time static and be moved during the
deployment step as an optimization. As selectors come with a performance cost, it is
@@ -298,9 +298,6 @@ QString QFileSelectorPrivate::select(const QString &filePath) const
{
Q_Q(const QFileSelector);
QFileInfo fi(filePath);
- // If file doesn't exist, don't select
- if (!fi.exists())
- return filePath;
QString ret = selectionHelper(fi.path().isEmpty() ? QString() : fi.path() + QLatin1Char('/'),
fi.fileName(), q->allSelectors());
@@ -369,14 +366,10 @@ QStringList QFileSelectorPrivate::platformSelectors()
// ### Qt6: remove macOS fallbacks to "mac" and the future compatibility
QStringList ret;
#if defined(Q_OS_WIN)
- // can't fall back to QSysInfo because we need both "winphone" and "winrt" for the Windows Phone case
ret << QStringLiteral("windows");
ret << QSysInfo::kernelType(); // "winnt"
# if defined(Q_OS_WINRT)
ret << QStringLiteral("winrt");
-# if defined(Q_OS_WINPHONE)
- ret << QStringLiteral("winphone");
-# endif
# endif
#elif defined(Q_OS_UNIX)
ret << QStringLiteral("unix");
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 96829b3b03..e195afdae9 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Intel Corporation.
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** Contact: https://www.qt.io/licensing/
@@ -122,13 +123,10 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
return true;
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
// Find if an application other than Finder claims to know how to handle the package
- QCFType<CFURLRef> application;
- LSGetApplicationForURL(url,
- kLSRolesEditor|kLSRolesViewer,
- NULL,
- &application);
+ QCFType<CFURLRef> application = LSCopyDefaultApplicationURLForURL(url,
+ kLSRolesEditor | kLSRolesViewer, nullptr);
if (application) {
QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, application);
@@ -606,25 +604,7 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
if (!createParents)
return false;
- // we need the cleaned path in order to create the parents
- // and we save errno just in case encodeName needs to load codecs
- int savedErrno = errno;
- bool pathChanged;
- {
- QString cleanName = QDir::cleanPath(dirName);
-
- // Check if the cleaned name is the same or not. If we were given a
- // path with resolvable "../" sections, cleanPath will remove them, but
- // this may change the target dir if one of those segments was a
- // symlink. This operation depends on cleanPath's optimization of
- // returning the original string if it didn't modify anything.
- pathChanged = !dirName.isSharedWith(cleanName);
- if (pathChanged)
- nativeName = QFile::encodeName(cleanName);
- }
-
- errno = savedErrno;
- return createDirectoryWithParents(nativeName, pathChanged);
+ return createDirectoryWithParents(nativeName, false);
}
//static
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 0d4ef94622..b1e218de9c 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qfilesystemengine_p.h"
-
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qsysinfo.h"
#include "private/qabstractfileengine_p.h"
@@ -81,11 +81,6 @@ using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::ApplicationModel;
-
-#if _MSC_VER < 1900
-#define Q_OS_WINRT_WIN81
-#endif
-
#endif // Q_OS_WINRT
#ifndef SPI_GETPLATFORMTYPE
@@ -157,7 +152,6 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
#if defined(Q_OS_WINRT)
-static QString qfsPrivateCurrentDir = QLatin1String("");
// As none of the functions we try to resolve do exist on WinRT we
// avoid library loading on WinRT in general to shorten everything
// up a little bit.
@@ -504,7 +498,6 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
{
// can be //server or //server/share
QString absPath;
-#if !defined(Q_OS_WINRT_WIN81)
QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
wchar_t *fileName = 0;
DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
@@ -524,12 +517,7 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
if (absPath.size() < rootPath.size() && rootPath.startsWith(absPath))
absPath = rootPath;
# endif // Q_OS_WINRT
-#else // !Q_OS_WINRT_WIN81
- if (QDir::isRelativePath(path))
- absPath = QDir::toNativeSeparators(QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + path));
- else
- absPath = QDir::toNativeSeparators(QDir::cleanPath(path));
-#endif // Q_OS_WINRT_WIN81
+
// This is really ugly, but GetFullPathName strips off whitespace at the end.
// If you for instance write ". " in the lineedit of QFileDialog,
// (which is an invalid filename) this function will strip the space off and viola,
@@ -551,14 +539,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
else
ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(entry.filePath()));
} else {
-#ifndef Q_OS_WINRT_WIN81
ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath());
-#else
- // Some WinRT APIs do not support absolute paths (due to sandboxing).
- // Thus the port uses the executable's directory as its root directory
- // and treats paths relative to that as absolute paths.
- ret = QDir::cleanPath(QDir::current().relativeFilePath(entry.filePath()));
-#endif
}
#ifndef Q_OS_WINRT
@@ -638,7 +619,7 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
FILE_SHARE_READ, OPEN_EXISTING, NULL);
#endif // Q_OS_WINRT
if (handle) {
- result = QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 ?
+ result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
fileIdWin8(handle) : fileId(handle);
CloseHandle(handle);
}
@@ -1219,9 +1200,6 @@ QString QFileSystemEngine::tempPath()
ret = QDir::fromNativeSeparators(ret);
}
#else // !Q_OS_WINRT
- // According to http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.applicationdata.temporaryfolder.aspx
- // the API is not available on winphone which should cause one of the functions
- // below to fail
ComPtr<IApplicationDataStatics> applicationDataStatics;
if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
return ret;
@@ -1253,20 +1231,14 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
if(!(meta.exists() && meta.isDirectory()))
return false;
-#if !defined(Q_OS_WINRT_WIN81)
//TODO: this should really be using nativeFilePath(), but that returns a path in long format \\?\c:\foo
//which causes many problems later on when it's returned through currentPath()
return ::SetCurrentDirectory(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(entry.filePath()).utf16())) != 0;
-#else
- qfsPrivateCurrentDir = entry.filePath();
- return true;
-#endif
}
QFileSystemEntry QFileSystemEngine::currentPath()
{
QString ret;
-#if !defined(Q_OS_WINRT_WIN81)
DWORD size = 0;
wchar_t currentName[PATH_MAX];
size = ::GetCurrentDirectory(PATH_MAX, currentName);
@@ -1282,13 +1254,6 @@ QFileSystemEntry QFileSystemEngine::currentPath()
}
if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
-#else // !Q_OS_WINRT_WIN81
- //TODO - a race condition exists when using currentPath / setCurrentPath from multiple threads
- if (qfsPrivateCurrentDir.isEmpty())
- qfsPrivateCurrentDir = QDir::rootPath();
-
- ret = qfsPrivateCurrentDir;
-#endif // Q_OS_WINRT_WIN81
return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath());
}
@@ -1369,15 +1334,11 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
{
- QDateTime ret;
-
- SYSTEMTIME sTime, lTime;
+ SYSTEMTIME sTime;
FileTimeToSystemTime(time, &sTime);
- SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime);
- ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay));
- ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds));
-
- return ret;
+ return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
+ QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
+ Qt::UTC);
}
QDateTime QFileSystemMetaData::creationTime() const
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
index 2e92f8fbba..de4c852068 100644
--- a/src/corelib/io/qfilesystementry.cpp
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -175,10 +175,8 @@ void QFileSystemEntry::resolveNativeFilePath() const
// WinRT/MSVC2015 allows a maximum of 256 characters for a filepath
// unless //?/ is prepended which extends the rule to have a maximum
// of 256 characters in the filename plus the preprending path
-#if _MSC_VER >= 1900
m_nativeFilePath.prepend("\\\\?\\");
#endif
-#endif
}
}
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
index 2ce7bd7a4b..2905a8e54e 100644
--- a/src/corelib/io/qfilesystemiterator_win.cpp
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -39,6 +39,7 @@
#include "qfilesystemiterator_p.h"
#include "qfilesystemengine_p.h"
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qvector.h"
@@ -68,10 +69,6 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi
nativePath.append(QLatin1Char('\\'));
nativePath.append(QLatin1Char('*'));
// In MSVC2015+ case we prepend //?/ for longer file-name support
-#if defined(Q_OS_WINRT) && _MSC_VER < 1900
- if (nativePath.startsWith(QLatin1Char('\\')))
- nativePath.remove(0, 1);
-#endif
if (!dirPath.endsWith(QLatin1Char('/')))
dirPath.append(QLatin1Char('/'));
if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
@@ -93,7 +90,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
haveData = true;
int infoLevel = 0 ; // FindExInfoStandard;
DWORD dwAdditionalFlags = 0;
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows7) {
dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH
infoLevel = 1 ; // FindExInfoBasic;
}
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index 091552f86e..b09223d656 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
class QFileSystemEngine;
-class QFileSystemMetaData
+class Q_AUTOTEST_EXPORT QFileSystemMetaData
{
public:
QFileSystemMetaData()
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index a1d90c76f4..612b3fa57c 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -64,6 +64,9 @@
# include "qfilesystemwatcher_fsevents_p.h"
#endif
+#include <algorithm>
+#include <iterator>
+
QT_BEGIN_NAMESPACE
QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject *parent)
@@ -102,6 +105,17 @@ void QFileSystemWatcherPrivate::init()
SIGNAL(directoryChanged(QString,bool)),
q,
SLOT(_q_directoryChanged(QString,bool)));
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemoval,
+ q, [this] (const QString &p) { _q_winDriveLockForRemoval(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed,
+ q, [this] (const QString &p) { _q_winDriveLockForRemovalFailed(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveRemoved,
+ q, [this] (const QString &p) { _q_winDriveRemoved(p); });
+#endif // !Q_OS_WINRT
}
}
@@ -146,7 +160,46 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re
emit q->directoryChanged(path, QFileSystemWatcher::QPrivateSignal());
}
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive for removal, release
+ // its paths under watch, temporarily storing them should the lock fail.
+ Q_Q(QFileSystemWatcher);
+ QStringList pathsToBeRemoved;
+ auto pred = [&path] (const QString &f) { return !f.startsWith(path, Qt::CaseInsensitive); };
+ std::remove_copy_if(files.cbegin(), files.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ std::remove_copy_if(directories.cbegin(), directories.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ if (!pathsToBeRemoved.isEmpty()) {
+ q->removePaths(pathsToBeRemoved);
+ temporarilyRemovedPaths.insert(path.at(0), pathsToBeRemoved);
+ }
+}
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive failed (blocked by other
+ // application), restore the watched paths.
+ Q_Q(QFileSystemWatcher);
+ if (!path.isEmpty()) {
+ const auto it = temporarilyRemovedPaths.find(path.at(0));
+ if (it != temporarilyRemovedPaths.end()) {
+ q->addPaths(it.value());
+ temporarilyRemovedPaths.erase(it);
+ }
+ }
+}
+void QFileSystemWatcherPrivate::_q_winDriveRemoved(const QString &path)
+{
+ // Windows: Drive finally removed, clear out paths stored in lock request.
+ if (!path.isEmpty())
+ temporarilyRemovedPaths.remove(path.at(0));
+}
+#endif // Q_OS_WIN && !Q_OS_WINRT
/*!
\class QFileSystemWatcher
diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h
index 6c64411f92..4220c1db28 100644
--- a/src/corelib/io/qfilesystemwatcher_p.h
+++ b/src/corelib/io/qfilesystemwatcher_p.h
@@ -58,6 +58,7 @@
#include <private/qobject_p.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,15 @@ public:
// private slots
void _q_fileChanged(const QString &path, bool removed);
void _q_directoryChanged(const QString &path, bool removed);
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ void _q_winDriveLockForRemoval(const QString &);
+ void _q_winDriveLockForRemovalFailed(const QString &);
+ void _q_winDriveRemoved(const QString &);
+
+private:
+ QHash<QChar, QStringList> temporarilyRemovedPaths;
+#endif // Q_OS_WIN && !Q_OS_WINRT
};
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index be56d8dd1d..c385a82fc5 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -52,6 +52,16 @@
#include <qt_windows.h>
+#ifndef Q_OS_WINRT
+# include <qabstractnativeeventfilter.h>
+# include <qcoreapplication.h>
+# include <qdir.h>
+# include <private/qeventdispatcher_win_p.h>
+# include <dbt.h>
+# include <algorithm>
+# include <vector>
+#endif // !Q_OS_WINRT
+
QT_BEGIN_NAMESPACE
// #define WINQFSW_DEBUG
@@ -61,11 +71,275 @@ QT_BEGIN_NAMESPACE
# define DEBUG if (false) qDebug
#endif
+#ifndef Q_OS_WINRT
+///////////
+// QWindowsRemovableDriveListener
+// Listen for the various WM_DEVICECHANGE message indicating drive addition/removal
+// requests and removals.
+///////////
+class QWindowsRemovableDriveListener : public QObject, public QAbstractNativeEventFilter
+{
+ Q_OBJECT
+public:
+ // Device UUids as declared in ioevent.h (GUID_IO_VOLUME_LOCK, ...)
+ enum VolumeUuid { UnknownUuid, UuidIoVolumeLock, UuidIoVolumeLockFailed,
+ UuidIoVolumeUnlock, UuidIoMediaRemoval };
+
+ struct RemovableDriveEntry {
+ HDEVNOTIFY devNotify;
+ wchar_t drive;
+ };
+
+ explicit QWindowsRemovableDriveListener(QObject *parent = nullptr);
+ ~QWindowsRemovableDriveListener();
+
+ // Call from QFileSystemWatcher::addPaths() to set up notifications on drives
+ void addPath(const QString &path);
+
+ bool nativeEventFilter(const QByteArray &, void *messageIn, long *) override;
+
+signals:
+ void driveAdded();
+ void driveRemoved(const QString &);
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+
+private:
+ static VolumeUuid volumeUuid(const UUID &needle);
+ void handleDbtCustomEvent(const MSG *msg);
+ void handleDbtDriveArrivalRemoval(const MSG *msg);
+
+ std::vector<RemovableDriveEntry> m_removableDrives;
+ quintptr m_lastMessageHash;
+};
+
+static inline QEventDispatcherWin32 *winEventDispatcher()
+{
+ return static_cast<QEventDispatcherWin32 *>(QCoreApplication::instance()->eventDispatcher());
+}
+
+QWindowsRemovableDriveListener::QWindowsRemovableDriveListener(QObject *parent)
+ : QObject(parent)
+ , m_lastMessageHash(0)
+{
+ winEventDispatcher()->installNativeEventFilter(this);
+}
+
+static void stopDeviceNotification(QWindowsRemovableDriveListener::RemovableDriveEntry &e)
+{
+ UnregisterDeviceNotification(e.devNotify);
+ e.devNotify = 0;
+}
+
+template <class Iterator> // Search sequence of RemovableDriveEntry for HDEVNOTIFY.
+static inline Iterator findByHDevNotify(Iterator i1, Iterator i2, HDEVNOTIFY hdevnotify)
+{
+ return std::find_if(i1, i2,
+ [hdevnotify] (const QWindowsRemovableDriveListener::RemovableDriveEntry &e) { return e.devNotify == hdevnotify; });
+}
+
+QWindowsRemovableDriveListener::~QWindowsRemovableDriveListener()
+{
+ std::for_each(m_removableDrives.begin(), m_removableDrives.end(), stopDeviceNotification);
+}
+
+static QString pathFromEntry(const QWindowsRemovableDriveListener::RemovableDriveEntry &re)
+{
+ QString path = QStringLiteral("A:/");
+ path[0] = QChar::fromLatin1(re.drive);
+ return path;
+}
+
+// Handle WM_DEVICECHANGE+DBT_CUSTOMEVENT, which is sent based on the registration
+// on the volume handle with QEventDispatcherWin32's message window in the class.
+// Capture the GUID_IO_VOLUME_LOCK indicating the drive is to be removed.
+QWindowsRemovableDriveListener::VolumeUuid QWindowsRemovableDriveListener::volumeUuid(const UUID &needle)
+{
+ static const struct VolumeUuidMapping // UUIDs from IoEvent.h (missing in MinGW)
+ {
+ VolumeUuid v;
+ UUID uuid;
+ } mapping[] = {
+ { UuidIoVolumeLock, // GUID_IO_VOLUME_LOCK
+ {0x50708874, 0xc9af, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeLockFailed, // GUID_IO_VOLUME_LOCK_FAILED
+ {0xae2eed10, 0x0ba8, 0x11d2, {0x8f, 0xfb, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeUnlock, // GUID_IO_VOLUME_UNLOCK
+ {0x9a8c3d68, 0xd0cb, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoMediaRemoval, // GUID_IO_MEDIA_REMOVAL
+ {0xd07433c1, 0xa98e, 0x11d2, {0x91, 0x7a, 0x0, 0xa0, 0xc9, 0x06, 0x8f, 0xf3}} }
+ };
+
+ static const VolumeUuidMapping *end = mapping + sizeof(mapping) / sizeof(mapping[0]);
+ const VolumeUuidMapping *m =
+ std::find_if(mapping, end, [&needle] (const VolumeUuidMapping &m) { return IsEqualGUID(m.uuid, needle); });
+ return m != end ? m->v : UnknownUuid;
+}
+
+inline void QWindowsRemovableDriveListener::handleDbtCustomEvent(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ if (broadcastHeader->dbch_devicetype != DBT_DEVTYP_HANDLE)
+ return;
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ broadcastHandle->dbch_hdevnotify);
+ if (it == m_removableDrives.cend())
+ return;
+ switch (volumeUuid(broadcastHandle->dbch_eventguid)) {
+ case UuidIoVolumeLock: // Received for removable USB media
+ emit driveLockForRemoval(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeLockFailed:
+ emit driveLockForRemovalFailed(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeUnlock:
+ break;
+ case UuidIoMediaRemoval: // Received for optical drives
+ break;
+ default:
+ break;
+ }
+}
+
+// Handle WM_DEVICECHANGE+DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE which are
+// sent to all top level windows and cannot be registered for (that is, their
+// triggering depends on top level windows being present)
+inline void QWindowsRemovableDriveListener::handleDbtDriveArrivalRemoval(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ switch (broadcastHeader->dbch_devicetype) {
+ case DBT_DEVTYP_HANDLE: // WM_DEVICECHANGE/DBT_DEVTYP_HANDLE is sent for our registered drives.
+ if (msg->wParam == DBT_DEVICEREMOVECOMPLETE) {
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.begin(), m_removableDrives.end(),
+ broadcastHandle->dbch_hdevnotify);
+ // Emit for removable USB drives we were registered for.
+ if (it != m_removableDrives.end()) {
+ emit driveRemoved(pathFromEntry(*it));
+ stopDeviceNotification(*it);
+ m_removableDrives.erase(it);
+ }
+ }
+ break;
+ case DBT_DEVTYP_VOLUME: {
+ const DEV_BROADCAST_VOLUME *broadcastVolume = reinterpret_cast<const DEV_BROADCAST_VOLUME *>(broadcastHeader);
+ // WM_DEVICECHANGE/DBT_DEVTYP_VOLUME messages are sent to all toplevel windows. Compare a hash value to ensure
+ // it is handled only once.
+ const quintptr newHash = reinterpret_cast<quintptr>(broadcastVolume) + msg->wParam
+ + quintptr(broadcastVolume->dbcv_flags) + quintptr(broadcastVolume->dbcv_unitmask);
+ if (newHash == m_lastMessageHash)
+ return;
+ m_lastMessageHash = newHash;
+ // Check for DBTF_MEDIA (inserted/Removed Optical drives). Ignore for now.
+ if (broadcastVolume->dbcv_flags & DBTF_MEDIA)
+ return;
+ // Continue with plugged in USB media where dbcv_flags=0.
+ switch (msg->wParam) {
+ case DBT_DEVICEARRIVAL:
+ emit driveAdded();
+ break;
+ case DBT_DEVICEREMOVECOMPLETE: // handled by DBT_DEVTYP_HANDLE above
+ break;
+ }
+ }
+ break;
+ }
+}
+
+bool QWindowsRemovableDriveListener::nativeEventFilter(const QByteArray &, void *messageIn, long *)
+{
+ const MSG *msg = reinterpret_cast<const MSG *>(messageIn);
+ if (msg->message == WM_DEVICECHANGE) {
+ switch (msg->wParam) {
+ case DBT_CUSTOMEVENT:
+ handleDbtCustomEvent(msg);
+ break;
+ case DBT_DEVICEARRIVAL:
+ case DBT_DEVICEREMOVECOMPLETE:
+ handleDbtDriveArrivalRemoval(msg);
+ break;
+ }
+ }
+ return false;
+}
+
+// Set up listening for WM_DEVICECHANGE+DBT_CUSTOMEVENT for a removable drive path,
+void QWindowsRemovableDriveListener::addPath(const QString &p)
+{
+ const wchar_t drive = p.size() >= 2 && p.at(0).isLetter() && p.at(1) == QLatin1Char(':')
+ ? wchar_t(p.at(0).toUpper().unicode()) : L'\0';
+ if (!drive)
+ return;
+ // Already listening?
+ if (std::any_of(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ [drive](const RemovableDriveEntry &e) { return e.drive == drive; })) {
+ return;
+ }
+
+ wchar_t devicePath[8] = L"\\\\.\\A:\\";
+ devicePath[4] = drive;
+ RemovableDriveEntry re;
+ re.drive = drive;
+ if (GetDriveTypeW(devicePath + 4) != DRIVE_REMOVABLE)
+ return;
+ const HANDLE volumeHandle =
+ CreateFile(devicePath, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, // Volume requires BACKUP_SEMANTICS
+ 0);
+ if (volumeHandle == INVALID_HANDLE_VALUE) {
+ qErrnoWarning("CreateFile %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ DEV_BROADCAST_HANDLE notify;
+ ZeroMemory(&notify, sizeof(notify));
+ notify.dbch_size = sizeof(notify);
+ notify.dbch_devicetype = DBT_DEVTYP_HANDLE;
+ notify.dbch_handle = volumeHandle;
+ re.devNotify = RegisterDeviceNotification(winEventDispatcher()->internalHwnd(),
+ &notify, DEVICE_NOTIFY_WINDOW_HANDLE);
+ // Empirically found: The notifications also work when the handle is immediately
+ // closed. Do it here to avoid having to close/reopen in lock message handling.
+ CloseHandle(volumeHandle);
+ if (!re.devNotify) {
+ qErrnoWarning("RegisterDeviceNotification %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ m_removableDrives.push_back(re);
+}
+#endif // !Q_OS_WINRT
+
+///////////
+// QWindowsFileSystemWatcherEngine
+///////////
QWindowsFileSystemWatcherEngine::Handle::Handle()
: handle(INVALID_HANDLE_VALUE), flags(0u)
{
}
+QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent)
+ : QFileSystemWatcherEngine(parent)
+#ifndef Q_OS_WINRT
+ , m_driveListener(new QWindowsRemovableDriveListener(this))
+#endif
+{
+#ifndef Q_OS_WINRT
+ parent->setProperty("_q_driveListener",
+ QVariant::fromValue(static_cast<QObject *>(m_driveListener)));
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemoval,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemoval);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemovalFailed,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveRemoved,
+ this, &QWindowsFileSystemWatcherEngine::driveRemoved);
+#endif // !Q_OS_WINRT
+}
+
QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
{
for (auto *thread : qAsConst(threads))
@@ -210,6 +484,13 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
}
}
}
+
+#ifndef Q_OS_WINRT
+ for (const QString &path : paths) {
+ if (!p.contains(path))
+ m_driveListener->addPath(path);
+ }
+#endif // !Q_OS_WINRT
return p;
}
@@ -439,4 +720,9 @@ void QWindowsFileSystemWatcherEngineThread::wakeup()
}
QT_END_NAMESPACE
+
+#ifndef Q_OS_WINRT
+# include "qfilesystemwatcher_win.moc"
+#endif
+
#endif // QT_NO_FILESYSTEMWATCHER
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index e8f5c49dec..51c7082483 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -66,6 +66,7 @@
QT_BEGIN_NAMESPACE
class QWindowsFileSystemWatcherEngineThread;
+class QWindowsRemovableDriveListener;
// Even though QWindowsFileSystemWatcherEngine is derived of QThread
// via QFileSystemWatcher, it does not start a thread.
@@ -75,9 +76,7 @@ class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine
{
Q_OBJECT
public:
- inline QWindowsFileSystemWatcherEngine(QObject *parent)
- : QFileSystemWatcherEngine(parent)
- { }
+ explicit QWindowsFileSystemWatcherEngine(QObject *parent);
~QWindowsFileSystemWatcherEngine();
QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
@@ -121,9 +120,17 @@ public:
|| lastModified != fileInfo.lastModified());
}
};
+
+signals:
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+ void driveRemoved(const QString &);
+
private:
QList<QWindowsFileSystemWatcherEngineThread *> threads;
-
+#ifndef Q_OS_WINRT
+ QWindowsRemovableDriveListener *m_driveListener;
+#endif
};
class QFileSystemWatcherPathKey : public QString
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index f8e31ed92b..e152b035e2 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -144,7 +144,7 @@ static inline bool setCloseOnExec(int fd)
static inline QString msgOpenDirectory()
{
const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory");
-#ifndef QT_BOOTSTRAPPED
+#if QT_CONFIG(translation)
return QIODevice::tr(message);
#else
return QLatin1String(message);
@@ -629,7 +629,7 @@ QString QFSFileEngine::fileName(FileName file) const
bool QFSFileEngine::isRelativePath() const
{
Q_D(const QFSFileEngine);
- return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true;
+ return d->fileEntry.filePath().length() ? d->fileEntry.filePath().at(0) != QLatin1Char('/') : true;
}
uint QFSFileEngine::ownerId(FileOwner own) const
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index e427b62136..7d16e59195 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -108,6 +108,20 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
{
Q_Q(QFSFileEngine);
+ // Check if the file name is valid:
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
+ const QString fileName = fileEntry.fileName();
+ for (QString::const_iterator it = fileName.constBegin(), end = fileName.constEnd();
+ it != end; ++it) {
+ const QChar c = *it;
+ if (c == QLatin1Char('<') || c == QLatin1Char('>') || c == QLatin1Char(':') ||
+ c == QLatin1Char('\"') || c == QLatin1Char('/') || c == QLatin1Char('\\') ||
+ c == QLatin1Char('|') || c == QLatin1Char('?') || c == QLatin1Char('*')) {
+ q->setError(QFile::OpenError, QStringLiteral("Invalid file name"));
+ return false;
+ }
+ }
+
// All files are opened in share mode (both read and write).
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
@@ -850,7 +864,6 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
QFile::MemoryMapFlags flags)
{
-#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
if (openMode == QFile::NotOpen) {
@@ -960,18 +973,11 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
::CloseHandle(mapHandle);
mapHandle = NULL;
-#else // !Q_OS_WINPHONE
- Q_UNUSED(offset);
- Q_UNUSED(size);
- Q_UNUSED(flags);
- Q_UNIMPLEMENTED();
-#endif // Q_OS_WINPHONE
return 0;
}
bool QFSFileEnginePrivate::unmap(uchar *ptr)
{
-#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
if (!maps.contains(ptr)) {
q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
@@ -990,11 +996,6 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
}
return true;
-#else // !Q_OS_WINPHONE
- Q_UNUSED(ptr);
- Q_UNIMPLEMENTED();
- return false;
-#endif // Q_OS_WINPHONE
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 5a02741727..ccc607afd5 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -115,6 +115,7 @@ int QLockFilePrivate::checkFcntlWorksAfterFlock(const QString &fn)
return 0;
return 1;
#else
+ Q_UNUSED(fn);
return 0;
#endif
}
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index 77a8c891b4..47fb1fb6b8 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -186,9 +186,10 @@ void QLoggingRule::parse(const QStringRef &pattern)
*/
void QLoggingSettingsParser::setContent(const QString &content)
{
- QString content_ = content;
- QTextStream stream(&content_, QIODevice::ReadOnly);
- setContent(stream);
+ _rules.clear();
+ const auto lines = content.splitRef(QLatin1Char('\n'));
+ for (const auto &line : lines)
+ parseNextLine(line);
}
/*!
@@ -198,42 +199,50 @@ void QLoggingSettingsParser::setContent(const QString &content)
void QLoggingSettingsParser::setContent(QTextStream &stream)
{
_rules.clear();
- while (!stream.atEnd()) {
- QString line = stream.readLine();
-
- // Remove all whitespace from line
- line = line.simplified();
- line.remove(QLatin1Char(' '));
+ QString line;
+ while (stream.readLineInto(&line))
+ parseNextLine(QStringRef(&line));
+}
- // comment
- if (line.startsWith(QLatin1Char(';')))
- continue;
+/*!
+ \internal
+ Parses one line of the configuation file
+*/
- if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
- // new section
- _section = line.mid(1, line.size() - 2);
- continue;
- }
+void QLoggingSettingsParser::parseNextLine(QStringRef line)
+{
+ // Remove whitespace at start and end of line:
+ line = line.trimmed();
+
+ // comment
+ if (line.startsWith(QLatin1Char(';')))
+ return;
+
+ if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
+ // new section
+ auto sectionName = line.mid(1, line.size() - 2).trimmed();
+ m_inRulesSection = sectionName.compare(QLatin1String("rules"), Qt::CaseInsensitive) == 0;
+ return;
+ }
- if (_section.toLower() == QLatin1String("rules")) {
- int equalPos = line.indexOf(QLatin1Char('='));
- if (equalPos != -1) {
- if (line.lastIndexOf(QLatin1Char('=')) == equalPos) {
- const QStringRef pattern = line.leftRef(equalPos);
- const QStringRef valueStr = line.midRef(equalPos + 1);
- int value = -1;
- if (valueStr == QLatin1String("true"))
- value = 1;
- else if (valueStr == QLatin1String("false"))
- value = 0;
- QLoggingRule rule(pattern, (value == 1));
- if (rule.flags != 0 && (value != -1))
- _rules.append(rule);
- else
- warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
- } else {
+ if (m_inRulesSection) {
+ int equalPos = line.indexOf(QLatin1Char('='));
+ if (equalPos != -1) {
+ if (line.lastIndexOf(QLatin1Char('=')) == equalPos) {
+ const auto pattern = line.left(equalPos).trimmed();
+ const auto valueStr = line.mid(equalPos + 1).trimmed();
+ int value = -1;
+ if (valueStr == QLatin1String("true"))
+ value = 1;
+ else if (valueStr == QLatin1String("false"))
+ value = 0;
+ QLoggingRule rule(pattern, (value == 1));
+ if (rule.flags != 0 && (value != -1))
+ _rules.append(rule);
+ else
warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
- }
+ } else {
+ warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
}
}
}
@@ -286,7 +295,7 @@ void QLoggingRegistry::init()
if (!rulesSrc.isEmpty()) {
QTextStream stream(rulesSrc);
QLoggingSettingsParser parser;
- parser.setSection(QStringLiteral("Rules"));
+ parser.setImplicitRulesSection(true);
parser.setContent(stream);
er += parser.rules();
}
@@ -350,7 +359,7 @@ void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
void QLoggingRegistry::setApiRules(const QString &content)
{
QLoggingSettingsParser parser;
- parser.setSection(QStringLiteral("Rules"));
+ parser.setImplicitRulesSection(true);
parser.setContent(content);
if (qtLoggingDebug())
@@ -371,7 +380,12 @@ void QLoggingRegistry::setApiRules(const QString &content)
*/
void QLoggingRegistry::updateRules()
{
- rules = qtConfigRules + configRules + apiRules + envRules;
+ rules.clear();
+ rules.reserve(qtConfigRules.size() + configRules.size() + apiRules.size() + envRules.size()),
+ rules += qtConfigRules;
+ rules += configRules;
+ rules += apiRules;
+ rules += envRules;
for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it)
(*categoryFilter)(*it);
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index 23740c4955..69fc6ea4ec 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -93,7 +93,7 @@ Q_DECLARE_TYPEINFO(QLoggingRule, Q_MOVABLE_TYPE);
class Q_AUTOTEST_EXPORT QLoggingSettingsParser
{
public:
- void setSection(const QString &section) { _section = section; }
+ void setImplicitRulesSection(bool inRulesSection) { m_inRulesSection = inRulesSection; }
void setContent(const QString &content);
void setContent(QTextStream &stream);
@@ -101,7 +101,10 @@ public:
QVector<QLoggingRule> rules() const { return _rules; }
private:
- QString _section;
+ void parseNextLine(QStringRef line);
+
+private:
+ bool m_inRulesSection = false;
QVector<QLoggingRule> _rules;
};
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index fd340ca607..c0ec35ff32 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -428,6 +428,8 @@ void QProcessEnvironment::insert(const QProcessEnvironment &e)
d->insert(*e.d);
}
+#if QT_CONFIG(process)
+
void QProcessPrivate::Channel::clear()
{
switch (type) {
@@ -1527,7 +1529,7 @@ void QProcess::setStandardOutputProcess(QProcess *destination)
dto->stdinChannel.pipeFrom(dfrom);
}
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
/*!
\since 4.7
@@ -2599,6 +2601,8 @@ QString QProcess::nullDevice()
\sa QProcess::pid()
*/
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#include "moc_qprocess.cpp"
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 67c163c012..19157bdd02 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -46,11 +46,13 @@
#include <functional>
-QT_REQUIRE_CONFIG(process);
+QT_REQUIRE_CONFIG(processenvironment);
QT_BEGIN_NAMESPACE
-#if !defined(Q_OS_WIN) || defined(Q_QDOC)
+class QProcessPrivate;
+
+#if !defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
typedef qint64 Q_PID;
#else
QT_END_NAMESPACE
@@ -60,7 +62,6 @@ typedef struct _STARTUPINFOW Q_STARTUPINFO;
QT_BEGIN_NAMESPACE
#endif
-class QProcessPrivate;
class QProcessEnvironmentPrivate;
class Q_CORE_EXPORT QProcessEnvironment
@@ -104,6 +105,8 @@ private:
Q_DECLARE_SHARED(QProcessEnvironment)
+#if QT_CONFIG(process)
+
class Q_CORE_EXPORT QProcess : public QIODevice
{
Q_OBJECT
@@ -186,7 +189,7 @@ public:
void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate);
void setStandardOutputProcess(QProcess *destination);
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
QString nativeArguments() const;
void setNativeArguments(const QString &arguments);
struct CreateProcessArguments
@@ -205,7 +208,7 @@ public:
typedef std::function<void(CreateProcessArguments *)> CreateProcessArgumentModifier;
CreateProcessArgumentModifier createProcessArgumentsModifier() const;
void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier);
-#endif // Q_OS_WIN
+#endif // Q_OS_WIN || Q_CLANG_QDOC
QString workingDirectory() const;
void setWorkingDirectory(const QString &dir);
@@ -297,6 +300,8 @@ private:
friend class QProcessManager;
};
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#endif // QPROCESS_H
diff --git a/src/corelib/io/qprocess_darwin.mm b/src/corelib/io/qprocess_darwin.mm
new file mode 100644
index 0000000000..dd7a8275b9
--- /dev/null
+++ b/src/corelib/io/qprocess_darwin.mm
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <private/qprocess_p.h>
+
+#import <Foundation/Foundation.h>
+
+QT_BEGIN_NAMESPACE
+
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ __block QProcessEnvironment env;
+ [[[NSProcessInfo processInfo] environment]
+ enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *__unused stop) {
+ env.d->hash.insert(
+ QProcessEnvironmentPrivate::Key(QString::fromNSString(name).toLocal8Bit()),
+ QProcessEnvironmentPrivate::Value(QString::fromNSString(value).toLocal8Bit()));
+ }];
+ return env;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index 250eeb5de6..6e0630eb66 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -58,7 +58,7 @@
#include "QtCore/qshareddata.h"
#include "private/qiodevice_p.h"
-QT_REQUIRE_CONFIG(process);
+QT_REQUIRE_CONFIG(processenvironment);
#ifdef Q_OS_UNIX
#include <QtCore/private/qorderedmutexlocker_p.h>
@@ -234,6 +234,8 @@ template<> Q_INLINE_TEMPLATE void QSharedDataPointer<QProcessEnvironmentPrivate>
d = x;
}
+#if QT_CONFIG(process)
+
class QProcessPrivate : public QIODevicePrivate
{
public:
@@ -387,6 +389,8 @@ public:
void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());
};
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#endif // QPROCESS_P_H
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 03e2c0c4ce..b822417ddf 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -41,7 +41,7 @@
//#define QPROCESS_DEBUG
#include "qdebug.h"
-#if defined QPROCESS_DEBUG
+#if QT_CONFIG(process) && defined(QPROCESS_DEBUG)
#include "private/qtools_p.h"
#include <ctype.h>
@@ -112,10 +112,40 @@ QT_END_NAMESPACE
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+
+#if QT_CONFIG(process)
#include <forkfd.h>
+#endif
QT_BEGIN_NAMESPACE
+#if !defined(Q_OS_DARWIN)
+
+QT_BEGIN_INCLUDE_NAMESPACE
+extern char **environ;
+QT_END_INCLUDE_NAMESPACE
+
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ QProcessEnvironment env;
+ const char *entry;
+ for (int count = 0; (entry = environ[count]); ++count) {
+ const char *equal = strchr(entry, '=');
+ if (!equal)
+ continue;
+
+ QByteArray name(entry, equal - entry);
+ QByteArray value(equal + 1);
+ env.d->hash.insert(QProcessEnvironmentPrivate::Key(name),
+ QProcessEnvironmentPrivate::Value(value));
+ }
+ return env;
+}
+
+#endif // !defined(Q_OS_DARWIN)
+
+#if QT_CONFIG(process)
+
// POSIX requires PIPE_BUF to be 512 or larger
// so we will use 512
static const int errorBufferMax = 512;
@@ -308,34 +338,6 @@ bool QProcessPrivate::openChannel(Channel &channel)
}
}
-QT_BEGIN_INCLUDE_NAMESPACE
-#if defined(Q_OS_MACX)
-# include <crt_externs.h>
-# define environ (*_NSGetEnviron())
-#else
- extern char **environ;
-#endif
-QT_END_INCLUDE_NAMESPACE
-
-QProcessEnvironment QProcessEnvironment::systemEnvironment()
-{
- QProcessEnvironment env;
-#if !defined(QT_PLATFORM_UIKIT)
- const char *entry;
- for (int count = 0; (entry = environ[count]); ++count) {
- const char *equal = strchr(entry, '=');
- if (!equal)
- continue;
-
- QByteArray name(entry, equal - entry);
- QByteArray value(equal + 1);
- env.d->hash.insert(QProcessEnvironmentPrivate::Key(name),
- QProcessEnvironmentPrivate::Value(value));
- }
-#endif
- return env;
-}
-
static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environment, int *envc)
{
*envc = 0;
@@ -1042,4 +1044,6 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
return success;
}
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 6dd431eb47..329d1842f0 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -38,6 +38,7 @@
**
****************************************************************************/
+//#define QPROCESS_DEBUG
#include "qprocess.h"
#include "qprocess_p.h"
#include "qwindowspipereader_p.h"
@@ -61,7 +62,29 @@
QT_BEGIN_NAMESPACE
-//#define QPROCESS_DEBUG
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ QProcessEnvironment env;
+ // Calls to setenv() affect the low-level environment as well.
+ // This is not the case the other way round.
+ if (wchar_t *envStrings = GetEnvironmentStringsW()) {
+ for (const wchar_t *entry = envStrings; *entry; ) {
+ const int entryLen = int(wcslen(entry));
+ // + 1 to permit magic cmd variable names starting with =
+ if (const wchar_t *equal = wcschr(entry + 1, L'=')) {
+ int nameLen = equal - entry;
+ QString name = QString::fromWCharArray(entry, nameLen);
+ QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
+ env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), value);
+ }
+ entry += entryLen + 1;
+ }
+ FreeEnvironmentStringsW(envStrings);
+ }
+ return env;
+}
+
+#if QT_CONFIG(process)
static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
{
@@ -367,28 +390,6 @@ static QString qt_create_commandline(const QString &program, const QStringList &
return args;
}
-QProcessEnvironment QProcessEnvironment::systemEnvironment()
-{
- QProcessEnvironment env;
- // Calls to setenv() affect the low-level environment as well.
- // This is not the case the other way round.
- if (wchar_t *envStrings = GetEnvironmentStringsW()) {
- for (const wchar_t *entry = envStrings; *entry; ) {
- const int entryLen = int(wcslen(entry));
- // + 1 to permit magic cmd variable names starting with =
- if (const wchar_t *equal = wcschr(entry + 1, L'=')) {
- int nameLen = equal - entry;
- QString name = QString::fromWCharArray(entry, nameLen);
- QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
- env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), value);
- }
- entry += entryLen + 1;
- }
- FreeEnvironmentStringsW(envStrings);
- }
- return env;
-}
-
static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Hash &environment)
{
QByteArray envlist;
@@ -890,4 +891,6 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
return success;
}
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index 0254eb984f..d8166014db 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -104,13 +104,14 @@ QSaveFilePrivate::~QSaveFilePrivate()
\sa QTextStream, QDataStream, QFileInfo, QDir, QFile, QTemporaryFile
*/
-/*!
- Constructs a new file object with the given \a parent.
-*/
-QSaveFile::QSaveFile(QObject *parent)
- : QFileDevice(*new QSaveFilePrivate, parent)
+#ifdef QT_NO_QOBJECT
+QSaveFile::QSaveFile(const QString &name)
+ : QFileDevice(*new QSaveFilePrivate)
{
+ Q_D(QSaveFile);
+ d->fileName = name;
}
+#else
/*!
Constructs a new file object to represent the file with the given \a name.
*/
@@ -120,6 +121,14 @@ QSaveFile::QSaveFile(const QString &name)
Q_D(QSaveFile);
d->fileName = name;
}
+
+/*!
+ Constructs a new file object with the given \a parent.
+*/
+QSaveFile::QSaveFile(QObject *parent)
+ : QFileDevice(*new QSaveFilePrivate, parent)
+{
+}
/*!
Constructs a new file object with the given \a parent to represent the
file with the specified \a name.
@@ -130,6 +139,7 @@ QSaveFile::QSaveFile(const QString &name, QObject *parent)
Q_D(QSaveFile);
d->fileName = name;
}
+#endif
/*!
Destroys the file object, discarding the saved contents unless commit() was called.
diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h
index 10857c27d1..09d6e29272 100644
--- a/src/corelib/io/qsavefile.h
+++ b/src/corelib/io/qsavefile.h
@@ -58,14 +58,18 @@ class QSaveFilePrivate;
class Q_CORE_EXPORT QSaveFile : public QFileDevice
{
+#ifndef QT_NO_QOBJECT
Q_OBJECT
+#endif
Q_DECLARE_PRIVATE(QSaveFile)
public:
explicit QSaveFile(const QString &name);
+#ifndef QT_NO_QOBJECT
explicit QSaveFile(QObject *parent = Q_NULLPTR);
explicit QSaveFile(const QString &name, QObject *parent);
+#endif
~QSaveFile();
QString fileName() const Q_DECL_OVERRIDE;
@@ -84,6 +88,9 @@ protected:
private:
void close() Q_DECL_OVERRIDE;
+#if !QT_CONFIG(translation)
+ static QString tr(const char *string) { return QString::fromLatin1(string); }
+#endif
private:
Q_DISABLE_COPY(QSaveFile)
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index e12da68671..16dab38a60 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -128,7 +128,18 @@ Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
typedef QHash<QString, QConfFile *> ConfFileHash;
typedef QCache<QString, QConfFile> ConfFileCache;
-typedef QHash<int, QString> PathHash;
+namespace {
+ struct Path
+ {
+ // Note: Defining constructors explicitly because of buggy C++11
+ // implementation in MSVC (uniform initialization).
+ Path() {}
+ Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
+ QString path;
+ bool userDefined; //!< true - user defined, overridden by setPath
+ };
+}
+typedef QHash<int, Path> PathHash;
typedef QVector<QConfFileCustomFormat> CustomFormatVector;
Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
@@ -220,7 +231,7 @@ void QConfFile::clearCache()
// QSettingsPrivate
QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
- : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), spec(0), fallbacks(true),
+ : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true),
pendingChanges(false), status(QSettings::NoError)
{
}
@@ -228,7 +239,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
: format(format), scope(scope), organizationName(organization), applicationName(application),
- iniCodec(0), spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
+ iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
{
}
@@ -940,7 +951,7 @@ void QConfFileSettingsPrivate::initFormat()
void QConfFileSettingsPrivate::initAccess()
{
- if (confFiles[spec]) {
+ if (!confFiles.isEmpty()) {
if (format > QSettings::IniFormat) {
if (!readFunc)
setStatus(QSettings::AccessError);
@@ -1070,22 +1081,22 @@ static void initDefaultPaths(QMutexLocker *locker)
const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
# endif
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
- roamingAppDataFolder + QDir::separator());
+ Path(roamingAppDataFolder + QDir::separator(), false));
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
- programDataFolder + QDir::separator());
+ Path(programDataFolder + QDir::separator(), false));
#else
const QString userPath = make_user_path();
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
#ifndef Q_OS_MAC
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
#endif
#endif // Q_OS_WIN
}
}
-static QString getPath(QSettings::Format format, QSettings::Scope scope)
+static Path getPath(QSettings::Format format, QSettings::Scope scope)
{
Q_ASSERT((int)QSettings::NativeFormat == 0);
Q_ASSERT((int)QSettings::IniFormat == 1);
@@ -1095,14 +1106,23 @@ static QString getPath(QSettings::Format format, QSettings::Scope scope)
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- QString result = pathHash->value(pathHashKey(format, scope));
- if (!result.isEmpty())
+ Path result = pathHash->value(pathHashKey(format, scope));
+ if (!result.path.isEmpty())
return result;
// fall back on INI path
return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
}
+#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+// Note: Suitable only for autotests.
+void Q_AUTOTEST_EXPORT clearDefaultPaths()
+{
+ QMutexLocker locker(&settingsGlobalMutex);
+ pathHashFunc()->clear();
+}
+#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+
QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QSettings::Scope scope,
const QString &organization,
@@ -1110,7 +1130,6 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
: QSettingsPrivate(format, scope, organization, application),
nextPosition(0x40000000) // big positive number
{
- int i;
initFormat();
QString org = organization;
@@ -1123,22 +1142,43 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QString orgFile = org + extension;
if (scope == QSettings::UserScope) {
- QString userPath = getPath(format, QSettings::UserScope);
+ Path userPath = getPath(format, QSettings::UserScope);
if (!application.isEmpty())
- confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true));
- confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
}
- QString systemPath = getPath(format, QSettings::SystemScope);
- if (!application.isEmpty())
- confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false));
- confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false));
-
- for (i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i]) {
- spec = i;
- break;
+ Path systemPath = getPath(format, QSettings::SystemScope);
+#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+ // check if the systemPath wasn't overridden by QSettings::setPath()
+ if (!systemPath.userDefined) {
+ // Note: We can't use QStandardPaths::locateAll() as we need all the
+ // possible files (not just the existing ones) and there is no way
+ // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
+ QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
+ // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
+ if (!dirs.isEmpty())
+ dirs.takeFirst();
+ QStringList paths;
+ if (!application.isEmpty()) {
+ paths.reserve(dirs.size() * 2);
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + appFile);
+ } else {
+ paths.reserve(dirs.size());
}
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + orgFile);
+
+ // Note: No check for existence of files is done intentionaly.
+ for (const auto &path : qAsConst(paths))
+ confFiles.append(QConfFile::fromName(path, false));
+ } else
+#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+ {
+ if (!application.isEmpty())
+ confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
+ confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
}
initAccess();
@@ -1151,7 +1191,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
{
initFormat();
- confFiles[0].reset(QConfFile::fromName(fileName, true));
+ confFiles.append(QConfFile::fromName(fileName, true));
initAccess();
}
@@ -1162,40 +1202,39 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i] && !confFiles[i]->ref.deref()) {
- if (confFiles[i]->size == 0) {
- delete confFiles[i].take();
+ for (auto conf_file : qAsConst(confFiles)) {
+ if (!conf_file->ref.deref()) {
+ if (conf_file->size == 0) {
+ delete conf_file;
} else {
if (usedHash)
- usedHash->remove(confFiles[i]->name);
+ usedHash->remove(conf_file->name);
if (unusedCache) {
QT_TRY {
// compute a better size?
- unusedCache->insert(confFiles[i]->name, confFiles[i].data(),
- 10 + (confFiles[i]->originalKeys.size() / 4));
- confFiles[i].take();
+ unusedCache->insert(conf_file->name, conf_file,
+ 10 + (conf_file->originalKeys.size() / 4));
} QT_CATCH(...) {
// out of memory. Do not cache the file.
- delete confFiles[i].take();
+ delete conf_file;
}
} else {
// unusedCache is gone - delete the entry to prevent a memory leak
- delete confFiles[i].take();
+ delete conf_file;
}
}
}
- // prevent the ScopedPointer to deref it again.
- confFiles[i].take();
}
}
void QConfFileSettingsPrivate::remove(const QString &key)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity);
QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
QMutexLocker locker(&confFile->mutex);
@@ -1219,10 +1258,12 @@ void QConfFileSettingsPrivate::remove(const QString &key)
void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity, nextPosition++);
QMutexLocker locker(&confFile->mutex);
confFile->removedKeys.remove(theKey);
@@ -1235,29 +1276,27 @@ bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
ParsedSettingsMap::const_iterator j;
bool found = false;
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (!confFile->addedKeys.isEmpty()) {
- j = confFile->addedKeys.constFind(theKey);
- found = (j != confFile->addedKeys.constEnd());
- }
- if (!found) {
- ensureSectionParsed(confFile, theKey);
- j = confFile->originalKeys.constFind(theKey);
- found = (j != confFile->originalKeys.constEnd()
- && !confFile->removedKeys.contains(theKey));
- }
+ if (!confFile->addedKeys.isEmpty()) {
+ j = confFile->addedKeys.constFind(theKey);
+ found = (j != confFile->addedKeys.constEnd());
+ }
+ if (!found) {
+ ensureSectionParsed(confFile, theKey);
+ j = confFile->originalKeys.constFind(theKey);
+ found = (j != confFile->originalKeys.constEnd()
+ && !confFile->removedKeys.contains(theKey));
+ }
- if (found && value)
- *value = *j;
+ if (found && value)
+ *value = *j;
- if (found)
- return true;
- if (!fallbacks)
- break;
- }
+ if (found)
+ return true;
+ if (!fallbacks)
+ break;
}
return false;
}
@@ -1270,34 +1309,31 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
QSettingsKey thePrefix(prefix, caseSensitivity);
int startPos = prefix.size();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (thePrefix.isEmpty()) {
- ensureAllSectionsParsed(confFile);
- } else {
- ensureSectionParsed(confFile, thePrefix);
- }
-
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->originalKeys)->lowerBound( thePrefix);
- while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
- if (!confFile->removedKeys.contains(j.key()))
- processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ if (thePrefix.isEmpty())
+ ensureAllSectionsParsed(confFile);
+ else
+ ensureSectionParsed(confFile, thePrefix);
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->addedKeys)->lowerBound(thePrefix);
- while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->originalKeys)->lowerBound( thePrefix);
+ while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ if (!confFile->removedKeys.contains(j.key()))
processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ ++j;
+ }
- if (!fallbacks)
- break;
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->addedKeys)->lowerBound(thePrefix);
+ while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
+ ++j;
}
+
+ if (!fallbacks)
+ break;
}
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()),
@@ -1307,10 +1343,12 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
void QConfFileSettingsPrivate::clear()
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QMutexLocker locker(&confFile->mutex);
ensureAllSectionsParsed(confFile);
confFile->addedKeys.clear();
@@ -1322,12 +1360,9 @@ void QConfFileSettingsPrivate::sync()
// people probably won't be checking the status a whole lot, so in case of
// error we just try to go on and make the best of it
- for (int i = 0; i < NumConfFiles; ++i) {
- QConfFile *confFile = confFiles[i].data();
- if (confFile) {
- QMutexLocker locker(&confFile->mutex);
- syncConfFile(i);
- }
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
+ syncConfFile(confFile);
}
}
@@ -1338,10 +1373,11 @@ void QConfFileSettingsPrivate::flush()
QString QConfFileSettingsPrivate::fileName() const
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return QString();
- return confFile->name;
+
+ // Note: First config file is always the most specific.
+ return confFiles.at(0)->name;
}
bool QConfFileSettingsPrivate::isWritable() const
@@ -1349,16 +1385,14 @@ bool QConfFileSettingsPrivate::isWritable() const
if (format > QSettings::IniFormat && !writeFunc)
return false;
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return false;
- return confFile->isWritable();
+ return confFiles.at(0)->isWritable();
}
-void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
+void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
{
- QConfFile *confFile = confFiles[confFileNo].data();
bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
/*
@@ -2188,9 +2222,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
\li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
- \li \c{/etc/xdg/MySoft/Star Runner.conf}
- \li \c{/etc/xdg/MySoft.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On \macos versions 10.2 and 10.3, these files are used by
default:
@@ -2225,9 +2260,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
\li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
- \li \c{/etc/xdg/MySoft/Star Runner.ini}
- \li \c{/etc/xdg/MySoft.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On Windows, the following files are used:
@@ -3380,7 +3416,7 @@ void QSettings::setPath(Format format, Scope scope, const QString &path)
PathHash *pathHash = pathHashFunc();
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- pathHash->insert(pathHashKey(format, scope), path + QDir::separator());
+ pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
}
/*!
diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp
index 0e3520441e..2a08ee2e64 100644
--- a/src/corelib/io/qsettings_mac.cpp
+++ b/src/corelib/io/qsettings_mac.cpp
@@ -211,7 +211,7 @@ static QCFType<CFPropertyListRef> macValue(const QVariant &value)
default:
QString string = QSettingsPrivate::variantToString(value);
if (string.contains(QChar::Null))
- result = string.toUtf8().toCFData();
+ result = std::move(string).toUtf8().toCFData();
else
result = string.toCFString();
}
@@ -419,25 +419,19 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString &
curPos = nextDot + 1;
}
javaPackageName.prepend(domainName.midRef(curPos));
- javaPackageName = javaPackageName.toLower();
+ javaPackageName = std::move(javaPackageName).toLower();
if (curPos == 0)
javaPackageName.prepend(QLatin1String("com."));
suiteId = javaPackageName;
- if (scope == QSettings::SystemScope)
- spec |= F_System;
-
- if (application.isEmpty()) {
- spec |= F_Organization;
- } else {
- javaPackageName += QLatin1Char('.');
- javaPackageName += application;
+ if (!application.isEmpty()) {
+ javaPackageName += QLatin1Char('.') + application;
applicationId = javaPackageName;
}
numDomains = 0;
- for (int i = (spec & F_System) ? 1 : 0; i < 2; ++i) {
- for (int j = (spec & F_Organization) ? 1 : 0; j < 3; ++j) {
+ for (int i = (scope == QSettings::SystemScope) ? 1 : 0; i < 2; ++i) {
+ for (int j = (application.isEmpty()) ? 1 : 0; j < 3; ++j) {
SearchDomain &domain = domains[numDomains++];
domain.userName = (i == 0) ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser;
if (j == 0)
@@ -578,7 +572,7 @@ bool QMacSettingsPrivate::isWritable() const
QString QMacSettingsPrivate::fileName() const
{
QString result;
- if ((spec & F_System) == 0)
+ if (scope == QSettings::UserScope)
result = QDir::homePath();
result += QLatin1String("/Library/Preferences/");
result += QString::fromCFString(domains[0].applicationOrSuiteId);
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index e6d3413bab..639605d8c4 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -236,19 +236,6 @@ public:
QTextCodec *codec);
static QStringList splitArgs(const QString &s, int idx);
- /*
- The numeric values of these enums define their search order. For example,
- F_User | F_Organization is searched before F_System | F_Application,
- because their values are respectively 1 and 2.
- */
- enum {
- F_Application = 0x0,
- F_Organization = 0x1,
- F_User = 0x0,
- F_System = 0x2,
- NumConfFiles = 4
- };
-
QSettings::Format format;
QSettings::Scope scope;
QString organizationName;
@@ -258,7 +245,6 @@ public:
protected:
QStack<QSettingsGroup> groupStack;
QString groupPrefix;
- int spec;
bool fallbacks;
bool pendingChanges;
mutable QSettings::Status status;
@@ -293,7 +279,7 @@ public:
private:
void initFormat();
void initAccess();
- void syncConfFile(int confFileNo);
+ void syncConfFile(QConfFile *confFile);
bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
#ifdef Q_OS_MAC
bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
@@ -302,7 +288,7 @@ private:
void ensureAllSectionsParsed(QConfFile *confFile) const;
void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
- QScopedSharedPointer<QConfFile> confFiles[NumConfFiles];
+ QVector<QConfFile *> confFiles;
QSettings::ReadFunc readFunc;
QSettings::WriteFunc writeFunc;
QString extension;
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index 1c10548cbc..edcae16776 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -138,21 +138,6 @@ static void mergeKeySets(NameSet *dest, const QStringList &src)
** Wrappers for the insane windows registry API
*/
-static QString errorCodeToString(DWORD errorCode)
-{
- wchar_t *data = 0;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, 0, 0);
- QString result = QString::fromWCharArray(data);
-
- if (data != 0)
- LocalFree(data);
-
- if (result.endsWith(QLatin1Char('\n')))
- result.truncate(result.length() - 1);
-
- return result;
-}
-
// Open a key with the specified "perms".
// "access" is to explicitly use the 32- or 64-bit branch.
static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access = 0)
@@ -184,7 +169,7 @@ static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSub
return resultHandle;
//qWarning("QSettings: Failed to create subkey \"%s\": %s",
- // rSubKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ // qPrintable(rSubKey), qPrintable(qt_error_string(int(res))));
return 0;
}
@@ -224,7 +209,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
&numKeys, &maxKeySize, 0, 0, 0);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegQueryInfoKey() failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegQueryInfoKey() failed: %s", qPrintable(qt_error_string(int(res))));
return result;
}
@@ -258,7 +243,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
item = QString::fromWCharArray((const wchar_t *)buff.constData(), l);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegEnumValue failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegEnumValue failed: %s", qPrintable(qt_error_string(int(res))));
continue;
}
if (item.isEmpty())
@@ -313,7 +298,7 @@ static void deleteChildGroups(HKEY parentHandle, REGSAM access = 0)
LONG res = RegDeleteKey(parentHandle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
return;
}
}
@@ -613,7 +598,7 @@ QWinSettingsPrivate::~QWinSettingsPrivate()
DWORD res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(emptyKey.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: Failed to delete key \"%s\": %s",
- regList.at(0).key().toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(regList.at(0).key()), qPrintable(qt_error_string(int(res))));
}
}
@@ -652,7 +637,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
LONG res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteValue failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
}
}
} else {
@@ -660,7 +645,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on key \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
}
}
RegCloseKey(handle);
@@ -758,7 +743,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
deleteWriteHandleOnExit = false;
} else {
qWarning("QSettings: failed to set subkey \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
setStatus(QSettings::AccessError);
}
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 3773b72606..27f0552a31 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -260,7 +260,7 @@ QByteArray QStorageInfo::fileSystemType() const
devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC
path starting with \c \\\\?\\ for local storages (in other words, the volume GUID).
- \sa rootPath()
+ \sa rootPath(), subvolume()
*/
QByteArray QStorageInfo::device() const
{
@@ -268,6 +268,26 @@ QByteArray QStorageInfo::device() const
}
/*!
+ \since 5.9
+ Returns the subvolume name for this volume.
+
+ Some filesystem types allow multiple subvolumes inside one device, which
+ may be mounted in different paths. If the subvolume could be detected, it
+ is returned here. The format of the subvolume name is specific to each
+ filesystem type.
+
+ If this volume was not mounted from a subvolume of a larger filesystem or
+ if the subvolume could not be detected, this function returns an empty byte
+ array.
+
+ \sa device()
+*/
+QByteArray QStorageInfo::subvolume() const
+{
+ return d->subvolume;
+}
+
+/*!
Returns the human-readable name of a filesystem, usually called \c label.
Not all filesystems support this feature. In this case, the value returned by
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
index 8941c11a16..e2d9747ceb 100644
--- a/src/corelib/io/qstorageinfo.h
+++ b/src/corelib/io/qstorageinfo.h
@@ -71,6 +71,7 @@ public:
QString rootPath() const;
QByteArray device() const;
+ QByteArray subvolume() const;
QByteArray fileSystemType() const;
QString name() const;
QString displayName() const;
@@ -100,7 +101,7 @@ inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
{
if (first.d == second.d)
return true;
- return first.device() == second.device();
+ return first.device() == second.device() && first.rootPath() == second.rootPath();
}
inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
index a14fa8480a..ec5bb785e3 100644
--- a/src/corelib/io/qstorageinfo_p.h
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -85,6 +85,7 @@ protected:
public:
QString rootPath;
QByteArray device;
+ QByteArray subvolume;
QByteArray fileSystemType;
QString name;
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index ae5c42ffd1..b9c9883609 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -120,6 +120,7 @@ public:
inline QString rootPath() const;
inline QByteArray fileSystemType() const;
inline QByteArray device() const;
+ inline QByteArray options() const;
private:
#if defined(Q_OS_BSD4)
QT_STATFSBUF *stat_buf;
@@ -133,6 +134,7 @@ private:
QByteArray m_rootPath;
QByteArray m_fileSystemType;
QByteArray m_device;
+ QByteArray m_options;
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
FILE *fp;
mntent mnt;
@@ -228,6 +230,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(stat_buf[currentIndex].f_mntfromname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#elif defined(Q_OS_SOLARIS)
static const char pathMounted[] = "/etc/mnttab";
@@ -301,6 +308,7 @@ inline bool QStorageIterator::next()
m_device = data.at(0);
m_rootPath = data.at(1);
m_fileSystemType = data.at(2);
+ m_options = data.at(3);
return true;
}
@@ -320,6 +328,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return m_options;
+}
+
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
static const char pathMounted[] = "/etc/mtab";
@@ -363,6 +376,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(mnt.mnt_fsname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray(mnt.mnt_opts);
+}
+
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
{
@@ -420,6 +438,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#else
inline QStorageIterator::QStorageIterator()
@@ -455,7 +478,36 @@ inline QByteArray QStorageIterator::device() const
return QByteArray();
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
+#endif
+
+static QByteArray extractSubvolume(const QStorageIterator &it)
+{
+#ifdef Q_OS_LINUX
+ if (it.fileSystemType() == "btrfs") {
+ const QByteArrayList opts = it.options().split(',');
+ QByteArray id;
+ for (const QByteArray &opt : opts) {
+ static const char subvol[] = "subvol=";
+ static const char subvolid[] = "subvolid=";
+ if (opt.startsWith(subvol))
+ return std::move(opt).mid(strlen(subvol));
+ if (opt.startsWith(subvolid))
+ id = std::move(opt).mid(strlen(subvolid));
+ }
+
+ // if we didn't find the subvolume name, return the subvolume ID
+ return id;
+ }
+#else
+ Q_UNUSED(it);
#endif
+ return QByteArray();
+}
void QStorageInfoPrivate::initRootPath()
{
@@ -483,6 +535,7 @@ void QStorageInfoPrivate::initRootPath()
rootPath = mountDir;
device = it.device();
fileSystemType = fsName;
+ subvolume = extractSubvolume(it);
}
}
}
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
index 6e50a8513e..b2bf9fce97 100644
--- a/src/corelib/io/qtemporarydir.cpp
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -305,6 +305,33 @@ QString QTemporaryDir::path() const
}
/*!
+ \since 5.9
+
+ Returns the path name of a file in the temporary directory.
+ Does \e not check if the file actually exists in the directory.
+ Redundant multiple separators or "." and ".." directories in
+ \a fileName are not removed (see QDir::cleanPath()). Absolute
+ paths are not allowed.
+*/
+QString QTemporaryDir::filePath(const QString &fileName) const
+{
+ if (QDir::isAbsolutePath(fileName)) {
+ qWarning("QTemporaryDir::filePath: Absolute paths are not allowed: %s", qUtf8Printable(fileName));
+ return QString();
+ }
+
+ if (!d_ptr->success)
+ return QString();
+
+ QString ret = d_ptr->pathOrError;
+ if (!fileName.isEmpty()) {
+ ret += QLatin1Char('/');
+ ret += fileName;
+ }
+ return ret;
+}
+
+/*!
Returns \c true if the QTemporaryDir is in auto remove
mode. Auto-remove mode will automatically delete the directory from
disk upon destruction. This makes it very easy to create your
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
index 2e70d34ae4..3f6b70a2eb 100644
--- a/src/corelib/io/qtemporarydir.h
+++ b/src/corelib/io/qtemporarydir.h
@@ -65,6 +65,7 @@ public:
bool remove();
QString path() const;
+ QString filePath(const QString &fileName) const;
private:
QScopedPointer<QTemporaryDirPrivate> d_ptr;
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 4fdb1505ff..9b565bff9d 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -2547,6 +2547,7 @@ QTextStream &QTextStream::operator<<(double f)
}
uint flags = 0;
+ const QLocale::NumberOptions numberOptions = locale().numberOptions();
if (numberFlags() & ShowBase)
flags |= QLocaleData::ShowBase;
if (numberFlags() & ForceSign)
@@ -2555,12 +2556,18 @@ QTextStream &QTextStream::operator<<(double f)
flags |= QLocaleData::UppercaseBase;
if (numberFlags() & UppercaseDigits)
flags |= QLocaleData::CapitalEorX;
- if (numberFlags() & ForcePoint)
- flags |= QLocaleData::Alternate;
- if (locale() != QLocale::c() && !(locale().numberOptions() & QLocale::OmitGroupSeparator))
+ if (numberFlags() & ForcePoint) {
+ flags |= QLocaleData::ForcePoint;
+
+ // Only for backwards compatibility
+ flags |= QLocaleData::AddTrailingZeroes | QLocaleData::ShowBase;
+ }
+ if (locale() != QLocale::c() && !(numberOptions & QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
- if (!(locale().numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
const QLocaleData *dd = d->locale.d->m_data;
QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags);
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 3df7070557..9663235a67 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -3182,8 +3182,7 @@ QUrl QUrl::resolved(const QUrl &relative) const
if (!relative.d) return *this;
QUrl t;
- // Compatibility hack (mostly for qtdeclarative) : treat "file:relative.txt" as relative even though QUrl::isRelative() says false
- if (!relative.d->scheme.isEmpty() && (!relative.isLocalFile() || QDir::isAbsolutePath(relative.d->path))) {
+ if (!relative.d->scheme.isEmpty()) {
t = relative;
t.detach();
} else {
@@ -3419,8 +3418,7 @@ QUrl QUrl::adjusted(QUrl::FormattingOptions options) const
QByteArray QUrl::toEncoded(FormattingOptions options) const
{
options &= ~(FullyDecoded | FullyEncoded);
- QString stringForm = toString(options | FullyEncoded);
- return stringForm.toLatin1();
+ return toString(options | FullyEncoded).toLatin1();
}
/*!
@@ -3537,8 +3535,7 @@ QString QUrl::fromAce(const QByteArray &domain)
*/
QByteArray QUrl::toAce(const QString &domain)
{
- QString result = qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/);
- return result.toLatin1();
+ return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/).toLatin1();
}
/*!
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index a554a3b07e..c16825a033 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -69,8 +69,8 @@ public:
Q_DECL_CONSTEXPR inline QUrlTwoFlags(E1 f) : i(f) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(E2 f) : i(f) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlag f) : i(f) {}
- Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E1> f) : i(f.operator int()) {}
- Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E2> f) : i(f.operator int()) {}
+ Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E1> f) : i(f.operator typename QFlags<E1>::Int()) {}
+ Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E2> f) : i(f.operator typename QFlags<E2>::Int()) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(Zero = 0) : i(0) {}
inline QUrlTwoFlags &operator&=(int mask) { i &= mask; return *this; }
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index 6848a408f6..0c87dd5659 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -2044,7 +2044,7 @@ Qt::DropActions QAbstractItemModel::supportedDropActions() const
Qt::DropActions QAbstractItemModel::supportedDragActions() const
{
Q_D(const QAbstractItemModel);
- if (d->supportedDragActions != -1)
+ if (d->supportedDragActions != Qt::IgnoreAction)
return d->supportedDragActions;
return supportedDropActions();
}
diff --git a/src/corelib/itemmodels/qitemselectionmodel.cpp b/src/corelib/itemmodels/qitemselectionmodel.cpp
index 6390d5f389..6c7101d41f 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.cpp
+++ b/src/corelib/itemmodels/qitemselectionmodel.cpp
@@ -274,8 +274,6 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &
*/
/*!
- \fn bool QItemSelectionRange::operator<(const QItemSelectionRange &other) const
-
Returns \c true if the selection range is less than the \a other
range given; otherwise returns \c false.
@@ -284,6 +282,33 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &
class can be used with QMap.
*/
+bool QItemSelectionRange::operator<(const QItemSelectionRange &other) const
+{
+ // ### Qt 6: This is inconsistent with op== and needs to be fixed, nay,
+ // ### removed, but cannot, because it was inline up to and including 5.9
+
+ // Comparing parents will compare the models, but if two equivalent ranges
+ // in two different models have invalid parents, they would appear the same
+ if (other.tl.model() == tl.model()) {
+ // parent has to be calculated, so we only do so once.
+ const QModelIndex topLeftParent = tl.parent();
+ const QModelIndex otherTopLeftParent = other.tl.parent();
+ if (topLeftParent == otherTopLeftParent) {
+ if (other.tl.row() == tl.row()) {
+ if (other.tl.column() == tl.column()) {
+ if (other.br.row() == br.row()) {
+ return br.column() < other.br.column();
+ }
+ return br.row() < other.br.row();
+ }
+ return tl.column() < other.tl.column();
+ }
+ return tl.row() < other.tl.row();
+ }
+ return topLeftParent < otherTopLeftParent;
+ }
+ return tl.model() < other.tl.model();
+}
/*!
\fn bool QItemSelectionRange::isValid() const
diff --git a/src/corelib/itemmodels/qitemselectionmodel.h b/src/corelib/itemmodels/qitemselectionmodel.h
index c22ac6dbe5..2421610bce 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.h
+++ b/src/corelib/itemmodels/qitemselectionmodel.h
@@ -116,30 +116,7 @@ public:
{ return (tl == other.tl && br == other.br); }
inline bool operator!=(const QItemSelectionRange &other) const
{ return !operator==(other); }
- inline bool operator<(const QItemSelectionRange &other) const
- {
- // Comparing parents will compare the models, but if two equivalent ranges
- // in two different models have invalid parents, they would appear the same
- if (other.tl.model() == tl.model()) {
- // parent has to be calculated, so we only do so once.
- const QModelIndex topLeftParent = tl.parent();
- const QModelIndex otherTopLeftParent = other.tl.parent();
- if (topLeftParent == otherTopLeftParent) {
- if (other.tl.row() == tl.row()) {
- if (other.tl.column() == tl.column()) {
- if (other.br.row() == br.row()) {
- return br.column() < other.br.column();
- }
- return br.row() < other.br.row();
- }
- return tl.column() < other.tl.column();
- }
- return tl.row() < other.tl.row();
- }
- return topLeftParent < otherTopLeftParent;
- }
- return tl.model() < other.tl.model();
- }
+ bool operator<(const QItemSelectionRange &other) const;
inline bool isValid() const
{
diff --git a/src/corelib/itemmodels/qstringlistmodel.h b/src/corelib/itemmodels/qstringlistmodel.h
index ff59e0e76c..3bda848f48 100644
--- a/src/corelib/itemmodels/qstringlistmodel.h
+++ b/src/corelib/itemmodels/qstringlistmodel.h
@@ -58,7 +58,7 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex sibling(int row, int column, const QModelIndex &idx) const Q_DECL_OVERRIDE;
- QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 61d0f2bdf1..0e6ff17b8f 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -88,6 +88,8 @@ win32 {
SOURCES += kernel/qeventdispatcher_win.cpp
HEADERS += kernel/qeventdispatcher_win_p.h
}
+
+ !winrt: LIBS_PRIVATE += -lversion
}
winrt {
@@ -119,8 +121,8 @@ mac {
osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit
- uikit {
- # We need UIKit for UIDevice
+ ios|tvos {
+ # We need UIKit for UIApplication in qeventdispatcher_cf.mm
LIBS_PRIVATE += -framework UIKit
}
@@ -173,6 +175,9 @@ unix|integrity {
SOURCES += kernel/qsharedmemory_android.cpp \
kernel/qsystemsemaphore_android.cpp
}
+
+ # This is needed by QMetaType::typeName array implementation
+ integrity: QMAKE_CXXFLAGS += --pending_instantiations=128
}
vxworks {
diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h
index f92e418ebf..68d9bf180f 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.h
+++ b/src/corelib/kernel/qabstracteventdispatcher.h
@@ -95,7 +95,7 @@ public:
virtual int remainingTime(int timerId) = 0;
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
virtual bool registerEventNotifier(QWinEventNotifier *notifier) = 0;
virtual void unregisterEventNotifier(QWinEventNotifier *notifier) = 0;
#endif
diff --git a/src/corelib/kernel/qcore_foundation.mm b/src/corelib/kernel/qcore_foundation.mm
index 7f591a22c7..56eabc4b8c 100644
--- a/src/corelib/kernel/qcore_foundation.mm
+++ b/src/corelib/kernel/qcore_foundation.mm
@@ -46,6 +46,13 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qrect.h>
+#if QT_CONFIG(timezone) && !defined(QT_NO_SYSTEMLOCALE)
+#include <QtCore/qtimezone.h>
+#include <QtCore/private/qtimezoneprivate_p.h>
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
+#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#if defined(QT_PLATFORM_UIKIT)
@@ -321,6 +328,8 @@ NSUUID *QUuid::toNSUUID() const
*/
QUrl QUrl::fromCFURL(CFURLRef url)
{
+ if (!url)
+ return QUrl();
return QUrl(QString::fromCFString(CFURLGetString(url)));
}
@@ -348,6 +357,8 @@ CFURLRef QUrl::toCFURL() const
*/
QUrl QUrl::fromNSURL(const NSURL *url)
{
+ if (!url)
+ return QUrl();
return QUrl(QString::fromNSString([url absoluteString]));
}
@@ -422,6 +433,67 @@ NSDate *QDateTime::toNSDate() const
// ----------------------------------------------------------------------------
+#if QT_CONFIG(timezone) && !defined(QT_NO_SYSTEMLOCALE)
+/*!
+ \since 5.9
+
+ Constructs a new QTimeZone containing a copy of the CFTimeZone \a timeZone.
+
+ \sa toCFTimeZone()
+*/
+QTimeZone QTimeZone::fromCFTimeZone(CFTimeZoneRef timeZone)
+{
+ if (!timeZone)
+ return QTimeZone();
+ return QTimeZone(QString::fromCFString(CFTimeZoneGetName(timeZone)).toLatin1());
+}
+
+/*!
+ \since 5.9
+
+ Creates a CFTimeZone from a QTimeZone. The caller owns the CFTimeZone object
+ and is responsible for releasing it.
+
+ \sa fromCFTimeZone()
+*/
+CFTimeZoneRef QTimeZone::toCFTimeZone() const
+{
+#ifndef QT_NO_DYNAMIC_CAST
+ Q_ASSERT(dynamic_cast<const QMacTimeZonePrivate *>(d.data()));
+#endif
+ const QMacTimeZonePrivate *p = static_cast<const QMacTimeZonePrivate *>(d.data());
+ return reinterpret_cast<CFTimeZoneRef>([p->nsTimeZone() copy]);
+}
+
+/*!
+ \since 5.9
+
+ Constructs a new QTimeZone containing a copy of the NSTimeZone \a timeZone.
+
+ \sa toNSTimeZone()
+*/
+QTimeZone QTimeZone::fromNSTimeZone(const NSTimeZone *timeZone)
+{
+ if (!timeZone)
+ return QTimeZone();
+ return QTimeZone(QString::fromNSString(timeZone.name).toLatin1());
+}
+
+/*!
+ \since 5.9
+
+ Creates an NSTimeZone from a QTimeZone. The NSTimeZone object is autoreleased.
+
+ \sa fromNSTimeZone()
+*/
+NSTimeZone *QTimeZone::toNSTimeZone() const
+{
+ return [static_cast<NSTimeZone *>(toCFTimeZone()) autorelease];
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
/*!
\since 5.8
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm
index d7e8d4847a..231afb991c 100644
--- a/src/corelib/kernel/qcore_mac_objc.mm
+++ b/src/corelib/kernel/qcore_mac_objc.mm
@@ -47,14 +47,8 @@
#include <qdebug.h>
-#if defined(Q_OS_IOS)
-#import <UIKit/UIKit.h>
-#endif
-
QT_BEGIN_NAMESPACE
-typedef qint16 (*GestaltFunction)(quint32 selector, qint32 *response);
-
// -------------------------------------------------------------------------
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
@@ -87,54 +81,6 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY
// -------------------------------------------------------------------------
-QAppleOperatingSystemVersion qt_apple_os_version()
-{
- QAppleOperatingSystemVersion v = {0, 0, 0};
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_8_0) || defined(Q_OS_TVOS) || defined(Q_OS_WATCHOS)
- if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) {
- NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
- v.major = osv.majorVersion;
- v.minor = osv.minorVersion;
- v.patch = osv.patchVersion;
- return v;
- }
-#endif
- // Use temporary variables so we can return 0.0.0 (unknown version)
- // in case of an error partway through determining the OS version
- qint32 major = 0, minor = 0, patch = 0;
-#if QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_10_10, __IPHONE_8_0)
-#if defined(Q_OS_IOS)
- @autoreleasepool {
- NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."];
- major = parts.count > 0 ? [[parts objectAtIndex:0] intValue] : 0;
- minor = parts.count > 1 ? [[parts objectAtIndex:1] intValue] : 0;
- patch = parts.count > 2 ? [[parts objectAtIndex:2] intValue] : 0;
- }
-#elif defined(Q_OS_OSX)
- static GestaltFunction pGestalt = 0;
- if (!pGestalt) {
- CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices"));
- pGestalt = reinterpret_cast<GestaltFunction>(CFBundleGetFunctionPointerForName(b,
- CFSTR("Gestalt")));
- }
- if (!pGestalt)
- return v;
- if (pGestalt('sys1', &major) != 0)
- return v;
- if (pGestalt('sys2', &minor) != 0)
- return v;
- if (pGestalt('sys3', &patch) != 0)
- return v;
-#endif
-#endif
- v.major = major;
- v.minor = minor;
- v.patch = patch;
- return v;
-}
-
-// -------------------------------------------------------------------------
-
QMacAutoReleasePool::QMacAutoReleasePool()
: pool([[NSAutoreleasePool alloc] init])
{
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index cb709f9d4b..d0edef33a2 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -131,12 +131,6 @@ private:
QString string;
};
-typedef struct {
- int major, minor, patch;
-} QAppleOperatingSystemVersion;
-
-QAppleOperatingSystemVersion qt_apple_os_version();
-
#ifdef Q_OS_OSX
Q_CORE_EXPORT QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Q_CORE_EXPORT Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index baf140b3b2..e4b1562b8b 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -95,6 +95,11 @@
#endif
#endif // QT_NO_QOBJECT
+#if defined(Q_OS_ANDROID)
+# include <private/qjni_p.h>
+# include <private/qjnihelpers_p.h>
+#endif
+
#ifdef Q_OS_MAC
# include "qcore_mac_p.h"
#endif
@@ -144,11 +149,13 @@ int QCoreApplicationPrivate::app_compile_version = 0x050000; //we don't know exa
bool QCoreApplicationPrivate::setuidAllowed = false;
#if !defined(Q_OS_WIN)
-#ifdef Q_OS_MAC
-QString QCoreApplicationPrivate::macMenuBarName()
+#ifdef Q_OS_DARWIN
+QString QCoreApplicationPrivate::infoDictionaryStringProperty(const QString &propertyName)
{
QString bundleName;
- CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("CFBundleName"));
+ QCFString cfPropertyName = propertyName.toCFString();
+ CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(),
+ cfPropertyName);
if (string)
bundleName = QString::fromCFString(static_cast<CFStringRef>(string));
return bundleName;
@@ -157,8 +164,8 @@ QString QCoreApplicationPrivate::macMenuBarName()
QString QCoreApplicationPrivate::appName() const
{
QString applicationName;
-#ifdef Q_OS_MAC
- applicationName = macMenuBarName();
+#ifdef Q_OS_DARWIN
+ applicationName = infoDictionaryStringProperty(QStringLiteral("CFBundleName"));
#endif
if (applicationName.isEmpty() && argv[0]) {
char *p = strrchr(argv[0], '/');
@@ -167,6 +174,34 @@ QString QCoreApplicationPrivate::appName() const
return applicationName;
}
+QString QCoreApplicationPrivate::appVersion() const
+{
+ QString applicationVersion;
+#ifndef QT_BOOTSTRAPPED
+# ifdef Q_OS_DARWIN
+ applicationVersion = infoDictionaryStringProperty(QStringLiteral("CFBundleVersion"));
+# elif defined(Q_OS_ANDROID)
+ QJNIObjectPrivate context(QtAndroidPrivate::context());
+ if (context.isValid()) {
+ QJNIObjectPrivate pm = context.callObjectMethod(
+ "getPackageManager", "()Landroid/content/pm/PackageManager;");
+ QJNIObjectPrivate pn = context.callObjectMethod<jstring>("getPackageName");
+ if (pm.isValid() && pn.isValid()) {
+ QJNIObjectPrivate packageInfo = pm.callObjectMethod(
+ "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;",
+ pn.object(), 0);
+ if (packageInfo.isValid()) {
+ QJNIObjectPrivate versionName = packageInfo.getObjectField(
+ "versionName", "Ljava/lang/String;");
+ if (versionName.isValid())
+ return versionName.toString();
+ }
+ }
+ }
+# endif
+#endif
+ return applicationVersion;
+}
#endif
QString *QCoreApplicationPrivate::cachedApplicationFilePath = 0;
@@ -323,6 +358,7 @@ uint QCoreApplicationPrivate::attribs =
struct QCoreApplicationData {
QCoreApplicationData() Q_DECL_NOTHROW {
applicationNameSet = false;
+ applicationVersionSet = false;
}
~QCoreApplicationData() {
#ifndef QT_NO_QOBJECT
@@ -338,6 +374,7 @@ struct QCoreApplicationData {
QString application; // application name, initially from argv[0], can then be modified.
QString applicationVersion;
bool applicationNameSet; // true if setApplicationName was called
+ bool applicationVersionSet; // true if setApplicationVersion was called
#if QT_CONFIG(library)
QScopedPointer<QStringList> app_libpaths;
@@ -519,12 +556,10 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
QThread *thr = receiver->thread();
Q_ASSERT_X(currentThread == thr || !thr,
"QCoreApplication::sendEvent",
- QString::fromLatin1("Cannot send events to objects owned by a different thread. "
- "Current thread %1. Receiver '%2' (of type '%3') was created in thread %4")
- .arg(QString::number((quintptr) currentThread, 16))
- .arg(receiver->objectName())
- .arg(QLatin1String(receiver->metaObject()->className()))
- .arg(QString::number((quintptr) thr, 16))
+ QString::asprintf("Cannot send events to objects owned by a different thread. "
+ "Current thread 0x%p. Receiver '%ls' (of type '%s') was created in thread 0x%p",
+ currentThread, qUtf16Printable(receiver->objectName()),
+ receiver->metaObject()->className(), thr)
.toLocal8Bit().data());
Q_UNUSED(currentThread);
Q_UNUSED(thr);
@@ -729,10 +764,13 @@ void QCoreApplicationPrivate::init()
Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
QCoreApplication::self = q;
- // Store app name (so it's still available after QCoreApplication is destroyed)
+ // Store app name/version (so they're still available after QCoreApplication is destroyed)
if (!coreappdata()->applicationNameSet)
coreappdata()->application = appName();
+ if (!coreappdata()->applicationVersionSet)
+ coreappdata()->applicationVersion = appVersion();
+
QLoggingRegistry::instance()->init();
#if QT_CONFIG(library)
@@ -2390,6 +2428,29 @@ Q_CORE_EXPORT QString qt_applicationName_noFallback()
\since 4.4
\brief the version of this application
+ If not set, the application version defaults to a platform-specific value
+ determined from the main application executable or package (since Qt 5.9):
+
+ \table
+ \header
+ \li Platform
+ \li Source
+ \row
+ \li Windows (classic desktop)
+ \li PRODUCTVERSION parameter of the VERSIONINFO resource
+ \row
+ \li Universal Windows Platform
+ \li version attribute of the application package manifest
+ \row
+ \li macOS, iOS, tvOS, watchOS
+ \li CFBundleVersion property of the information property list
+ \row
+ \li Android
+ \li android:versionName property of the AndroidManifest.xml manifest element
+ \endtable
+
+ On other platforms, the default is the empty string.
+
\sa applicationName, organizationName, organizationDomain
*/
/*!
@@ -2400,9 +2461,13 @@ Q_CORE_EXPORT QString qt_applicationName_noFallback()
*/
void QCoreApplication::setApplicationVersion(const QString &version)
{
- if (coreappdata()->applicationVersion == version)
+ coreappdata()->applicationVersionSet = !version.isEmpty();
+ QString newVersion = version;
+ if (newVersion.isEmpty() && QCoreApplication::self)
+ newVersion = QCoreApplication::self->d_func()->appVersion();
+ if (coreappdata()->applicationVersion == newVersion)
return;
- coreappdata()->applicationVersion = version;
+ coreappdata()->applicationVersion = newVersion;
#ifndef QT_NO_QOBJECT
if (QCoreApplication::self)
emit QCoreApplication::self->applicationVersionChanged();
@@ -2411,7 +2476,7 @@ void QCoreApplication::setApplicationVersion(const QString &version)
QString QCoreApplication::applicationVersion()
{
- return coreappdata()->applicationVersion;
+ return coreappdata() ? coreappdata()->applicationVersion : QString();
}
#if QT_CONFIG(library)
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 3601add098..c646786296 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -83,9 +83,10 @@ public:
void init();
QString appName() const;
+ QString appVersion() const;
-#ifdef Q_OS_MAC
- static QString macMenuBarName();
+#ifdef Q_OS_DARWIN
+ static QString infoDictionaryStringProperty(const QString &propertyName);
#endif
static void initLocale();
diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp
index a9ca82c757..50888dd0aa 100644
--- a/src/corelib/kernel/qcoreapplication_win.cpp
+++ b/src/corelib/kernel/qcoreapplication_win.cpp
@@ -51,27 +51,20 @@
#include <ctype.h>
#include <qt_windows.h>
+#ifdef Q_OS_WINRT
+#include <qfunctions_winrt.h>
+#include <wrl.h>
+#include <Windows.ApplicationModel.core.h>
+#include <windows.foundation.h>
+using namespace ABI::Windows::ApplicationModel;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+#endif
+
QT_BEGIN_NAMESPACE
int appCmdShow = 0;
-// GetModuleFileName only exists for MSVC2015 and upwards for WinRT, meaning
-// Windows 10 (Mobile). Hence take the first argument passed to the
-// QCoreApplication contructor for older versions as a fallback on older platforms.
-#if defined(Q_OS_WINRT) && _MSC_VER < 1900
-
-Q_CORE_EXPORT QString qAppFileName()
-{
- return QFileInfo(QCoreApplication::arguments().constFirst()).filePath();
-}
-
-QString QCoreApplicationPrivate::appName() const
-{
- return QFileInfo(QCoreApplication::arguments().constFirst()).baseName();
-}
-
-#else // !(defined(Q_OS_WINRT) && _MSC_VER < 1900)
-
Q_CORE_EXPORT QString qAppFileName() // get application file name
{
// We do MAX_PATH + 2 here, and request with MAX_PATH + 1, so we can handle all paths
@@ -118,7 +111,63 @@ QString QCoreApplicationPrivate::appName() const
return QFileInfo(qAppFileName()).baseName();
}
-#endif // !(defined(Q_OS_WINRT) && _MSC_VER < 1900)
+QString QCoreApplicationPrivate::appVersion() const
+{
+ QString applicationVersion;
+#ifndef QT_BOOTSTRAPPED
+# ifdef Q_OS_WINRT
+ HRESULT hr;
+
+ ComPtr<IPackageStatics> packageFactory;
+ hr = RoGetActivationFactory(
+ HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Package).Get(),
+ IID_PPV_ARGS(&packageFactory));
+ RETURN_IF_FAILED("Failed to create package instance", return QString());
+
+ ComPtr<IPackage> package;
+ packageFactory->get_Current(&package);
+ RETURN_IF_FAILED("Failed to get current application package", return QString());
+
+ ComPtr<IPackageId> packageId;
+ package->get_Id(&packageId);
+ RETURN_IF_FAILED("Failed to get current application package ID", return QString());
+
+ PackageVersion version;
+ packageId->get_Version(&version);
+ RETURN_IF_FAILED("Failed to get current application package version", return QString());
+
+ applicationVersion = QStringLiteral("%1.%2.%3.%4")
+ .arg(version.Major)
+ .arg(version.Minor)
+ .arg(version.Build)
+ .arg(version.Revision);
+# else
+ const QString appFileName = qAppFileName();
+ QVarLengthArray<wchar_t> buffer(appFileName.size() + 1);
+ buffer[appFileName.toWCharArray(buffer.data())] = 0;
+
+ DWORD versionInfoSize = GetFileVersionInfoSize(buffer.data(), nullptr);
+ if (versionInfoSize) {
+ QVarLengthArray<BYTE> info(static_cast<int>(versionInfoSize));
+ if (GetFileVersionInfo(buffer.data(), 0, versionInfoSize, info.data())) {
+ UINT size;
+ DWORD *fi;
+
+ if (VerQueryValue(info.data(), __TEXT("\\"),
+ reinterpret_cast<void **>(&fi), &size) && size) {
+ const VS_FIXEDFILEINFO *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi);
+ applicationVersion = QStringLiteral("%1.%2.%3.%4")
+ .arg(HIWORD(verInfo->dwProductVersionMS))
+ .arg(LOWORD(verInfo->dwProductVersionMS))
+ .arg(HIWORD(verInfo->dwProductVersionLS))
+ .arg(LOWORD(verInfo->dwProductVersionLS));
+ }
+ }
+ }
+# endif
+#endif
+ return applicationVersion;
+}
#ifndef Q_OS_WINRT
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index 64e73d23c5..4efc38ac89 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -216,6 +216,7 @@ QT_BEGIN_NAMESPACE
\omitvalue OkRequest
\value TabletEnterProximity Wacom tablet enter proximity event (QTabletEvent), sent to QApplication.
\value TabletLeaveProximity Wacom tablet leave proximity event (QTabletEvent), sent to QApplication.
+ \value TabletTrackingChange The Wacom tablet tracking state has changed (since Qt 5.9).
\omitvalue ThemeChange
\value ThreadChange The object is moved to another thread. This is the last event sent to this object in the previous thread. See QObject::moveToThread().
\value Timer Regular timer events (QTimerEvent).
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 7e962f816e..ac974ba411 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -284,6 +284,8 @@ public:
Pointer = 218, // QQuickPointerEvent; ### Qt 6: QPointerEvent
+ TabletTrackingChange = 219, // tablet tracking state has changed
+
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp
index 1f554c9f2e..a2ec813f11 100644
--- a/src/corelib/kernel/qdeadlinetimer.cpp
+++ b/src/corelib/kernel/qdeadlinetimer.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2016 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $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 http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** 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 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** 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.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** 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$
**
@@ -175,9 +181,9 @@ Q_DECL_CONST_FUNCTION static inline QPair<qint64, qint64> toSecsAndNSecs(qint64
*/
/*!
- \fn QDeadlineTimer::QDeadlineTimer(ForeverConstant foreverConstant, Qt::TimerType timerType)
+ \fn QDeadlineTimer::QDeadlineTimer(ForeverConstant forever, Qt::TimerType timerType)
- QDeadlineTimer objects created with parameter \a foreverConstant never expire.
+ QDeadlineTimer objects created with parameter \a forever never expire.
For such objects, remainingTime() will return -1, deadline() will return the
maximum value, and isForever() will return true.
@@ -343,54 +349,6 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time
*/
/*!
- \fn std::chrono::nanoseconds remainingTimeAsDuration() const
-
- Returns a \c{std::chrono::duration} object of type \c{Duration} containing
- the remaining time in this QDeadlineTimer, if it still has time left. If
- the deadline has passed, this returns \c{Duration::zero()}, whereas if the
- object is set to never expire, it returns \c{Duration::max()} (instead of
- -1).
-
- It is not possible to obtain the overdue time for expired timers with this
- function. To do that, see deadline().
-
- \note The overload of this function without template parameter always
- returns milliseconds.
-
- \sa setRemainingTime(), deadline<Clock, Duration>()
-*/
-
-/*!
- \overload
- \fn std::chrono::time_point<Clock, Duration> QDeadlineTimer::deadline() const
-
- Returns the absolute time point for the deadline stored in QDeadlineTimer
- object as a \c{std::chrono::time_point} object. The template parameter
- \c{Clock} is mandatory and indicates which of the C++ timekeeping clocks to
- use as a reference. The value will be in the past if this QDeadlineTimer
- has expired.
-
- If this QDeadlineTimer never expires, this function returns
- \c{std::chrono::time_point<Clock, Duration>::max()}.
-
- This function can be used to calculate the amount of time a timer is
- overdue, by subtracting the current time point of the reference clock, as
- in the following example:
-
- \code
- auto realTimeLeft = std::chrono::nanoseconds::max();
- auto tp = deadline.deadline<std::chrono::steady_clock>();
- if (tp != std::chrono::steady_clock::max())
- realTimeLeft = tp - std::chrono::steady_clock::now();
- \endcode
-
- \note Timers that were created as expired have an indetermine time point in
- the past as their deadline, so the above calculation may not work.
-
- \sa remainingTime(), deadlineNSecs(), setDeadline()
-*/
-
-/*!
\fn bool QDeadlineTimer::isForever() const
Returns true if this QDeadlineTimer object never expires, false otherwise.
@@ -791,6 +749,30 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) Q_DECL_
To subtract times of precision greater than 1 millisecond, use addNSecs().
*/
+/*!
+ \fn void QDeadlineTimer::swap(QDeadlineTimer &other)
+
+ Swaps this deadline timer with the \a other deadline timer.
+ */
+
+/*!
+ \fn QDeadlineTimer & QDeadlineTimer::operator=(std::chrono::time_point<Clock, Duration> deadline_)
+
+ Assigns \a deadline_ to this deadline timer.
+ */
+
+/*!
+ \fn QDeadlineTimer & QDeadlineTimer::operator=(std::chrono::duration<Rep, Period> remaining)
+
+ Sets this deadline timer to the \a remaining time.
+ */
+
+/*!
+ \fn std::chrono::nanoseconds QDeadlineTimer::remainingTimeAsDuration() const
+
+ Returns the time remaining before the deadline.
+ */
+
// the rest of the functions are in qelapsedtimer_xxx.cpp
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qdeadlinetimer.h b/src/corelib/kernel/qdeadlinetimer.h
index aa0f735fcc..ddab0191ad 100644
--- a/src/corelib/kernel/qdeadlinetimer.h
+++ b/src/corelib/kernel/qdeadlinetimer.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2016 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $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 http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** 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 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** 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.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** 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$
**
diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm
index 4defae559e..608dea5426 100644
--- a/src/corelib/kernel/qeventdispatcher_cf.mm
+++ b/src/corelib/kernel/qeventdispatcher_cf.mm
@@ -81,7 +81,8 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(RunLoopModeTracker);
#elif defined(Q_OS_WATCHOS)
object:[WKExtension sharedExtension]];
#else
- object:[UIApplication sharedApplication]];
+ // Use performSelector so this can work in an App Extension
+ object:[[UIApplication class] performSelector:@selector(sharedApplication)]];
#endif
}
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index fd9d41647d..74fa2d8d50 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -42,6 +42,7 @@
#include "qcoreapplication.h"
#include <private/qsystemlibrary_p.h>
+#include "qoperatingsystemversion.h"
#include "qpair.h"
#include "qset.h"
#include "qsocketnotifier.h"
@@ -230,7 +231,7 @@ static inline UINT inputTimerMask()
// QTBUG 28513, QTBUG-29097, QTBUG-29435: QS_TOUCH, QS_POINTER became part of
// QS_INPUT in Windows Kit 8. They should not be used when running on pre-Windows 8.
#if WINVER > 0x0601
- if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8)
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
result &= ~(QS_TOUCH | QS_POINTER);
#endif // WINVER > 0x0601
return result;
@@ -1041,4 +1042,11 @@ void QEventDispatcherWin32::sendPostedEvents()
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
}
+HWND QEventDispatcherWin32::internalHwnd()
+{
+ Q_D(QEventDispatcherWin32);
+ createInternalHwnd();
+ return d->internalHwnd;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index df1513a43a..423dc5b169 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -106,6 +106,8 @@ public:
bool event(QEvent *e);
+ HWND internalHwnd();
+
protected:
QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = 0);
virtual void sendPostedEvents();
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index fe204bbee2..93bc477e7d 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -52,6 +52,18 @@
QT_BEGIN_NAMESPACE
+namespace QtAndroidPrivate {
+ // *Listener virtual function implementations.
+ // Defined out-of-line to pin the vtable/type_info.
+ ActivityResultListener::~ActivityResultListener() {}
+ NewIntentListener::~NewIntentListener() {}
+ ResumePauseListener::~ResumePauseListener() {}
+ void ResumePauseListener::handlePause() {}
+ void ResumePauseListener::handleResume() {}
+ GenericMotionEventListener::~GenericMotionEventListener() {}
+ KeyEventListener::~KeyEventListener() {}
+}
+
static JavaVM *g_javaVM = Q_NULLPTR;
static jobject g_jActivity = Q_NULLPTR;
static jobject g_jService = Q_NULLPTR;
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index 478f62a5c7..62f9358513 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -65,36 +65,36 @@ namespace QtAndroidPrivate
class Q_CORE_EXPORT ActivityResultListener
{
public:
- virtual ~ActivityResultListener() {}
+ virtual ~ActivityResultListener();
virtual bool handleActivityResult(jint requestCode, jint resultCode, jobject data) = 0;
};
class Q_CORE_EXPORT NewIntentListener
{
public:
- virtual ~NewIntentListener() {}
+ virtual ~NewIntentListener();
virtual bool handleNewIntent(JNIEnv *env, jobject intent) = 0;
};
class Q_CORE_EXPORT ResumePauseListener
{
public:
- virtual ~ResumePauseListener() {}
- virtual void handlePause() {};
- virtual void handleResume() {};
+ virtual ~ResumePauseListener();
+ virtual void handlePause();
+ virtual void handleResume();
};
class Q_CORE_EXPORT GenericMotionEventListener
{
public:
- virtual ~GenericMotionEventListener() {}
+ virtual ~GenericMotionEventListener();
virtual bool handleGenericMotionEvent(jobject event) = 0;
};
class Q_CORE_EXPORT KeyEventListener
{
public:
- virtual ~KeyEventListener() {}
+ virtual ~KeyEventListener();
virtual bool handleKeyEvent(jobject event) = 0;
};
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 1c540f64c7..e247c48703 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -143,21 +143,17 @@ public:
}
bool operator==(const QArgumentType &other) const
{
- if (_type)
+ if (_type && other._type)
return _type == other._type;
- else if (other._type)
- return false;
else
- return _name == other._name;
+ return name() == other.name();
}
bool operator!=(const QArgumentType &other) const
{
- if (_type)
+ if (_type && other._type)
return _type != other._type;
- else if (other._type)
- return true;
else
- return _name != other._name;
+ return name() != other.name();
}
private:
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 718c42ba55..b75f2ad9dc 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -825,9 +825,91 @@ void QMetaType::registerStreamOperators(int idx, SaveOperator saveOp,
}
#endif // QT_NO_DATASTREAM
+#if defined(Q_COMPILER_CONSTEXPR) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900)
+// We don't officially support constexpr in MSVC 2015, but the limited support it
+// has is enough for the code below.
+
+# define STRINGIFY_TYPE_NAME(MetaTypeName, TypeId, RealName) \
+ #RealName "\0"
+# define CALCULATE_TYPE_LEN(MetaTypeName, TypeId, RealName) \
+ short(sizeof(#RealName)),
+# define MAP_TYPE_ID_TO_IDX(MetaTypeName, TypeId, RealName) \
+ TypeId,
+
+namespace {
+// All type names in one long string.
+constexpr char metaTypeStrings[] = QT_FOR_EACH_STATIC_TYPE(STRINGIFY_TYPE_NAME);
+
+// The sizes of the strings in the metaTypeStrings string (including terminating null)
+constexpr short metaTypeNameSizes[] = {
+ QT_FOR_EACH_STATIC_TYPE(CALCULATE_TYPE_LEN)
+};
+
+// The type IDs, in the order of the metaTypeStrings data
+constexpr short metaTypeIds[] = {
+ QT_FOR_EACH_STATIC_TYPE(MAP_TYPE_ID_TO_IDX)
+};
+
+constexpr int MetaTypeNameCount = sizeof(metaTypeNameSizes) / sizeof(metaTypeNameSizes[0]);
+
+template <typename IntegerSequence> struct MetaTypeOffsets;
+template <int... TypeIds> struct MetaTypeOffsets<QtPrivate::IndexesList<TypeIds...>>
+{
+ // This would have been a lot easier if the meta types that the macro
+ // QT_FOR_EACH_STATIC_TYPE declared were in sorted, ascending order, but
+ // they're not (i.e., the first one declared is QMetaType::Void == 43,
+ // followed by QMetaType::Bool == 1)... As a consequence, we need to use
+ // the C++11 constexpr function calculateOffsetForTypeId below in order to
+ // create the offset array.
+
+ static constexpr int findTypeId(int typeId, int i = 0)
+ {
+ return i >= MetaTypeNameCount ? -1 :
+ metaTypeIds[i] == typeId ? i : findTypeId(typeId, i + 1);
+ }
+
+ static constexpr short calculateOffsetForIdx(int i)
+ {
+ return i < 0 ? -1 :
+ i == 0 ? 0 : metaTypeNameSizes[i - 1] + calculateOffsetForIdx(i - 1);
+ }
+
+ static constexpr short calculateOffsetForTypeId(int typeId)
+ {
+ return calculateOffsetForIdx(findTypeId(typeId));
+#if 0
+ // same as, but this is only valid in C++14:
+ short offset = 0;
+ for (int i = 0; i < MetaTypeNameCount; ++i) {
+ if (metaTypeIds[i] == typeId)
+ return offset;
+ offset += metaTypeNameSizes[i];
+ }
+ return -1;
+#endif
+ }
+
+ short offsets[sizeof...(TypeIds)];
+ constexpr MetaTypeOffsets() : offsets{calculateOffsetForTypeId(TypeIds)...} {}
+
+ const char *operator[](int typeId) const Q_DECL_NOTHROW
+ {
+ short o = offsets[typeId];
+ return o < 0 ? nullptr : metaTypeStrings + o;
+ }
+};
+} // anonymous namespace
+
+constexpr MetaTypeOffsets<QtPrivate::Indexes<QMetaType::HighestInternalId + 1>::Value> metaTypeNames {};
+# undef STRINGIFY_TYPE_NAME
+# undef CALCULATE_TYPE_LEN
+# undef MAP_TYPE_ID_TO_IDX
+#endif
+
/*!
- Returns the type name associated with the given \a typeId, or 0 if no
- matching type was found. The returned pointer must not be deleted.
+ Returns the type name associated with the given \a typeId, or a null
+ pointer if no matching type was found. The returned pointer must not be
+ deleted.
\sa type(), isRegistered(), Type
*/
@@ -837,14 +919,18 @@ const char *QMetaType::typeName(int typeId)
#define QT_METATYPE_TYPEID_TYPENAME_CONVERTER(MetaTypeName, TypeId, RealName) \
case QMetaType::MetaTypeName: return #RealName; break;
- switch (QMetaType::Type(type)) {
- QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_TYPEID_TYPENAME_CONVERTER)
- case QMetaType::UnknownType:
- case QMetaType::User:
- break;
- }
-
- if (Q_UNLIKELY(type < QMetaType::User)) {
+ if (Q_LIKELY(type <= QMetaType::HighestInternalId)) {
+#if defined(Q_COMPILER_CONSTEXPR) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900)
+ return metaTypeNames[typeId];
+#else
+ switch (QMetaType::Type(type)) {
+ QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_TYPEID_TYPENAME_CONVERTER)
+ case QMetaType::UnknownType:
+ case QMetaType::User:
+ break;
+ }
+#endif
+ } else if (Q_UNLIKELY(type < QMetaType::User)) {
return nullptr; // It can happen when someone cast int to QVariant::Type, we should not crash...
}
@@ -1014,7 +1100,7 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
normalizedTypeName.size());
int previousSize = 0;
- int previousFlags = 0;
+ QMetaType::TypeFlags::Int previousFlags = 0;
if (idx == UnknownType) {
QWriteLocker locker(customTypesLock());
int posInVector = -1;
@@ -1264,6 +1350,7 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
case QMetaType::QJsonDocument:
return false;
case QMetaType::Nullptr:
+ stream << *static_cast<const std::nullptr_t *>(data);
return true;
case QMetaType::Long:
stream << qlonglong(*static_cast<const long *>(data));
@@ -1487,6 +1574,7 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
case QMetaType::QJsonDocument:
return false;
case QMetaType::Nullptr:
+ stream >> *static_cast<std::nullptr_t *>(data);
return true;
case QMetaType::Long: {
qlonglong l;
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 5a90314735..d88f469e0f 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -1413,17 +1413,17 @@ namespace QtPrivate
static inline const QMetaObject *value() { return Q_NULLPTR; }
};
template<typename T>
- struct MetaObjectForType<T*, typename QEnableIf<IsPointerToTypeDerivedFromQObject<T*>::Value>::Type>
+ struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type>
{
static inline const QMetaObject *value() { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename QEnableIf<IsGadgetHelper<T>::Value>::Type>
+ struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::Value>::type>
{
static inline const QMetaObject *value() { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename QEnableIf<IsQEnumHelper<T>::Value>::Type >
+ struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type >
{
static inline const QMetaObject *value() { return qt_getEnumMetaObject(T()); }
};
@@ -2009,7 +2009,7 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
}; \
template<typename T> \
struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
- typename QEnableIf<IsPointerToTypeDerivedFromQObject<T*>::Value >::Type> \
+ typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \
{ \
static bool registerConverter(int id) \
{ \
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index dd0bce2645..6f1334d082 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -129,7 +129,7 @@ public:
QMetaType::Constructor constructor;
QMetaType::Destructor destructor;
int size;
- quint32 flags; // same as QMetaType::TypeFlags
+ QMetaType::TypeFlags::Int flags;
const QMetaObject *metaObject;
};
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index b1de62bceb..1b05962c07 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -147,12 +147,13 @@ static inline QMutex *signalSlotLock(const QObject *o)
uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]);
}
-// ### Qt >= 5.6, remove qt_add/removeObject
+#if QT_VERSION < 0x60000
extern "C" Q_CORE_EXPORT void qt_addObject(QObject *)
{}
extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *)
{}
+#endif
struct QConnectionSenderSwitcher {
QObject *receiver;
@@ -754,30 +755,6 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
\sa {Object Trees & Ownership}
*/
-/*!
- \relates QObject
-
- Returns a pointer to the object named \a name that inherits \a
- type and with a given \a parent.
-
- Returns 0 if there is no such child.
-
- \snippet code/src_corelib_kernel_qobject.cpp 0
-*/
-
-void *qt_find_obj_child(QObject *parent, const char *type, const QString &name)
-{
- QObjectList list = parent->children();
- if (list.size() == 0) return 0;
- for (int i = 0; i < list.size(); ++i) {
- QObject *obj = list.at(i);
- if (name == obj->objectName() && obj->inherits(type))
- return obj;
- }
- return 0;
-}
-
-
/*****************************************************************************
QObject member functions
*****************************************************************************/
@@ -835,7 +812,9 @@ QObject::QObject(QObject *parent)
QT_RETHROW;
}
}
+#if QT_VERSION < 0x60000
qt_addObject(this);
+#endif
if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}
@@ -868,7 +847,9 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent)
QT_RETHROW;
}
}
+#if QT_VERSION < 0x60000
qt_addObject(this);
+#endif
if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}
@@ -1040,7 +1021,9 @@ QObject::~QObject()
if (!d->children.isEmpty())
d->deleteChildren();
+#if QT_VERSION < 0x60000
qt_removeObject(this);
+#endif
if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(this);
@@ -1651,6 +1634,45 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
}
/*!
+ \since 5.9
+ \overload
+ \fn int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType)
+
+ Starts a timer and returns a timer identifier, or returns zero if
+ it could not start a timer.
+
+ A timer event will occur every \a time interval until killTimer()
+ is called. If \a time is equal to \c{std::chrono::duration::zero()},
+ then the timer event occurs once every time there are no more window
+ system events to process.
+
+ The virtual timerEvent() function is called with the QTimerEvent
+ event parameter class when a timer event occurs. Reimplement this
+ function to get timer events.
+
+ If multiple timers are running, the QTimerEvent::timerId() can be
+ used to find out which timer was activated.
+
+ Example:
+
+ \snippet code/src_corelib_kernel_qobject.cpp 8
+
+ Note that QTimer's accuracy depends on the underlying operating system and
+ hardware. The \a timerType argument allows you to customize the accuracy of
+ the timer. See Qt::TimerType for information on the different timer types.
+ Most platforms support an accuracy of 20 milliseconds; some provide more.
+ If Qt is unable to deliver the requested number of timer events, it will
+ silently discard some.
+
+ The QTimer class provides a high-level programming interface with
+ single-shot timers and timer signals instead of events. There is
+ also a QBasicTimer class that is more lightweight than QTimer and
+ less clumsy than using timer IDs directly.
+
+ \sa timerEvent(), killTimer(), QTimer::singleShot()
+*/
+
+/*!
Kills the timer with timer identifier, \a id.
The timer identifier is returned by startTimer() when a timer
@@ -2631,7 +2653,8 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
call qRegisterMetaType() to register the data type before you
establish the connection.
- \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE()
+ \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE(),
+ {Differences between String-Based and Functor-Based Connections}
*/
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
@@ -3944,9 +3967,8 @@ QList<QByteArray> QObject::dynamicPropertyNames() const
QObject debugging output routines.
*****************************************************************************/
-static void dumpRecursive(int level, QObject *object)
+static void dumpRecursive(int level, const QObject *object)
{
-#if defined(QT_DEBUG)
if (object) {
QByteArray buf;
buf.fill(' ', level / 2 * 8);
@@ -3975,45 +3997,65 @@ static void dumpRecursive(int level, QObject *object)
dumpRecursive(level+1, children.at(i));
}
}
-#else
- Q_UNUSED(level)
- Q_UNUSED(object)
-#endif
}
/*!
- Dumps a tree of children to the debug output.
+ \overload
+ \obsolete
- This function is useful for debugging, but does nothing if the
- library has been compiled in release mode (i.e. without debugging
- information).
+ Dumps a tree of children to the debug output.
\sa dumpObjectInfo()
*/
void QObject::dumpObjectTree()
{
+ const_cast<const QObject *>(this)->dumpObjectTree();
+}
+
+/*!
+ Dumps a tree of children to the debug output.
+
+ \note before Qt 5.9, this function was not const.
+
+ \sa dumpObjectInfo()
+*/
+
+void QObject::dumpObjectTree() const
+{
dumpRecursive(0, this);
}
/*!
+ \overload
+ \obsolete
+
Dumps information about signal connections, etc. for this object
to the debug output.
- This function is useful for debugging, but does nothing if the
- library has been compiled in release mode (i.e. without debugging
- information).
-
\sa dumpObjectTree()
*/
void QObject::dumpObjectInfo()
{
-#if defined(QT_DEBUG)
+ const_cast<const QObject *>(this)->dumpObjectInfo();
+}
+
+/*!
+ Dumps information about signal connections, etc. for this object
+ to the debug output.
+
+ \note before Qt 5.9, this function was not const.
+
+ \sa dumpObjectTree()
+*/
+
+void QObject::dumpObjectInfo() const
+{
qDebug("OBJECT %s::%s", metaObject()->className(),
objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
- Q_D(QObject);
+ Q_D(const QObject);
QMutexLocker locker(signalSlotLock(this));
// first, look for connections where this object is the sender
@@ -4069,7 +4111,6 @@ void QObject::dumpObjectInfo()
} else {
qDebug(" <None>");
}
-#endif
}
#ifndef QT_NO_USERDATA
@@ -4616,11 +4657,9 @@ void qDeleteInEventHandler(QObject *o)
Overloaded functions can be resolved with help of \l qOverload.
- \note The number of arguments in the signal or slot are limited to 6 if
- the compiler does not support C++11 variadic templates.
+ \sa {Differences between String-Based and Functor-Based Connections}
*/
-
/*!
\fn QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
@@ -4643,7 +4682,7 @@ void qDeleteInEventHandler(QObject *o)
\snippet code/src_corelib_kernel_qobject.cpp 45
- If your compiler support C++11 lambda expressions, you can use them:
+ Lambda expressions can also be used:
\snippet code/src_corelib_kernel_qobject.cpp 46
@@ -4653,9 +4692,6 @@ void qDeleteInEventHandler(QObject *o)
Overloaded functions can be resolved with help of \l qOverload.
- \note If the compiler does not support C++11 variadic templates, the number
- of arguments in the signal or slot are limited to 6, and the functor object
- must not have an overloaded or templated operator().
*/
/*!
@@ -4686,7 +4722,7 @@ void qDeleteInEventHandler(QObject *o)
\snippet code/src_corelib_kernel_qobject.cpp 50
- If your compiler support C++11 lambda expressions, you can use them:
+ Lambda expressions can also be used:
\snippet code/src_corelib_kernel_qobject.cpp 51
@@ -4696,10 +4732,6 @@ void qDeleteInEventHandler(QObject *o)
are still alive when the signal is emitted.
Overloaded functions can be resolved with help of \l qOverload.
-
- \note If the compiler does not support C++11 variadic templates, the number
- of arguments in the signal or slot are limited to 6, and the functor object
- must not have an overloaded or templated operator().
*/
/*!
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 69b70ad6ec..6941c55896 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -55,6 +55,10 @@
#include <QtCore/qobject_impl.h>
+#if QT_HAS_INCLUDE(<chrono>)
+# include <chrono>
+#endif
+
QT_BEGIN_NAMESPACE
@@ -150,6 +154,13 @@ public:
void moveToThread(QThread *thread);
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
+#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC)
+ Q_ALWAYS_INLINE
+ int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
+ {
+ return startTimer(int(time.count()), timerType);
+ }
+#endif
void killTimer(int id);
template<typename T>
@@ -250,7 +261,7 @@ public:
//connect to a function pointer (not a member)
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::Type
+ static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
{
return connect(sender, signal, sender, slot, Qt::DirectConnection);
@@ -258,8 +269,8 @@ public:
//connect to a function pointer (not a member)
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&
- !QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::Type
+ static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&
+ !QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
@@ -290,7 +301,7 @@ public:
//connect to a functor
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type
+ 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);
@@ -298,7 +309,7 @@ public:
//connect to a functor, with a "context" object defining in which event loop is going to be executed
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type
+ static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
@@ -375,8 +386,12 @@ public:
#endif //Q_QDOC
- void dumpObjectTree();
- void dumpObjectInfo();
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ void dumpObjectTree(); // ### Qt 6: remove
+ void dumpObjectInfo(); // ### Qt 6: remove
+#endif
+ void dumpObjectTree() const;
+ void dumpObjectInfo() const;
#ifndef QT_NO_PROPERTIES
bool setProperty(const char *name, const QVariant &value);
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 5cdbef443b..ea4046df55 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -147,34 +147,8 @@ class QString;
# define QT_TR_FUNCTIONS
#endif
-#if defined(QT_NO_QOBJECT_CHECK)
-/* qmake ignore Q_OBJECT */
-#define Q_OBJECT_CHECK
-#else
-
-/* This is a compile time check that ensures that any class cast with qobject_cast
- actually contains a Q_OBJECT macro. Note: qobject_cast will fail if a QObject
- subclass doesn't contain Q_OBJECT.
-
- In qt_check_for_QOBJECT_macro, we call a dummy templated function with two
- parameters, the first being "this" and the other the target of the qobject
- cast. If the types are not identical, we know that a Q_OBJECT macro is missing.
-
- If you get a compiler error here, make sure that the class you are casting
- to contains a Q_OBJECT macro.
-*/
-
-/* qmake ignore Q_OBJECT */
-#define Q_OBJECT_CHECK \
- template <typename ThisObject> inline void qt_check_for_QOBJECT_macro(const ThisObject &_q_argument) const \
- { int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i + 1; }
-
-template <typename T>
-inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
-
-template <typename T1, typename T2>
-inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
-#endif // QT_NO_QOBJECT_CHECK
+// ### Qt6: remove
+#define Q_OBJECT_CHECK /* empty, unused since Qt 5.2 */
#if defined(Q_CC_INTEL)
// Cannot redefine the visibility of a method in an exported class
@@ -200,7 +174,6 @@ inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
/* qmake ignore Q_OBJECT */
#define Q_OBJECT \
public: \
- Q_OBJECT_CHECK \
QT_WARNING_PUSH \
Q_OBJECT_NO_OVERRIDE_WARNING \
static const QMetaObject staticMetaObject; \
@@ -267,6 +240,11 @@ private: \
#define Q_SLOT Q_SLOT
#endif //Q_MOC_RUN
+#ifdef Q_CLANG_QDOC
+#undef Q_GADGET
+#define Q_GADGET
+#endif
+
#ifndef QT_NO_META_MACROS
// macro for onaming members
#ifdef METHOD
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index 1768e8ccc6..3f5f2e78bb 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -50,8 +50,6 @@
#pragma qt_sync_stop_processing
#endif
-#include <type_traits>
-
QT_BEGIN_NAMESPACE
@@ -92,14 +90,9 @@ namespace QtPrivate {
explicit ApplyReturnValue(void *data_) : data(data_) {}
};
template<typename T, typename U>
- void operator,(const T &value, const ApplyReturnValue<U> &container) {
- if (container.data)
- *reinterpret_cast<U*>(container.data) = value;
- }
- template<typename T, typename U>
void operator,(T &&value, const ApplyReturnValue<U> &container) {
if (container.data)
- *reinterpret_cast<U*>(container.data) = value;
+ *reinterpret_cast<U *>(container.data) = std::forward<T>(value);
}
template<typename T>
void operator,(T, const ApplyReturnValue<void> &) {}
diff --git a/src/corelib/kernel/qppsobject.cpp b/src/corelib/kernel/qppsobject.cpp
index dd01d48cc0..d58715d12b 100644
--- a/src/corelib/kernel/qppsobject.cpp
+++ b/src/corelib/kernel/qppsobject.cpp
@@ -492,8 +492,7 @@ void QPpsObjectPrivate::encodeObject(pps_encoder_t *encoder, const QVariantMap &
///////////////////////////////////////////////////////////////////////////////
QPpsObject::QPpsObject(const QString &path, QObject *parent)
- : QObject(parent),
- d_ptr(new QPpsObjectPrivate(path))
+ : QObject(*new QPpsObjectPrivate(path), parent)
{
}
diff --git a/src/corelib/kernel/qppsobject_p.h b/src/corelib/kernel/qppsobject_p.h
index 86f4528c93..c7b99c8e42 100644
--- a/src/corelib/kernel/qppsobject_p.h
+++ b/src/corelib/kernel/qppsobject_p.h
@@ -118,7 +118,6 @@ Q_SIGNALS:
void readyRead();
private:
- QScopedPointer<QPpsObjectPrivate> d_ptr;
Q_DECLARE_PRIVATE(QPpsObject)
Q_DISABLE_COPY(QPpsObject)
};
diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp
index 07d4930332..be42a369c2 100644
--- a/src/corelib/kernel/qsharedmemory_win.cpp
+++ b/src/corelib/kernel/qsharedmemory_win.cpp
@@ -64,11 +64,6 @@ void QSharedMemoryPrivate::setErrorString(QLatin1String function)
errorString = QSharedMemory::tr("%1: already exists").arg(function);
break;
case ERROR_FILE_NOT_FOUND:
-#if defined(Q_OS_WINRT) && _MSC_VER < 1900
- // This happens on WinRT only if no file is present as CreateFileMappingW
- // bails out with this error code
- case ERROR_INVALID_PARAMETER:
-#endif
error = QSharedMemory::NotFound;
errorString = QSharedMemory::tr("%1: doesn't exist").arg(function);
break;
@@ -103,16 +98,9 @@ HANDLE QSharedMemoryPrivate::handle()
errorString = QSharedMemory::tr("%1: unable to make key").arg(function);
return 0;
}
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- hand = 0;
-#elif defined(Q_OS_WINRT)
-#if _MSC_VER >= 1900
+#if defined(Q_OS_WINRT)
hand = OpenFileMappingFromApp(FILE_MAP_ALL_ACCESS, FALSE, reinterpret_cast<PCWSTR>(nativeKey.utf16()));
#else
- hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, (PCWSTR)nativeKey.utf16());
-#endif
-#else
hand = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, (wchar_t*)nativeKey.utf16());
#endif
if (!hand) {
@@ -144,11 +132,7 @@ bool QSharedMemoryPrivate::create(int size)
}
// Create the file mapping.
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- Q_UNUSED(size)
- hand = 0;
-#elif defined(Q_OS_WINRT)
+#if defined(Q_OS_WINRT)
hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, size, (PCWSTR)nativeKey.utf16());
#else
hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, (wchar_t*)nativeKey.utf16());
@@ -166,12 +150,7 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
{
// Grab a pointer to the memory block
int permissions = (mode == QSharedMemory::ReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS);
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- Q_UNUSED(mode)
- Q_UNUSED(permissions)
- memory = 0;
-#elif defined(Q_OS_WINRT)
+#if defined(Q_OS_WINRT)
memory = (void *)MapViewOfFileFromApp(handle(), permissions, 0, 0);
#else
memory = (void *)MapViewOfFile(handle(), permissions, 0, 0, 0);
@@ -199,15 +178,10 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
bool QSharedMemoryPrivate::detach()
{
// umap memory
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- return false;
-#else
if (!UnmapViewOfFile(memory)) {
setErrorString(QLatin1String("QSharedMemory::detach"));
return false;
}
-#endif
memory = 0;
size = 0;
diff --git a/src/corelib/kernel/qsystemsemaphore_systemv.cpp b/src/corelib/kernel/qsystemsemaphore_systemv.cpp
index 1967899a58..83da09da44 100644
--- a/src/corelib/kernel/qsystemsemaphore_systemv.cpp
+++ b/src/corelib/kernel/qsystemsemaphore_systemv.cpp
@@ -72,7 +72,13 @@ QT_BEGIN_NAMESPACE
key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
{
if (key.isEmpty()){
- errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:"));
+ errorString =
+#if QT_CONFIG(translation)
+ QCoreApplication::tr("%1: key is empty", "QSystemSemaphore")
+#else
+ QString::fromLatin1("%1: key is empty")
+#endif
+ .arg(QLatin1String("QSystemSemaphore::handle:"));
error = QSystemSemaphore::KeyError;
return -1;
}
@@ -84,16 +90,30 @@ key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
// Create the file needed for ftok
int built = QSharedMemoryPrivate::createUnixKeyFile(fileName);
if (-1 == built) {
- errorString = QCoreApplication::tr("%1: unable to make key", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:"));
+ errorString =
+#if QT_CONFIG(translation)
+ QCoreApplication::tr("%1: unable to make key", "QSystemSemaphore")
+#else
+ QString::fromLatin1("%1: unable to make key")
+#endif
+ .arg(QLatin1String("QSystemSemaphore::handle:"));
error = QSystemSemaphore::KeyError;
return -1;
}
createdFile = (1 == built);
+#if !defined(QT_NO_SHAREDMEMORY) && !defined(QT_POSIX_IPC) && !defined(Q_OS_ANDROID)
// Get the unix key for the created file
unix_key = qt_safe_ftok(QFile::encodeName(fileName), 'Q');
+#endif
if (-1 == unix_key) {
- errorString = QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:"));
+ errorString =
+#if QT_CONFIG(translation)
+ QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore")
+#else
+ QString::fromLatin1("%1: ftok failed")
+#endif
+ .arg(QLatin1String("QSystemSemaphore::handle:"));
error = QSystemSemaphore::KeyError;
return -1;
}
diff --git a/src/corelib/kernel/qtcore_eval.cpp b/src/corelib/kernel/qtcore_eval.cpp
index 787db8a8a6..86992ce10b 100644
--- a/src/corelib/kernel/qtcore_eval.cpp
+++ b/src/corelib/kernel/qtcore_eval.cpp
@@ -207,7 +207,9 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include <qlabel.h>
#include <qlayout.h>
#include <qmessagebox.h>
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
#include <qtimer.h>
#include <qapplication.h>
QT_END_INCLUDE_NAMESPACE
diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h
index 9303f82544..6e61ca10cb 100644
--- a/src/corelib/kernel/qtimer.h
+++ b/src/corelib/kernel/qtimer.h
@@ -118,30 +118,30 @@ public:
}
// singleShot to a functor or function pointer (without context)
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), nullptr, slot);
}
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ 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 to a functor or function pointer (with context)
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, QObject *context, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), context, slot);
}
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ 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, QObject *context, Func1 slot)
{
//compilation error if the slot has arguments.
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 8ad61be8ee..e636c6fe52 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -649,6 +649,9 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QVariant::Bool:
*ba = QByteArray(d->data.b ? "true" : "false");
break;
+ case QVariant::Uuid:
+ *ba = v_cast<QUuid>(d)->toByteArray();
+ break;
default:
#ifndef QT_NO_QOBJECT
{
@@ -916,6 +919,9 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QVariant::String:
*static_cast<QUuid *>(result) = QUuid(*v_cast<QString>(d));
break;
+ case QVariant::ByteArray:
+ *static_cast<QUuid *>(result) = QUuid(*v_cast<QByteArray>(d));
+ break;
default:
return false;
}
@@ -2527,7 +2533,7 @@ QRegularExpression QVariant::toRegularExpression() const
\since 5.0
Returns the variant as a QUuid if the variant has type()
- \l QMetaType::QUuid or \l QMetaType::QString;
+ \l QMetaType::QUuid, \l QMetaType::QByteArray or \l QMetaType::QString;
otherwise returns a default-constructed QUuid.
\sa canConvert(), convert()
@@ -2875,7 +2881,8 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] =
/*QStringList*/ 1 << QVariant::List | 1 << QVariant::String,
/*QByteArray*/ 1 << QVariant::String | 1 << QVariant::Int | 1 << QVariant::UInt | 1 << QVariant::Bool
- | 1 << QVariant::Double | 1 << QVariant::LongLong | 1 << QVariant::ULongLong,
+ | 1 << QVariant::Double | 1 << QVariant::LongLong | 1 << QVariant::ULongLong
+ | 1 << QVariant::Uuid,
/*QBitArray*/ 0,
@@ -2911,12 +2918,12 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] =
/*QEasingCurve*/ 0,
-/*QUuid*/ 1 << QVariant::String
+/*QUuid*/ 1 << QVariant::String | 1 << QVariant::ByteArray,
};
static const size_t qCanConvertMatrixMaximumTargetType = 8 * sizeof(*qCanConvertMatrix);
#ifndef QT_BOOTSTRAPPED
-/*!
+/*
Returns \c true if from inherits to.
*/
static bool canConvertMetaObject(const QMetaObject *from, const QMetaObject *to)
@@ -2966,7 +2973,7 @@ static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject)
\l QMetaType::UInt, \l QMetaType::ULongLong
\row \li \l QMetaType::QByteArray \li \l QMetaType::Double,
\l QMetaType::Int, \l QMetaType::LongLong, \l QMetaType::QString,
- \l QMetaType::UInt, \l QMetaType::ULongLong
+ \l QMetaType::UInt, \l QMetaType::ULongLong, \l QMetaType::QUuid
\row \li \l QMetaType::QChar \li \l QMetaType::Bool, \l QMetaType::Int,
\l QMetaType::UInt, \l QMetaType::LongLong, \l QMetaType::ULongLong
\row \li \l QMetaType::QColor \li \l QMetaType::QString
@@ -3006,7 +3013,7 @@ static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject)
\row \li \l QMetaType::ULongLong \li \l QMetaType::Bool,
\l QMetaType::QChar, \l QMetaType::Double, \l QMetaType::Int,
\l QMetaType::LongLong, \l QMetaType::QString, \l QMetaType::UInt
- \row \li \l QMetaType::QUuid \li \l QMetaType::QString
+ \row \li \l QMetaType::QUuid \li \l QMetaType::QByteArray, \l QMetaType::QString
\endtable
A QVariant containing a pointer to a type derived from QObject will also return true for this
diff --git a/src/corelib/kernel/qwineventnotifier.h b/src/corelib/kernel/qwineventnotifier.h
index f17fa059a1..f29f325d13 100644
--- a/src/corelib/kernel/qwineventnotifier.h
+++ b/src/corelib/kernel/qwineventnotifier.h
@@ -42,7 +42,7 @@
#include "QtCore/qobject.h"
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/mimetypes/qmimeglobpattern_p.h b/src/corelib/mimetypes/qmimeglobpattern_p.h
index c8b70464fd..21332e71bc 100644
--- a/src/corelib/mimetypes/qmimeglobpattern_p.h
+++ b/src/corelib/mimetypes/qmimeglobpattern_p.h
@@ -83,11 +83,9 @@ public:
static const unsigned MinWeight = 1;
explicit QMimeGlobPattern(const QString &thePattern, const QString &theMimeType, unsigned theWeight = DefaultWeight, Qt::CaseSensitivity s = Qt::CaseInsensitive) :
- m_pattern(thePattern), m_mimeType(theMimeType), m_weight(theWeight), m_caseSensitivity(s)
+ m_pattern(s == Qt::CaseInsensitive ? thePattern.toLower() : thePattern),
+ m_mimeType(theMimeType), m_weight(theWeight), m_caseSensitivity(s)
{
- if (s == Qt::CaseInsensitive) {
- m_pattern = m_pattern.toLower();
- }
}
void swap(QMimeGlobPattern &other) Q_DECL_NOTHROW
diff --git a/src/corelib/mimetypes/qmimetypeparser.cpp b/src/corelib/mimetypes/qmimetypeparser.cpp
index 7693055cc1..20b4461b03 100644
--- a/src/corelib/mimetypes/qmimetypeparser.cpp
+++ b/src/corelib/mimetypes/qmimetypeparser.cpp
@@ -165,7 +165,8 @@ bool QMimeTypeParserBase::parseNumber(const QStringRef &n, int *target, QString
bool ok;
*target = n.toInt(&ok);
if (Q_UNLIKELY(!ok)) {
- *errorMessage = QLatin1String("Not a number '") + n + QLatin1String("'.");
+ if (errorMessage)
+ *errorMessage = QLatin1String("Not a number '") + n + QLatin1String("'.");
return false;
}
return true;
diff --git a/src/corelib/plugin/qelfparser_p.cpp b/src/corelib/plugin/qelfparser_p.cpp
index 85478e376e..7a42b0d023 100644
--- a/src/corelib/plugin/qelfparser_p.cpp
+++ b/src/corelib/plugin/qelfparser_p.cpp
@@ -71,7 +71,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (fdlen < 64){
if (lib)
- lib->errorString = QLibrary::tr("'%1' is not an ELF object (%2)").arg(library).arg(QLatin1String("file too small"));
+ lib->errorString = QLibrary::tr("'%1' is not an ELF object (%2)").arg(library, QLibrary::tr("file too small"));
return NotElf;
}
const char *data = dataStart;
@@ -83,7 +83,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
// 32 or 64 bit
if (data[4] != 1 && data[4] != 2) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("odd cpu architecture"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("odd cpu architecture"));
return Corrupt;
}
m_bits = (data[4] << 5);
@@ -93,13 +93,13 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
*/
if ((sizeof(void*) == 4 && m_bits != 32) || (sizeof(void*) == 8 && m_bits != 64)) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("wrong cpu architecture"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("wrong cpu architecture"));
return Corrupt;
}
// endian
if (data[5] == 0) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("odd endianness"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("odd endianness"));
return Corrupt;
}
m_endian = (data[5] == 1 ? ElfLittleEndian : ElfBigEndian);
@@ -119,7 +119,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (e_shsize > fdlen) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("unexpected e_shsize"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shsize"));
return Corrupt;
}
@@ -131,7 +131,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (e_shentsize % 4){
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("unexpected e_shentsize"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shentsize"));
return Corrupt;
}
data += sizeof(qelfhalf_t); // e_shentsize
@@ -141,10 +141,12 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
data += sizeof(qelfhalf_t); // e_shtrndx
if ((quint32)(e_shnum * e_shentsize) > fdlen) {
- if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("announced %2 sections, each %3 bytes, exceed file size"))
- .arg(e_shnum).arg(e_shentsize);
+ if (lib) {
+ const QString message =
+ QLibrary::tr("announced %n section(s), each %1 byte(s), exceed file size",
+ nullptr, int(e_shnum)).arg(e_shentsize);
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, message);
+ }
return Corrupt;
}
@@ -157,9 +159,9 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("shstrtab section header seems to be at %1"))
- .arg(QString::number(soff, 16));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("shstrtab section header seems to be at %1")
+ .arg(QString::number(soff, 16)));
return Corrupt;
}
@@ -168,9 +170,9 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if ((quint32)(m_stringTableFileOffset + e_shentsize) >= fdlen || m_stringTableFileOffset == 0) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("string table seems to be at %1"))
- .arg(QString::number(soff, 16));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("string table seems to be at %1")
+ .arg(QString::number(soff, 16)));
return Corrupt;
}
@@ -190,9 +192,9 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (m_stringTableFileOffset + sh.name > fdlen) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("section name %2 of %3 behind end of file"))
- .arg(i).arg(e_shnum);
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("section name %1 of %2 behind end of file")
+ .arg(i).arg(e_shnum));
return Corrupt;
}
@@ -204,8 +206,8 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (!(sh.type & 0x1)) {
if (shnam[1] == 'r') {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("empty .rodata. not a library."));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("empty .rodata. not a library."));
return Corrupt;
}
#if defined(QELFPARSER_DEBUG)
@@ -217,8 +219,8 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (sh.offset == 0 || (sh.offset + sh.size) > fdlen || sh.size < 1) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("missing section data. This is not a library."));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("missing section data. This is not a library."));
return Corrupt;
}
*pos = sh.offset;
diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp
index 6c1253ea08..3c4fbaf348 100644
--- a/src/corelib/plugin/qlibrary_unix.cpp
+++ b/src/corelib/plugin/qlibrary_unix.cpp
@@ -242,7 +242,7 @@ bool QLibraryPrivate::load_sys()
}
#endif
if (!pHnd) {
- errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qdlerror());
+ errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror());
}
if (pHnd) {
qualifiedFileName = attempt;
@@ -262,10 +262,10 @@ bool QLibraryPrivate::unload_sys()
char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance
if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative"
return true;
- errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName)
- .arg(QLatin1String(error));
+ errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName,
+ QLatin1String(error));
#else
- errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName).arg(qdlerror());
+ errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName, qdlerror());
#endif
return false;
}
@@ -298,7 +298,7 @@ QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
#endif
if (!address) {
errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg(
- QString::fromLatin1(symbol)).arg(fileName).arg(qdlerror());
+ QString::fromLatin1(symbol), fileName, qdlerror());
} else {
errorString.clear();
}
diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp
index f11ac6548b..0afce7fcf0 100644
--- a/src/corelib/plugin/quuid.cpp
+++ b/src/corelib/plugin/quuid.cpp
@@ -968,10 +968,10 @@ QUuid QUuid::createUuid()
if (!uuidseed.hasLocalData())
{
int *pseed = new int;
- static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(2);
+ static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
qsrand(*pseed = QDateTime::currentSecsSinceEpoch()
+ quintptr(&pseed)
- + serial.fetchAndAddRelaxed(1));
+ + 2 + serial.fetchAndAddRelaxed(1));
uuidseed.setLocalData(pseed);
}
#else
diff --git a/src/corelib/statemachine/qfinalstate_p.h b/src/corelib/statemachine/qfinalstate_p.h
index 57de703fe9..65598f6c19 100644
--- a/src/corelib/statemachine/qfinalstate_p.h
+++ b/src/corelib/statemachine/qfinalstate_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 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:LGPL21$
+** $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 http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** 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 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** 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.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** 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$
**
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index d7cdec9aac..1d80da55c9 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -2331,6 +2331,7 @@ void QStateMachinePrivate::unregisterAllTransitions()
unregisterSignalTransition(t);
}
}
+#if QT_CONFIG(qeventtransition)
{
QList<QEventTransition*> transitions = rootState()->findChildren<QEventTransition*>();
for (int i = 0; i < transitions.size(); ++i) {
@@ -2339,6 +2340,7 @@ void QStateMachinePrivate::unregisterAllTransitions()
unregisterEventTransition(t);
}
}
+#endif
}
#if QT_CONFIG(qeventtransition)
diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h
index 06bb4bc8f1..5c4c02a2ec 100644
--- a/src/corelib/thread/qgenericatomic.h
+++ b/src/corelib/thread/qgenericatomic.h
@@ -283,7 +283,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
// implement fetchAndAnd on top of testAndSet
T tmp = BaseClass::load(_q_value);
@@ -294,7 +294,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand);
BaseClass::acquireMemoryFence(_q_value);
@@ -302,21 +302,21 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::releaseMemoryFence(_q_value);
return BaseClass::fetchAndAndRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::orderedMemoryFence(_q_value);
return BaseClass::fetchAndAndRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
// implement fetchAndOr on top of testAndSet
T tmp = BaseClass::load(_q_value);
@@ -327,7 +327,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand);
BaseClass::acquireMemoryFence(_q_value);
@@ -335,21 +335,21 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::releaseMemoryFence(_q_value);
return BaseClass::fetchAndOrRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::orderedMemoryFence(_q_value);
return BaseClass::fetchAndOrRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
// implement fetchAndXor on top of testAndSet
T tmp = BaseClass::load(_q_value);
@@ -360,7 +360,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand);
BaseClass::acquireMemoryFence(_q_value);
@@ -368,14 +368,14 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::releaseMemoryFence(_q_value);
return BaseClass::fetchAndXorRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::orderedMemoryFence(_q_value);
return BaseClass::fetchAndXorRelaxed(_q_value, operand);
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index 29095f8b51..7e3610f0b3 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -266,8 +266,8 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
/*! \fn bool QMutex::try_lock()
\since 5.8
- This function returns \c true if the lock was obtained; otherwise it
- returns \c false.
+ Attempts to lock the mutex. This function returns \c true if the lock
+ was obtained; otherwise it returns \c false.
This function is provided for compatibility with the Standard Library
concept \c Lockable. It is equivalent to tryLock().
@@ -342,16 +342,23 @@ void QMutex::unlock() Q_DECL_NOTHROW
unlockInternal();
}
+
+/*!
+ \fn bool QMutex::isRecursive() const
+ \since 5.7
+
+ Returns \c true if the mutex is recursive.
+*/
+
bool QBasicMutex::isRecursive() Q_DECL_NOTHROW
{
return QT_PREPEND_NAMESPACE(isRecursive)(d_ptr.loadAcquire());
}
/*!
- \overload
\since 5.7
- Returns \c true if the mutex is recursive
+ Returns \c true if the mutex is recursive.
*/
bool QBasicMutex::isRecursive() const Q_DECL_NOTHROW
{
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
index 056ebdeaa5..12987f16c3 100644
--- a/src/corelib/thread/qmutex.h
+++ b/src/corelib/thread/qmutex.h
@@ -54,7 +54,7 @@ class tst_QMutex;
QT_BEGIN_NAMESPACE
-#if !defined(QT_NO_THREAD) && !defined(Q_QDOC)
+#if !defined(QT_NO_THREAD) || defined(Q_CLANG_QDOC)
#ifdef Q_OS_LINUX
# define QT_MUTEX_LOCK_NOEXCEPT Q_DECL_NOTHROW
@@ -189,6 +189,7 @@ private:
class Q_CORE_EXPORT QMutexLocker
{
public:
+#ifndef Q_CLANG_QDOC
inline explicit QMutexLocker(QBasicMutex *m) QT_MUTEX_LOCK_NOEXCEPT
{
Q_ASSERT_X((reinterpret_cast<quintptr>(m) & quintptr(1u)) == quintptr(0),
@@ -200,6 +201,9 @@ public:
val |= 1;
}
}
+#else
+ QMutexLocker(QMutex *) { }
+#endif
inline ~QMutexLocker() { unlock(); }
inline void unlock() Q_DECL_NOTHROW
@@ -240,7 +244,7 @@ private:
quintptr val;
};
-#else // QT_NO_THREAD or Q_QDOC
+#else // QT_NO_THREAD && !Q_CLANG_QDOC
class Q_CORE_EXPORT QMutex
{
@@ -255,7 +259,7 @@ public:
inline void unlock() Q_DECL_NOTHROW {}
inline bool isRecursive() const Q_DECL_NOTHROW { return true; }
-#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC)
+#if QT_HAS_INCLUDE(<chrono>)
template <class Rep, class Period>
inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) Q_DECL_NOTHROW
{
@@ -291,7 +295,7 @@ private:
typedef QMutex QBasicMutex;
-#endif // QT_NO_THREAD or Q_QDOC
+#endif // QT_NO_THREAD && !Q_CLANG_QDOC
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index c08038cf90..0828400733 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -149,6 +149,14 @@ QThreadPrivate::QThreadPrivate(QThreadData *d)
exited(false), returnCode(-1),
stackSize(0), priority(QThread::InheritPriority), data(d)
{
+
+// INTEGRITY doesn't support self-extending stack. The default stack size for
+// a pthread on INTEGRITY is too small so we have to increase the default size
+// to 128K.
+#ifdef Q_OS_INTEGRITY
+ stackSize = 128 * 1024;
+#endif
+
#if defined (Q_OS_WIN)
handle = 0;
# ifndef Q_OS_WINRT
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index 6d00aa42ff..f359d25a73 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -211,25 +211,25 @@ static void clear_thread_data()
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, Qt::HANDLE>::Type to_HANDLE(T id)
+static typename std::enable_if<QTypeInfo<T>::isIntegral, Qt::HANDLE>::type to_HANDLE(T id)
{
return reinterpret_cast<Qt::HANDLE>(static_cast<intptr_t>(id));
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type from_HANDLE(Qt::HANDLE id)
+static typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type from_HANDLE(Qt::HANDLE id)
{
return static_cast<T>(reinterpret_cast<intptr_t>(id));
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isPointer, Qt::HANDLE>::Type to_HANDLE(T id)
+static typename std::enable_if<QTypeInfo<T>::isPointer, Qt::HANDLE>::type to_HANDLE(T id)
{
return id;
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isPointer, T>::Type from_HANDLE(Qt::HANDLE id)
+static typename std::enable_if<QTypeInfo<T>::isPointer, T>::type from_HANDLE(Qt::HANDLE id)
{
return static_cast<T>(id);
}
diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp
index 7ce757064f..e45aaec103 100644
--- a/src/corelib/thread/qthreadpool.cpp
+++ b/src/corelib/thread/qthreadpool.cpp
@@ -245,7 +245,8 @@ void QThreadPoolPrivate::startThread(QRunnable *runnable)
{
QScopedPointer <QThreadPoolThread> thread(new QThreadPoolThread(this));
thread->setObjectName(QLatin1String("Thread (pooled)"));
- allThreads.insert(thread.data());
+ Q_ASSERT(!allThreads.contains(thread.data())); // if this assert hits, we have an ABA problem (deleted threads don't get removed here)
+ allThreads.append(thread.data());
++activeThreads;
if (runnable->autoDelete())
@@ -265,7 +266,7 @@ void QThreadPoolPrivate::reset()
while (!allThreads.empty()) {
// move the contents of the set out so that we can iterate without the lock
- QSet<QThreadPoolThread *> allThreadsCopy;
+ QList<QThreadPoolThread *> allThreadsCopy;
allThreadsCopy.swap(allThreads);
locker.unlock();
@@ -315,22 +316,39 @@ void QThreadPoolPrivate::clear()
}
/*!
- \internal
- Searches for \a runnable in the queue, removes it from the queue and
- returns \c true if it was found in the queue
+ \since 5.9
+
+ Attempts to remove the specified \a runnable from the queue if it is not yet started.
+ If the runnable had not been started, returns \c true, and ownership of \a runnable
+ is transferred to the caller (even when \c{runnable->autoDelete() == true}).
+ Otherwise returns \c false.
+
+ \note If \c{runnable->autoDelete() == true}, this function may remove the wrong
+ runnable. This is known as the \l{https://en.wikipedia.org/wiki/ABA_problem}{ABA problem}:
+ the original \a runnable may already have executed and has since been deleted.
+ The memory is re-used for another runnable, which then gets removed instead of
+ the intended one. For this reason, we recommend calling this function only for
+ runnables that are not auto-deleting.
+
+ \sa start(), QRunnable::autoDelete()
*/
-bool QThreadPoolPrivate::stealRunnable(QRunnable *runnable)
+bool QThreadPool::tryTake(QRunnable *runnable)
{
+ Q_D(QThreadPool);
+
if (runnable == 0)
return false;
{
- QMutexLocker locker(&mutex);
- QVector<QPair<QRunnable *, int> >::iterator it = queue.begin();
- QVector<QPair<QRunnable *, int> >::iterator end = queue.end();
+ QMutexLocker locker(&d->mutex);
+
+ auto it = d->queue.begin();
+ auto end = d->queue.end();
while (it != end) {
if (it->first == runnable) {
- queue.erase(it);
+ d->queue.erase(it);
+ if (runnable->autoDelete())
+ --runnable->ref; // undo ++ref in start()
return true;
}
++it;
@@ -348,10 +366,10 @@ bool QThreadPoolPrivate::stealRunnable(QRunnable *runnable)
*/
void QThreadPoolPrivate::stealAndRunRunnable(QRunnable *runnable)
{
- if (!stealRunnable(runnable))
+ Q_Q(QThreadPool);
+ if (!q->tryTake(runnable))
return;
- const bool autoDelete = runnable->autoDelete();
- bool del = autoDelete && !--runnable->ref;
+ const bool del = runnable->autoDelete() && !runnable->ref; // tryTake already deref'ed
runnable->run();
@@ -641,24 +659,23 @@ void QThreadPool::clear()
d->clear();
}
+#if QT_DEPRECATED_SINCE(5, 9)
/*!
\since 5.5
+ \obsolete use tryTake() instead, but note the different deletion rules.
Removes the specified \a runnable from the queue if it is not yet started.
The runnables for which \l{QRunnable::autoDelete()}{runnable->autoDelete()}
returns \c true are deleted.
- \sa start()
+ \sa start(), tryTake()
*/
void QThreadPool::cancel(QRunnable *runnable)
{
- Q_D(QThreadPool);
- if (!d->stealRunnable(runnable))
- return;
- if (runnable->autoDelete() && !--runnable->ref) {
+ if (tryTake(runnable) && runnable->autoDelete() && !runnable->ref) // tryTake already deref'ed
delete runnable;
- }
}
+#endif
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h
index 0ad63c5ac3..74a8c28fc8 100644
--- a/src/corelib/thread/qthreadpool.h
+++ b/src/corelib/thread/qthreadpool.h
@@ -83,7 +83,12 @@ public:
bool waitForDone(int msecs = -1);
void clear();
+
+#if QT_DEPRECATED_SINCE(5, 9)
+ QT_DEPRECATED_X("use tryTake(), but note the different deletion rules")
void cancel(QRunnable *runnable);
+#endif
+ bool tryTake(QRunnable *runnable) Q_REQUIRED_RESULT;
};
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h
index 5694bc8b10..4a9f9e5cfa 100644
--- a/src/corelib/thread/qthreadpool_p.h
+++ b/src/corelib/thread/qthreadpool_p.h
@@ -82,11 +82,10 @@ public:
void reset();
bool waitForDone(int msecs);
void clear();
- bool stealRunnable(QRunnable *runnable);
void stealAndRunRunnable(QRunnable *runnable);
mutable QMutex mutex;
- QSet<QThreadPoolThread *> allThreads;
+ QList<QThreadPoolThread *> allThreads;
QQueue<QThreadPoolThread *> waitingThreads;
QQueue<QThreadPoolThread *> expiredThreads;
QVector<QPair<QRunnable *, int> > queue;
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 55af7256be..a04536b18b 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -63,6 +63,29 @@ QT_WARNING_POP
static const QArrayData &qt_array_empty = qt_array[0];
static const QArrayData &qt_array_unsharable_empty = qt_array[1];
+static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize,
+ uint options)
+{
+ // Calculate the byte size
+ // allocSize = objectSize * capacity + headerSize, but checked for overflow
+ // plus padded to grow in size
+ if (options & QArrayData::Grow) {
+ auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
+ capacity = r.elementCount;
+ return r.size;
+ } else {
+ return qCalculateBlockSize(capacity, objectSize, headerSize);
+ }
+}
+
+static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint options)
+{
+ header = static_cast<QArrayData *>(::realloc(header, allocSize));
+ if (header)
+ header->capacityReserved = bool(options & QArrayData::CapacityReserved);
+ return header;
+}
+
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options) Q_DECL_NOTHROW
{
@@ -91,18 +114,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
if (headerSize > size_t(MaxAllocSize))
return 0;
- // Calculate the byte size
- // allocSize = objectSize * capacity + headerSize, but checked for overflow
- // plus padded to grow in size
- size_t allocSize;
- if (options & Grow) {
- auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
- capacity = r.elementCount;
- allocSize = r.size;
- } else {
- allocSize = qCalculateBlockSize(capacity, objectSize, headerSize);
- }
-
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
if (header) {
quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
@@ -122,6 +134,21 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
return header;
}
+QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity,
+ AllocationOptions options) Q_DECL_NOTHROW
+{
+ Q_ASSERT(data);
+ Q_ASSERT(data->isMutable());
+ Q_ASSERT(!data->ref.isShared());
+
+ size_t headerSize = sizeof(QArrayData);
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
+ QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options));
+ if (header)
+ header->alloc = capacity;
+ return header;
+}
+
void QArrayData::deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW
{
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index 5a369baf08..bc20932cca 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -115,6 +115,9 @@ struct Q_CORE_EXPORT QArrayData
static QArrayData *allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options = Default)
Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+ static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize,
+ size_t newCapacity, AllocationOptions newOptions = Default)
+ Q_DECL_NOTHROW Q_REQUIRED_RESULT;
static void deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW;
@@ -222,6 +225,14 @@ struct QTypedArrayData
Q_ALIGNOF(AlignmentDummy), capacity, options));
}
+ static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity,
+ AllocationOptions options = Default)
+ {
+ Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
+ return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T),
+ capacity, options));
+ }
+
static void deallocate(QArrayData *data)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 6bb8280ca8..ae83e6986e 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -145,7 +145,7 @@ struct QGenericArrayOps
T *const begin = this->begin();
do {
- new (begin + this->size) T();
+ new (begin + this->size) T;
} while (uint(++this->size) != newSize);
}
@@ -411,18 +411,18 @@ struct QArrayOpsSelector
template <class T>
struct QArrayOpsSelector<T,
- typename QEnableIf<
- !QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
- >::Type>
+ typename std::enable_if<
+ !QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ >::type>
{
typedef QPodArrayOps<T> Type;
};
template <class T>
struct QArrayOpsSelector<T,
- typename QEnableIf<
- QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
- >::Type>
+ typename std::enable_if<
+ QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ >::type>
{
typedef QMovableArrayOps<T> Type;
};
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 9298472305..329cc358d4 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -541,15 +541,40 @@ static const quint16 crc_tbl[16] = {
Returns the CRC-16 checksum of the first \a len bytes of \a data.
- The checksum is independent of the byte order (endianness).
+ The checksum is independent of the byte order (endianness) and will be
+ calculated accorded to the algorithm published in ISO 3309 (Qt::ChecksumIso3309).
\note This function is a 16-bit cache conserving (16 entry table)
implementation of the CRC-16-CCITT algorithm.
*/
-
quint16 qChecksum(const char *data, uint len)
{
- quint16 crc = 0xffff;
+ return qChecksum(data, len, Qt::ChecksumIso3309);
+}
+
+/*!
+ \relates QByteArray
+ \since 5.9
+
+ Returns the CRC-16 checksum of the first \a len bytes of \a data.
+
+ The checksum is independent of the byte order (endianness) and will
+ be calculated accorded to the algorithm published in \a standard.
+
+ \note This function is a 16-bit cache conserving (16 entry table)
+ implementation of the CRC-16-CCITT algorithm.
+*/
+quint16 qChecksum(const char *data, uint len, Qt::ChecksumType standard)
+{
+ quint16 crc = 0x0000;
+ switch (standard) {
+ case Qt::ChecksumIso3309:
+ crc = 0xffff;
+ break;
+ case Qt::ChecksumItuV41:
+ crc = 0x6363;
+ break;
+ }
uchar c;
const uchar *p = reinterpret_cast<const uchar *>(data);
while (len--) {
@@ -558,7 +583,14 @@ quint16 qChecksum(const char *data, uint len)
c >>= 4;
crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)];
}
- return ~crc & 0xffff;
+ switch (standard) {
+ case Qt::ChecksumIso3309:
+ crc = ~crc;
+ break;
+ case Qt::ChecksumItuV41:
+ break;
+ }
+ return crc & 0xffff;
}
/*!
@@ -663,6 +695,20 @@ QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel)
*/
#ifndef QT_NO_COMPRESS
+namespace {
+struct QByteArrayDataDeleter
+{
+ static inline void cleanup(QTypedArrayData<char> *d)
+ { if (d) QTypedArrayData<char>::deallocate(d); }
+};
+}
+
+static QByteArray invalidCompressedData()
+{
+ qWarning("qUncompress: Input data is corrupted");
+ return QByteArray();
+}
+
QByteArray qUncompress(const uchar* data, int nbytes)
{
if (!data) {
@@ -677,53 +723,29 @@ QByteArray qUncompress(const uchar* data, int nbytes)
ulong expectedSize = uint((data[0] << 24) | (data[1] << 16) |
(data[2] << 8) | (data[3] ));
ulong len = qMax(expectedSize, 1ul);
- QScopedPointer<QByteArray::Data, QScopedPointerPodDeleter> d;
+ const ulong maxPossibleSize = MaxAllocSize - sizeof(QByteArray::Data);
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ }
+
+ QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1));
+ if (Q_UNLIKELY(d.data() == nullptr))
+ return invalidCompressedData();
+ d->size = expectedSize;
forever {
ulong alloc = len;
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + alloc + 1));
- if (!p) {
- // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
- qWarning("qUncompress: could not allocate enough memory to uncompress data");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- d->offset = sizeof(QByteArrayData);
- d->size = 0; // Shut up valgrind "uninitialized variable" warning
int res = ::uncompress((uchar*)d->data(), &len,
data+4, nbytes-4);
switch (res) {
case Z_OK:
- if (len != alloc) {
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + len + 1));
- if (!p) {
- // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
- qWarning("qUncompress: could not allocate enough memory to uncompress data");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- }
- d->ref.initializeOwned();
+ Q_ASSERT(len <= alloc);
+ Q_UNUSED(alloc);
d->size = len;
- d->alloc = uint(len) + 1u;
- d->capacityReserved = false;
- d->offset = sizeof(QByteArrayData);
d->data()[len] = 0;
-
{
QByteArrayDataPtr dataPtr = { d.take() };
return QByteArray(dataPtr);
@@ -735,6 +757,17 @@ QByteArray qUncompress(const uchar* data, int nbytes)
case Z_BUF_ERROR:
len *= 2;
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ } else {
+ // grow the block
+ QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), len + 1);
+ if (Q_UNLIKELY(p == nullptr))
+ return invalidCompressedData();
+ d.take(); // don't free
+ d.reset(p);
+ }
continue;
case Z_DATA_ERROR:
@@ -1707,19 +1740,8 @@ void QByteArray::reallocData(uint alloc, Data::AllocationOptions options)
Data::deallocate(d);
d = x;
} else {
- size_t blockSize;
- if (options & Data::Grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
-
- Data *x = static_cast<Data *>(::realloc(d, blockSize));
+ Data *x = Data::reallocateUnaligned(d, alloc, options);
Q_CHECK_PTR(x);
- x->alloc = alloc;
- x->capacityReserved = (options & Data::CapacityReserved) ? 1 : 0;
d = x;
}
}
@@ -4365,12 +4387,41 @@ QByteArray QByteArray::fromHex(const QByteArray &hexEncoded)
*/
QByteArray QByteArray::toHex() const
{
- QByteArray hex(d->size * 2, Qt::Uninitialized);
+ return toHex('\0');
+}
+
+/*! \overload
+ \since 5.9
+
+ Returns a hex encoded copy of the byte array. The hex encoding uses the numbers 0-9 and
+ the letters a-f.
+
+ If \a separator is not '\0', the separator character is inserted between the hex bytes.
+
+ Example:
+ \code
+ QByteArray macAddress = QByteArray::fromHex("123456abcdef");
+ macAddress.toHex(':'); // returns "12:34:56:ab:cd:ef"
+ macAddress.toHex(0); // returns "123456abcdef"
+ \endcode
+
+ \sa fromHex()
+*/
+QByteArray QByteArray::toHex(char separator) const
+{
+ if (!d->size)
+ return QByteArray();
+
+ const int length = separator ? (d->size * 3 - 1) : (d->size * 2);
+ QByteArray hex(length, Qt::Uninitialized);
char *hexData = hex.data();
const uchar *data = (const uchar *)d->data();
- for (int i = 0; i < d->size; ++i) {
- hexData[i*2] = QtMiscUtils::toHexLower(data[i] >> 4);
- hexData[i*2+1] = QtMiscUtils::toHexLower(data[i] & 0xf);
+ for (int i = 0, o = 0; i < d->size; ++i) {
+ hexData[o++] = QtMiscUtils::toHexLower(data[i] >> 4);
+ hexData[o++] = QtMiscUtils::toHexLower(data[i] & 0xf);
+
+ if ((separator) && (o < length))
+ hexData[o++] = separator;
}
return hex;
}
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 477402d6de..06a50e5990 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -105,8 +105,8 @@ Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap);
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt, ...);
// qChecksum: Internet checksum
-
-Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len);
+Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len); // ### Qt 6: Remove
+Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len, Qt::ChecksumType standard); // ### Qt 6: Use Qt::ChecksumType standard = Qt::ChecksumIso3309
class QByteRef;
class QString;
@@ -140,8 +140,6 @@ struct QByteArrayDataPtr
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QByteArrayData)) \
/**/
-#if defined(Q_COMPILER_LAMBDA)
-
# define QByteArrayLiteral(str) \
([]() -> QByteArray { \
enum { Size = sizeof(str) - 1 }; \
@@ -154,14 +152,6 @@ struct QByteArrayDataPtr
}()) \
/**/
-#endif
-
-#ifndef QByteArrayLiteral
-// no lambdas, not GCC, just return a temporary QByteArray
-
-# define QByteArrayLiteral(str) QByteArray(str, sizeof(str) - 1)
-#endif
-
class Q_CORE_EXPORT QByteArray
{
private:
@@ -252,7 +242,7 @@ public:
void truncate(int pos);
void chop(int n);
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT")
@@ -357,6 +347,7 @@ public:
QByteArray toBase64(Base64Options options) const;
QByteArray toBase64() const; // ### Qt6 merge with previous
QByteArray toHex() const;
+ QByteArray toHex(char separator) const; // ### Qt6 merge with previous
QByteArray toPercentEncoding(const QByteArray &exclude = QByteArray(),
const QByteArray &include = QByteArray(),
char percent = '%') const;
diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp
index d06ca1292a..76af726ef9 100644
--- a/src/corelib/tools/qbytearraymatcher.cpp
+++ b/src/corelib/tools/qbytearraymatcher.cpp
@@ -323,4 +323,112 @@ int qFindByteArray(
return -1;
}
+/*!
+ \class QStaticByteArrayMatcherBase
+ \since 5.9
+ \internal
+ \brief Non-template base class of QStaticByteArrayMatcher.
+*/
+
+/*!
+ \class QStaticByteArrayMatcher
+ \since 5.9
+ \inmodule QtCore
+ \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher
+
+ \ingroup tools
+ \ingroup string-processing
+
+ This class is useful when you have a sequence of bytes that you
+ want to repeatedly match against some byte arrays (perhaps in a
+ loop), or when you want to search for the same sequence of bytes
+ multiple times in the same byte array. Using a matcher object and
+ indexIn() is faster than matching a plain QByteArray with
+ QByteArray::indexOf(), in particular if repeated matching takes place.
+
+ Unlike QByteArrayMatcher, this class calculates the internal
+ representation at \e{compile-time}, if your compiler supports
+ C++14-level \c{constexpr} (C++11 is not sufficient), so it can
+ even benefit if you are doing one-off byte array matches.
+
+ Create the QStaticByteArrayMatcher by calling qMakeStaticByteArrayMatcher(),
+ passing it the C string literal you want to search for. Store the return
+ value of that function in a \c{static const auto} variable, so you don't need
+ to pass the \c{N} template parameter explicitly:
+
+ \code
+ static const auto matcher = qMakeStaticByteArrayMatcher("needle");
+ \endcode
+
+ Then call indexIn() on the QByteArray in which you want to search, just like
+ with QByteArrayMatcher.
+
+ Since this class is designed to do all the up-front calculations at compile-time,
+ it does not offer a setPattern() method.
+
+ \sa QByteArrayMatcher, QStringMatcher
+*/
+
+/*!
+ \fn int QStaticByteArrayMatcher::indexIn(const char *haystack, int hlen, int from = 0) const
+
+ Searches the char string \a haystack, which has length \a hlen, from
+ byte position \a from (default 0, i.e. from the first byte), for
+ the byte array pattern() that was set in the constructor.
+
+ Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
+*/
+
+/*!
+ \fn int QStaticByteArrayMatcher::indexIn(const QByteArray &haystack, int from = 0) const
+
+ Searches the char string \a haystack, from byte position \a from
+ (default 0, i.e. from the first byte), for the byte array pattern()
+ that was set in the constructor.
+
+ Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
+*/
+
+/*!
+ \fn QByteArray QStaticByteArrayMatcher::pattern() const
+
+ Returns the byte array pattern that this byte array matcher will
+ search for.
+
+ \sa setPattern()
+*/
+
+/*!
+ \internal
+*/
+int QStaticByteArrayMatcherBase::indexOfIn(const char *needle, uint nlen, const char *haystack, int hlen, int from) const Q_DECL_NOTHROW
+{
+ if (from < 0)
+ from = 0;
+ return bm_find(reinterpret_cast<const uchar *>(haystack), hlen, from,
+ reinterpret_cast<const uchar *>(needle), nlen, m_skiptable.data);
+}
+
+/*!
+ \fn QStaticByteArrayMatcher::QStaticByteArrayMatcher(const char (&pattern)[N])
+ \internal
+*/
+
+/*!
+ \fn qMakeStaticByteArrayMatcher(const char (&pattern)[N])
+ \since 5.9
+ \relates QStaticByteArrayMatcher
+
+ Return a QStaticByteArrayMatcher with the correct \c{N} determined
+ automatically from the \a pattern passed.
+
+ To take full advantage of this function, assign the result to an
+ \c{auto} variable:
+
+ \code
+ static const auto matcher = qMakeStaticByteArrayMatcher("needle");
+ \endcode
+*/
+
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h
index aac62715a1..c1c0c3a660 100644
--- a/src/corelib/tools/qbytearraymatcher.h
+++ b/src/corelib/tools/qbytearraymatcher.h
@@ -83,6 +83,87 @@ private:
};
};
+class QStaticByteArrayMatcherBase
+{
+ Q_DECL_ALIGN(16)
+ struct Skiptable {
+ uchar data[256];
+ } m_skiptable;
+protected:
+ explicit Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcherBase(const char *pattern, uint n) Q_DECL_NOTHROW
+ : m_skiptable(generate(pattern, n)) {}
+ // compiler-generated copy/more ctors/assignment operators are ok!
+ // compiler-generated dtor is ok!
+
+ Q_CORE_EXPORT int indexOfIn(const char *needle, uint nlen, const char *haystack, int hlen, int from) const Q_DECL_NOTHROW;
+
+private:
+ static Q_DECL_RELAXED_CONSTEXPR Skiptable generate(const char *pattern, uint n) Q_DECL_NOTHROW
+ {
+ const auto uchar_max = (std::numeric_limits<uchar>::max)();
+ uchar max = n > uchar_max ? uchar_max : n;
+ Skiptable table = {
+ // this verbose initialization code aims to avoid some opaque error messages
+ // even on powerful compilers such as GCC 5.3. Even though for GCC a loop
+ // format can be found that v5.3 groks, it's probably better to go with this
+ // for the time being:
+ {
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ }
+ };
+ pattern += n - max;
+ while (max--)
+ table.data[uchar(*pattern++)] = max;
+ return table;
+ }
+};
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_MSVC(4351) // MSVC 2013: "new behavior: elements of array ... will be default initialized"
+ // remove once we drop MSVC 2013 support
+template <uint N>
+class QStaticByteArrayMatcher : QStaticByteArrayMatcherBase
+{
+ char m_pattern[N];
+ Q_STATIC_ASSERT_X(N > 2, "QStaticByteArrayMatcher makes no sense for finding a single-char pattern");
+public:
+ explicit Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcher(const char (&patternToMatch)[N]) Q_DECL_NOTHROW
+ : QStaticByteArrayMatcherBase(patternToMatch, N - 1), m_pattern()
+ {
+ for (uint i = 0; i < N; ++i)
+ m_pattern[i] = patternToMatch[i];
+ }
+
+ int indexIn(const QByteArray &haystack, int from = 0) const Q_DECL_NOTHROW
+ { return this->indexOfIn(m_pattern, N - 1, haystack.data(), haystack.size(), from); }
+ int indexIn(const char *haystack, int hlen, int from = 0) const Q_DECL_NOTHROW
+ { return this->indexOfIn(m_pattern, N - 1, haystack, hlen, from); }
+
+ QByteArray pattern() const { return QByteArray(m_pattern, int(N - 1)); }
+};
+
+QT_WARNING_POP
+
+template <uint N>
+Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcher<N> qMakeStaticByteArrayMatcher(const char (&pattern)[N]) Q_DECL_NOTHROW
+{ return QStaticByteArrayMatcher<N>(pattern); }
+
QT_END_NAMESPACE
#endif // QBYTEARRAYMATCHER_H
diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp
index 5f918aab0f..1d3293e85e 100644
--- a/src/corelib/tools/qchar.cpp
+++ b/src/corelib/tools/qchar.cpp
@@ -101,7 +101,7 @@ QT_BEGIN_NAMESPACE
In Qt, Unicode characters are 16-bit entities without any markup
or structure. This class represents such an entity. It is
lightweight, so it can be used everywhere. Most compilers treat
- it like a \c{unsigned short}.
+ it like an \c{unsigned short}.
QChar provides a full complement of testing/classification
functions, converting to and from other formats, converting from
@@ -424,7 +424,7 @@ QT_BEGIN_NAMESPACE
\enum QChar::Direction
This enum type defines the Unicode direction attributes. See the
- \l{http://www.unicode.org/}{Unicode Standard} for a description
+ \l{http://www.unicode.org/reports/tr9/tr9-35.html#Table_Bidirectional_Character_Types}{Unicode Standard} for a description
of the values.
In order to conform to C/C++ naming conventions "Dir" is prepended
diff --git a/src/corelib/tools/qcollator.h b/src/corelib/tools/qcollator.h
index 5ff74fd69a..d81c7c85e3 100644
--- a/src/corelib/tools/qcollator.h
+++ b/src/corelib/tools/qcollator.h
@@ -69,7 +69,7 @@ public:
protected:
QCollatorSortKey(QCollatorSortKeyPrivate*);
- QSharedDataPointer<QCollatorSortKeyPrivate> d;
+ QExplicitlySharedDataPointer<QCollatorSortKeyPrivate> d;
private:
QCollatorSortKey();
diff --git a/src/corelib/tools/qcollator_icu.cpp b/src/corelib/tools/qcollator_icu.cpp
index 1e94798c5b..ad98a187c5 100644
--- a/src/corelib/tools/qcollator_icu.cpp
+++ b/src/corelib/tools/qcollator_icu.cpp
@@ -39,6 +39,7 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
@@ -56,7 +57,7 @@ void QCollatorPrivate::init()
cleanup();
UErrorCode status = U_ZERO_ERROR;
- QByteArray name = locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')).toLatin1();
+ QByteArray name = QLocalePrivate::get(locale)->bcp47Name('_');
collator = ucol_open(name.constData(), &status);
if (U_FAILURE(status)) {
qWarning("Could not create collator: %d", status);
@@ -144,7 +145,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
string.size(), (uint8_t *)result.data(), result.size());
}
result.truncate(size);
- return QCollatorSortKey(new QCollatorSortKeyPrivate(result));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(result)));
}
return QCollatorSortKey(new QCollatorSortKeyPrivate(QByteArray()));
diff --git a/src/corelib/tools/qcollator_macx.cpp b/src/corelib/tools/qcollator_macx.cpp
index b4d93e58d4..d468272430 100644
--- a/src/corelib/tools/qcollator_macx.cpp
+++ b/src/corelib/tools/qcollator_macx.cpp
@@ -38,9 +38,12 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
+
#include <QtCore/private/qcore_mac_p.h>
+
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFLocale.h>
@@ -53,7 +56,7 @@ void QCollatorPrivate::init()
{
cleanup();
LocaleRef localeRef;
- int rc = LocaleRefFromLocaleString(locale.bcp47Name().toLocal8Bit(), &localeRef);
+ int rc = LocaleRefFromLocaleString(QLocalePrivate::get(locale)->bcp47Name().constData(), &localeRef);
if (rc != 0)
qWarning("couldn't initialize the locale");
@@ -128,7 +131,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
ret.size(), &actualSize, ret.data());
}
ret[actualSize] = 0;
- return QCollatorSortKey(new QCollatorSortKeyPrivate(ret));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(ret)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &key) const
diff --git a/src/corelib/tools/qcollator_p.h b/src/corelib/tools/qcollator_p.h
index 423ba0325a..c03a3431db 100644
--- a/src/corelib/tools/qcollator_p.h
+++ b/src/corelib/tools/qcollator_p.h
@@ -85,7 +85,7 @@ typedef QVector<wchar_t> CollatorKeyType;
typedef int CollatorType;
#endif
-class Q_CORE_EXPORT QCollatorPrivate
+class QCollatorPrivate
{
public:
QAtomicInt ref;
@@ -127,13 +127,14 @@ private:
Q_DISABLE_COPY(QCollatorPrivate)
};
-class Q_CORE_EXPORT QCollatorSortKeyPrivate : public QSharedData
+class QCollatorSortKeyPrivate : public QSharedData
{
friend class QCollator;
public:
- QCollatorSortKeyPrivate(const CollatorKeyType &key)
+ template <typename...T>
+ explicit QCollatorSortKeyPrivate(T &&...args)
: QSharedData()
- , m_key(key)
+ , m_key(std::forward<T>(args)...)
{
}
diff --git a/src/corelib/tools/qcollator_posix.cpp b/src/corelib/tools/qcollator_posix.cpp
index da424970e6..42413a4a82 100644
--- a/src/corelib/tools/qcollator_posix.cpp
+++ b/src/corelib/tools/qcollator_posix.cpp
@@ -110,7 +110,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
}
result.resize(size+1);
result[size] = 0;
- return QCollatorSortKey(new QCollatorSortKeyPrivate(result));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(result)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
diff --git a/src/corelib/tools/qcollator_win.cpp b/src/corelib/tools/qcollator_win.cpp
index fcd8d069eb..bce896278e 100644
--- a/src/corelib/tools/qcollator_win.cpp
+++ b/src/corelib/tools/qcollator_win.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
@@ -61,7 +62,7 @@ void QCollatorPrivate::init()
collator = 0;
#ifndef USE_COMPARESTRINGEX
- localeID = qt_inIsoNametoLCID(locale.bcp47Name().toUtf8().constData());
+ localeID = qt_inIsoNametoLCID(QLocalePrivate::get(locale)->bcp47Name().constData());
#else
localeName = locale.bcp47Name();
#endif
@@ -146,7 +147,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
if (finalSize == 0) {
qWarning() << "there were problems when generating the ::sortKey by LCMapStringW with error:" << GetLastError();
}
- return QCollatorSortKey(new QCollatorSortKeyPrivate(ret));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(ret)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index bf92be2dd4..bcdbc5af2a 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -929,7 +929,7 @@ QString QDate::toString(Qt::DateFormat format) const
*/
QString QDate::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -1333,6 +1333,7 @@ QDate QDate::fromString(const QString &string, const QString &format)
QDate date;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, &date, 0);
#else
@@ -1676,7 +1677,7 @@ QString QTime::toString(Qt::DateFormat format) const
*/
QString QTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
/*!
@@ -1970,7 +1971,7 @@ QTime QTime::fromString(const QString& string, Qt::DateFormat format)
case Qt::ISODateWithMs:
case Qt::TextDate:
default:
- return fromIsoTimeString(&string, format, 0);
+ return fromIsoTimeString(QStringRef(&string), format, 0);
}
}
@@ -2030,6 +2031,7 @@ QTime QTime::fromString(const QString &string, const QString &format)
QTime time;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, 0, &time);
#else
@@ -2285,10 +2287,11 @@ static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localT
tm local;
bool valid = false;
-#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
// localtime() is required to work as if tzset() was called before it.
// localtime_r() does not have this requirement, so make an explicit call.
+ // The explicit call should also request the timezone info be re-parsed.
qt_tzset();
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
// Use the reentrant version of localtime() where available
// as is thread-safe and doesn't use a shared static data area
tm *res = 0;
@@ -2574,6 +2577,13 @@ static inline Qt::TimeSpec getSpec(const QDateTimeData &d)
return extractSpec(getStatus(d));
}
+#if QT_CONFIG(timezone)
+void QDateTimePrivate::setUtcOffsetByTZ(qint64 atMSecsSinceEpoch)
+{
+ m_offsetFromUtc = m_timeZone.d->offsetFromUtc(atMSecsSinceEpoch);
+}
+#endif
+
// Refresh the LocalTime validity and offset
static void refreshDateTime(QDateTimeData &d)
{
@@ -2589,10 +2599,12 @@ static void refreshDateTime(QDateTimeData &d)
#if QT_CONFIG(timezone)
// If not valid time zone then is invalid
if (spec == Qt::TimeZone) {
- if (!d->m_timeZone.isValid())
+ if (!d->m_timeZone.isValid()) {
status &= ~QDateTimePrivate::ValidDateTime;
- else
- epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, &testDate, &testTime);
+ } else {
+ epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, extractDaylightStatus(status), &testDate, &testTime);
+ d->setUtcOffsetByTZ(epochMSecs);
+ }
}
#endif // timezone
@@ -2916,11 +2928,13 @@ inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime
}
// Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs
+// DST transitions are disambiguated by hint.
inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone,
+ DaylightStatus hint,
QDate *localDate, QTime *localTime)
{
// Get the effective data from QTimeZone
- QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs);
+ QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint));
// Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
// but all affected times afterwards will have DST applied.
if (data.atMSecsSinceEpoch >= 0) {
@@ -3533,7 +3547,8 @@ qint64 QDateTime::toMSecsSinceEpoch() const
#if !QT_CONFIG(timezone)
return 0;
#else
- return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone);
+ return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone,
+ extractDaylightStatus(getStatus(d)));
#endif
}
Q_UNREACHABLE();
@@ -3632,10 +3647,16 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
// Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
// but all affected times afterwards will have DST applied.
d.detach();
- if (msecs >= 0)
+ if (msecs >= 0) {
+ status = mergeDaylightStatus(status,
+ d->m_timeZone.d->isDaylightTime(msecs)
+ ? QDateTimePrivate::DaylightTime
+ : QDateTimePrivate::StandardTime);
d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs);
- else
+ } else {
+ status = mergeDaylightStatus(status, QDateTimePrivate::StandardTime);
d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(msecs);
+ }
msecs = msecs + (d->m_offsetFromUtc * 1000);
status = status
| QDateTimePrivate::ValidDate
@@ -3783,15 +3804,20 @@ QString QDateTime::toString(Qt::DateFormat format) const
#ifndef QT_NO_TEXTDATE
case Qt::TextDate: {
const QPair<QDate, QTime> p = getDateTime(d);
- const QDate &dt = p.first;
- const QTime &tm = p.second;
- //We cant use date.toString(Qt::TextDate) as we need to insert the time before the year
- buf = QString::fromLatin1("%1 %2 %3 %4 %5").arg(dt.shortDayName(dt.dayOfWeek()))
- .arg(dt.shortMonthName(dt.month()))
- .arg(dt.day())
- .arg(tm.toString(Qt::TextDate))
- .arg(dt.year());
- if (timeSpec() != Qt::LocalTime) {
+ buf = p.first.toString(Qt::TextDate);
+ // Insert time between date's day and year:
+ buf.insert(buf.lastIndexOf(QLatin1Char(' ')),
+ QLatin1Char(' ') + p.second.toString(Qt::TextDate));
+ // Append zone/offset indicator, as appropriate:
+ switch (timeSpec()) {
+ case Qt::LocalTime:
+ break;
+# if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+ buf += QLatin1Char(' ') + d->m_timeZone.abbreviation(*this);
+ break;
+# endif
+ default:
buf += QLatin1String(" GMT");
if (getSpec(d) == Qt::OffsetFromUTC)
buf += toOffsetString(Qt::TextDate, offsetFromUtc());
@@ -3814,6 +3840,9 @@ QString QDateTime::toString(Qt::DateFormat format) const
buf += QLatin1Char('Z');
break;
case Qt::OffsetFromUTC:
+#if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+#endif
buf += toOffsetString(Qt::ISODate, offsetFromUtc());
break;
default:
@@ -3899,7 +3928,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
*/
QString QDateTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -3923,7 +3952,10 @@ static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date,
localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time);
#if QT_CONFIG(timezone)
} else if (spec == Qt::TimeZone) {
- QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), d->m_timeZone, date, time);
+ QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time),
+ d->m_timeZone,
+ QDateTimePrivate::UnknownDaylightTime,
+ date, time);
#endif // timezone
}
}
@@ -4953,6 +4985,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format)
QDate date;
QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
return QDateTime(date, time);
#else
diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h
index eb33dddbb7..4d30d4192b 100644
--- a/src/corelib/tools/qdatetime_p.h
+++ b/src/corelib/tools/qdatetime_p.h
@@ -134,11 +134,12 @@ public:
#if QT_CONFIG(timezone)
static qint64 zoneMSecsToEpochMSecs(qint64 msecs, const QTimeZone &zone,
+ DaylightStatus hint = UnknownDaylightTime,
QDate *localDate = 0, QTime *localTime = 0);
-#endif // timezone
- static inline qint64 minJd() { return QDate::minJd(); }
- static inline qint64 maxJd() { return QDate::maxJd(); }
+ // Inlined for its one caller in qdatetime.cpp
+ inline void setUtcOffsetByTZ(qint64 atMSecsSinceEpoch);
+#endif // timezone
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index efed5d36ee..ba06de8f9e 100644
--- a/src/corelib/tools/qeasingcurve.h
+++ b/src/corelib/tools/qeasingcurve.h
@@ -125,7 +125,7 @@ private:
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QEasingCurve &);
#endif
};
-Q_DECLARE_TYPEINFO(QEasingCurve, Q_MOVABLE_TYPE);
+Q_DECLARE_SHARED(QEasingCurve)
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index abec9ebb79..334bd52f1e 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -199,14 +199,14 @@ static uint crc32(...)
}
#endif
-static inline uint hash(const uchar *p, int len, uint seed) Q_DECL_NOTHROW
+static inline uint hash(const uchar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
if (hasFastCrc32())
- return crc32(p, size_t(len), h);
+ return crc32(p, len, h);
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
h = 31 * h + p[i];
return h;
@@ -217,14 +217,14 @@ uint qHashBits(const void *p, size_t len, uint seed) Q_DECL_NOTHROW
return hash(static_cast<const uchar*>(p), int(len), seed);
}
-static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW
+static inline uint hash(const QChar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
if (hasFastCrc32())
- return crc32(p, size_t(len), h);
+ return crc32(p, len, h);
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
h = 31 * h + p[i].unicode();
return h;
@@ -232,23 +232,24 @@ static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW
uint qHash(const QByteArray &key, uint seed) Q_DECL_NOTHROW
{
- return hash(reinterpret_cast<const uchar *>(key.constData()), key.size(), seed);
+ return hash(reinterpret_cast<const uchar *>(key.constData()), size_t(key.size()), seed);
}
uint qHash(const QString &key, uint seed) Q_DECL_NOTHROW
{
- return hash(key.unicode(), key.size(), seed);
+ return hash(key.unicode(), size_t(key.size()), seed);
}
uint qHash(const QStringRef &key, uint seed) Q_DECL_NOTHROW
{
- return hash(key.unicode(), key.size(), seed);
+ return hash(key.unicode(), size_t(key.size()), seed);
}
uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW
{
int m = bitArray.d.size() - 1;
- uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()), qMax(0, m), seed);
+ uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()),
+ size_t(qMax(0, m)), seed);
// deal with the last 0 to 7 bits manually, because we can't trust that
// the padding is initialized to 0 in bitArray.d
@@ -260,7 +261,7 @@ uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW
uint qHash(QLatin1String key, uint seed) Q_DECL_NOTHROW
{
- return hash(reinterpret_cast<const uchar *>(key.data()), key.size(), seed);
+ return hash(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
}
/*!
@@ -324,7 +325,7 @@ static uint qt_create_qhash_seed()
/*
The QHash seed itself.
*/
-Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1);
+static QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1);
/*!
\internal
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 66b5e75a1a..c59f789cb2 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -432,6 +432,7 @@ public:
typedef const Key *pointer;
typedef const Key &reference;
+ key_iterator() = default;
explicit key_iterator(const_iterator o) : i(o) { }
const Key &operator*() const { return i.key(); }
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 5995be47a9..e2706de9ee 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -126,6 +126,7 @@ class QList
public:
struct MemoryLayout
: std::conditional<
+ // must stay isStatic until ### Qt 6 for BC reasons (don't use !isRelocatable)!
QTypeInfo<T>::isStatic || QTypeInfo<T>::isLarge,
QListData::IndirectLayout,
typename std::conditional<
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index c23c84534f..697e0062dd 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -972,7 +972,7 @@ QLocale::NumberOptions QLocale::numberOptions() const
*/
QString QLocale::quoteString(const QString &str, QuotationStyle style) const
{
- return quoteString(&str, style);
+ return quoteString(QStringRef(&str), style);
}
/*!
@@ -2058,6 +2058,8 @@ QString QLocale::toString(double i, char f, int prec) const
flags |= QLocaleData::ThousandsGroup;
if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
return d->m_data->doubleToString(i, prec, form, -1, flags);
}
@@ -2819,7 +2821,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
reinterpret_cast<ushort *>(digits.data())[i] += z;
}
- bool always_show_decpt = (flags & Alternate || flags & ForcePoint);
+ bool always_show_decpt = (flags & ForcePoint);
switch (form) {
case DFExponent: {
num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
@@ -2834,7 +2836,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
break;
}
case DFSignificantDigits: {
- PrecisionMode mode = (flags & Alternate) ?
+ PrecisionMode mode = (flags & AddTrailingZeroes) ?
PMSignificantDigits : PMChopTrailingZeros;
int cutoff = precision < 0 ? 6 : precision;
@@ -2889,7 +2891,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
num_str.prepend(QLatin1Char(' '));
if (flags & QLocaleData::CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
return num_str;
}
@@ -2939,7 +2941,7 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -2960,10 +2962,10 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
--num_pad_chars;
// leave space for optional '0x' in hex form
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && (flags & ShowBase))
num_pad_chars -= 2;
for (int i = 0; i < num_pad_chars; ++i)
@@ -2971,11 +2973,11 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
}
if (flags & CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- if (base == 2 && (flags & Alternate || flags & ShowBase))
+ if (base == 2 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -3024,7 +3026,7 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
if (zeroPadding > 0)
num_str.prepend(QString(zeroPadding, resultZero));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str.at(0).unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -3039,10 +3041,10 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
int num_pad_chars = width - num_str.length();
// leave space for optional '0x' in hex form
- if (base == 16 && flags & Alternate)
+ if (base == 16 && flags & ShowBase)
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && flags & Alternate)
+ else if (base == 2 && flags & ShowBase)
num_pad_chars -= 2;
if (num_pad_chars > 0)
@@ -3050,11 +3052,11 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
}
if (flags & CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -3115,25 +3117,37 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
out = in.toLatin1();
else
break;
+ } else if (out == '.') {
+ // Fail if more than one decimal point or point after e
+ if (decpt_idx != -1 || exponent_idx != -1)
+ return false;
+ decpt_idx = idx;
+ } else if (out == 'e' || out == 'E') {
+ exponent_idx = idx;
}
if (number_options & QLocale::RejectLeadingZeroInExponent) {
- if (out == 'e' || out == 'E') {
- exponent_idx = idx;
- } else if (exponent_idx != -1) {
- if (out >= '1' && out <= '9')
- exponent_idx = -1; // leading digit is not 0, forget exponent_idx
- else if (out == '0' && idx < l - 1)
+ if (exponent_idx != -1 && out == '0' && idx < l - 1) {
+ // After the exponent there can only be '+', '-' or digits.
+ // If we find a '0' directly after some non-digit, then that is a leading zero.
+ if (result->last() < '0' || result->last() > '9')
return false;
}
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // If we've seen a decimal point and the last character after the exponent is 0, then
+ // that is a trailing zero.
+ if (decpt_idx >= 0 && idx == exponent_idx && result->last() == '0')
+ return false;
+ }
+
if (!(number_options & QLocale::RejectGroupSeparator)) {
if (start_of_digits_idx == -1 && out >= '0' && out <= '9') {
start_of_digits_idx = idx;
} else if (out == ',') {
- // Don't allow group chars after the decimal point
- if (decpt_idx != -1)
+ // Don't allow group chars after the decimal point or exponent
+ if (decpt_idx != -1 || exponent_idx != -1)
return false;
// check distance from the last separator or from the beginning of the digits
@@ -3150,12 +3164,6 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
++idx;
continue;
} else if (out == '.' || out == 'e' || out == 'E') {
- // Fail if more than one decimal point
- if (out == '.' && decpt_idx != -1)
- return false;
- if (decpt_idx == -1)
- decpt_idx = idx;
-
// check distance from the last separator
// ### FIXME: Some locales allow other groupings! See https://en.wikipedia.org/wiki/Thousands_separator
if (last_separator_idx != -1 && idx - last_separator_idx != 4)
@@ -3181,6 +3189,12 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
return false;
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // In decimal form, the last character can be a trailing zero if we've seen a decpt.
+ if (decpt_idx != -1 && exponent_idx == -1 && result->last() == '0')
+ return false;
+ }
+
result->append('\0');
return idx == l;
}
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index 657fce9fa1..bd89e48234 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -897,7 +897,9 @@ public:
OmitGroupSeparator = 0x01,
RejectGroupSeparator = 0x02,
OmitLeadingZeroInExponent = 0x04,
- RejectLeadingZeroInExponent = 0x08
+ RejectLeadingZeroInExponent = 0x08,
+ IncludeTrailingZeroesAfterDot = 0x10,
+ RejectTrailingZeroesAfterDot = 0x20
};
Q_DECLARE_FLAGS(NumberOptions, NumberOption)
diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc
index 8c5711fb5e..d419172356 100644
--- a/src/corelib/tools/qlocale.qdoc
+++ b/src/corelib/tools/qlocale.qdoc
@@ -949,7 +949,8 @@
setNumberOptions().
\value DefaultNumberOptions This option represents the default behavior, with
- group separators and with one leading zero in single digit exponents.
+ group separators, with one leading zero in single digit exponents, and
+ without trailing zeroes after the decimal dot.
\value OmitGroupSeparator If this option is set, the number-to-string functions
will not insert group separators in their return values. The default
is to insert group separators.
@@ -964,6 +965,14 @@
functions will fail if they encounter an exponent padded with zeroes when
parsing a floating point number in scientific notation. The default is to
accept such padding.
+ \value IncludeTrailingZeroesAfterDot If this option is set, the number-to-string
+ functions will pad numbers with zeroes to the requested precision in "g"
+ or "most concise" mode, even if the number of significant digits is lower
+ than the requested precision. The default is to omit trailing zeroes.
+ \value RejectTrailingZeroesAfterDot If this option is set, the string-to-number
+ functions will fail if they encounter trailing zeroes after the decimal
+ dot when parsing a number in scientific or decimal representation. The
+ default is to accept trailing zeroes.
\sa setNumberOptions(), numberOptions()
*/
diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm
index 8587716446..c5519bfabf 100644
--- a/src/corelib/tools/qlocale_mac.mm
+++ b/src/corelib/tools/qlocale_mac.mm
@@ -43,9 +43,11 @@
#include "qvariant.h"
#include "qdatetime.h"
-#if !defined(QWS) && defined(Q_OS_MAC)
-# include "private/qcore_mac_p.h"
-# include <CoreFoundation/CoreFoundation.h>
+#ifdef Q_OS_DARWIN
+#include "qtimezone.h"
+#include "private/qcore_mac_p.h"
+#include <CoreFoundation/CoreFoundation.h>
+QT_REQUIRE_CONFIG(timezone);
#endif
QT_BEGIN_NAMESPACE
@@ -121,16 +123,7 @@ static QString macDayName(int day, bool short_format)
static QString macDateToString(const QDate &date, bool short_format)
{
- CFGregorianDate macGDate;
- macGDate.year = date.year();
- macGDate.month = date.month();
- macGDate.day = date.day();
- macGDate.hour = 0;
- macGDate.minute = 0;
- macGDate.second = 0.0;
- QCFType<CFDateRef> myDate
- = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
- QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
+ QCFType<CFDateRef> myDate = QDateTime(date, QTime()).toCFDate();
QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle;
QCFType<CFDateFormatterRef> myFormatter
@@ -142,19 +135,7 @@ static QString macDateToString(const QDate &date, bool short_format)
static QString macTimeToString(const QTime &time, bool short_format)
{
- CFGregorianDate macGDate;
- // Assume this is local time and the current date
- QDate dt = QDate::currentDate();
- macGDate.year = dt.year();
- macGDate.month = dt.month();
- macGDate.day = dt.day();
- macGDate.hour = time.hour();
- macGDate.minute = time.minute();
- macGDate.second = time.second();
- QCFType<CFDateRef> myDate
- = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
- QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
-
+ QCFType<CFDateRef> myDate = QDateTime(QDate::currentDate(), time).toCFDate();
QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle;
QCFType<CFDateFormatterRef> myFormatter = CFDateFormatterCreate(kCFAllocatorDefault,
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index 20eff8fd64..f7adb021b6 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -193,7 +193,7 @@ public:
enum Flags {
NoFlags = 0,
- Alternate = 0x01,
+ AddTrailingZeroes = 0x01,
ZeroPadded = 0x02,
LeftAdjusted = 0x04,
BlankBeforePositive = 0x08,
@@ -204,7 +204,7 @@ public:
ShowBase = 0x80,
UppercaseBase = 0x100,
ZeroPadExponent = 0x200,
- ForcePoint = Alternate
+ ForcePoint = 0x400
};
enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode };
@@ -332,6 +332,9 @@ public:
return retval;
}
+ static QLocalePrivate *get(QLocale &l) { return l.d; }
+ static const QLocalePrivate *get(const QLocale &l) { return l.d; }
+
QChar decimal() const { return QChar(m_data->m_decimal); }
QChar group() const { return QChar(m_data->m_group); }
QChar list() const { return QChar(m_data->m_list); }
diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp
index b5f97b5fe8..2475859abd 100644
--- a/src/corelib/tools/qlocale_win.cpp
+++ b/src/corelib/tools/qlocale_win.cpp
@@ -691,7 +691,7 @@ QString QSystemLocalePrivate::winToQtFormat(const QString &sys_fmt)
if (text == QLatin1String("'"))
result += QLatin1String("''");
else
- result += QString(QLatin1Char('\'') + text + QLatin1Char('\''));
+ result += QLatin1Char('\'') + text + QLatin1Char('\'');
continue;
}
@@ -1037,7 +1037,7 @@ static QString winIso639LangName(LPWSTR id)
if (!lang_code.isEmpty()) {
const char *endptr;
bool ok;
- QByteArray latin1_lang_code = lang_code.toLatin1();
+ QByteArray latin1_lang_code = std::move(lang_code).toLatin1();
int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok);
if (ok && *endptr == '\0') {
switch (i) {
@@ -1120,15 +1120,12 @@ static QByteArray getWinLocaleName(LPWSTR id)
id = lcName;
}
#endif // Q_OS_WINRT
- QString resultuage = winIso639LangName(id);
+ QString resultusage = winIso639LangName(id);
QString country = winIso3116CtryName(id);
- result = resultuage.toLatin1();
- if (!country.isEmpty()) {
- result += '_';
- result += country.toLatin1();
- }
+ if (!country.isEmpty())
+ resultusage += QLatin1Char('_') + country;
- return result;
+ return std::move(resultusage).toLatin1();
}
Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index da77ba4458..a3b11eddcf 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -99,10 +99,10 @@ struct Q_CORE_EXPORT QMapNodeBase
void setParent(QMapNodeBase *pp) { p = (p & Mask) | quintptr(pp); }
template <typename T>
- static typename QtPrivate::QEnableIf<QTypeInfo<T>::isComplex>::Type
+ static typename std::enable_if<QTypeInfo<T>::isComplex>::type
callDestructorIfNecessary(T &t) Q_DECL_NOTHROW { Q_UNUSED(t); t.~T(); } // Q_UNUSED: silence MSVC unused 't' warning
template <typename T>
- static typename QtPrivate::QEnableIf<!QTypeInfo<T>::isComplex>::Type
+ static typename std::enable_if<!QTypeInfo<T>::isComplex>::type
callDestructorIfNecessary(T &) Q_DECL_NOTHROW {}
};
@@ -533,6 +533,7 @@ public:
typedef const Key *pointer;
typedef const Key &reference;
+ key_iterator() = default;
explicit key_iterator(const_iterator o) : i(o) { }
const Key &operator*() const { return i.key(); }
diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp
index 4a30daa72c..88b696f53a 100644
--- a/src/corelib/tools/qregularexpression.cpp
+++ b/src/corelib/tools/qregularexpression.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>.
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+** Copyright (C) 2016 Giuseppe D'Angelo <dangelog@gmail.com>.
+** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -45,7 +45,7 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qhashfunctions.h>
-#include <QtCore/qmutex.h>
+#include <QtCore/qreadwritelock.h>
#include <QtCore/qvector.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qdebug.h>
@@ -54,7 +54,9 @@
#include <QtCore/qatomic.h>
#include <QtCore/qdatastream.h>
-#include <pcre.h>
+#define PCRE2_CODE_UNIT_WIDTH 16
+
+#include <pcre2.h>
QT_BEGIN_NAMESPACE
@@ -443,19 +445,25 @@ QT_BEGIN_NAMESPACE
Other differences are outlined below.
- \section2 Exact matching
+ \section2 Porting from QRegExp::exactMatch()
QRegExp::exactMatch() in Qt 4 served two purposes: it exactly matched
a regular expression against a subject string, and it implemented partial
- matching. In fact, if an exact match was not found, one could still find
- out how much of the subject string was matched by the regular expression
- by calling QRegExp::matchedLength(). If the returned length was equal
- to the subject string's length, then one could desume that a partial match
- was found.
+ matching.
- QRegularExpression supports partial matching explicitly by means of the
- appropriate MatchType. If instead you simply want to be sure that the
- subject string matches the regular expression exactly, you can wrap the
+ \section3 Porting from QRegExp's Exact Matching
+
+ Exact matching indicates whether the regular expression matches the entire
+ subject string. For example, the classes yield on the subject string \c{"abc123"}:
+
+ \table
+ \header \li \li QRegExp::exactMatch() \li QRegularExpressionMatch::hasMatch()
+ \row \li \c{"\\d+"} \li \b false \li \b true
+ \row \li \c{"[a-z]+\\d+"} \li \b true \li \b true
+ \endtable
+
+ Exact matching is not reflected in QRegularExpression. If you want to be
+ sure that the subject string matches the regular expression exactly, you can wrap the
pattern between a couple of anchoring expressions. Simply
putting the pattern between the \c{^} and the \c{$} anchors is enough
in most cases:
@@ -477,6 +485,17 @@ QT_BEGIN_NAMESPACE
Note the usage of the non-capturing group in order to preserve the meaning
of the branch operator inside the pattern.
+ \section3 Porting from QRegExp's Partial Matching
+
+ When using QRegExp::exactMatch(), if an exact match was not found, one
+ could still find out how much of the subject string was matched by the
+ regular expression by calling QRegExp::matchedLength(). If the returned length
+ was equal to the subject string's length, then one could conclude that a partial
+ match was found.
+
+ QRegularExpression supports partial matching explicitly by means of the
+ appropriate MatchType.
+
\section2 Global matching
Due to limitations of the QRegExp API it was impossible to implement global
@@ -548,7 +567,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\reentrant
- \brief The QRegularExpressionMatch class provides the results of matching
+ \brief The QRegularExpressionMatch class provides the results of a matching
a QRegularExpression against a string.
\since 5.0
@@ -789,19 +808,19 @@ static int convertToPcreOptions(QRegularExpression::PatternOptions patternOption
int options = 0;
if (patternOptions & QRegularExpression::CaseInsensitiveOption)
- options |= PCRE_CASELESS;
+ options |= PCRE2_CASELESS;
if (patternOptions & QRegularExpression::DotMatchesEverythingOption)
- options |= PCRE_DOTALL;
+ options |= PCRE2_DOTALL;
if (patternOptions & QRegularExpression::MultilineOption)
- options |= PCRE_MULTILINE;
+ options |= PCRE2_MULTILINE;
if (patternOptions & QRegularExpression::ExtendedPatternSyntaxOption)
- options |= PCRE_EXTENDED;
+ options |= PCRE2_EXTENDED;
if (patternOptions & QRegularExpression::InvertedGreedinessOption)
- options |= PCRE_UNGREEDY;
+ options |= PCRE2_UNGREEDY;
if (patternOptions & QRegularExpression::DontCaptureOption)
- options |= PCRE_NO_AUTO_CAPTURE;
+ options |= PCRE2_NO_AUTO_CAPTURE;
if (patternOptions & QRegularExpression::UseUnicodePropertiesOption)
- options |= PCRE_UCP;
+ options |= PCRE2_UCP;
return options;
}
@@ -814,7 +833,9 @@ static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
int options = 0;
if (matchOptions & QRegularExpression::AnchoredMatchOption)
- options |= PCRE_ANCHORED;
+ options |= PCRE2_ANCHORED;
+ if (matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption)
+ options |= PCRE2_NO_UTF_CHECK;
return options;
}
@@ -856,20 +877,16 @@ struct QRegularExpressionPrivate : QSharedData
QRegularExpression::PatternOptions patternOptions;
QString pattern;
- // *All* of the following members are set managed while holding this mutex,
+ // *All* of the following members are managed while holding this mutex,
// except for isDirty which is set to true by QRegularExpression setters
// (right after a detach happened).
- // On the other hand, after the compilation and studying,
- // it's safe to *use* (i.e. read) them from multiple threads at the same time.
- // Therefore, doMatch doesn't need to lock this mutex.
- QMutex mutex;
+ mutable QReadWriteLock mutex;
- // The PCRE pointers are reference-counted by the QRegularExpressionPrivate
+ // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
// objects themselves; when the private is copied (i.e. a detach happened)
// they are set to 0
- pcre16 *compiledPattern;
- QAtomicPointer<pcre16_extra> studyData;
- const char *errorString;
+ pcre2_code_16 *compiledPattern;
+ int errorCode;
int errorOffset;
int capturingCount;
unsigned int usedCount;
@@ -884,8 +901,7 @@ struct QRegularExpressionMatchPrivate : QSharedData
int subjectStart,
int subjectLength,
QRegularExpression::MatchType matchType,
- QRegularExpression::MatchOptions matchOptions,
- int capturingCount = 0);
+ QRegularExpression::MatchOptions matchOptions);
QRegularExpressionMatch nextMatch() const;
@@ -934,10 +950,13 @@ QRegularExpression::QRegularExpression(QRegularExpressionPrivate &dd)
\internal
*/
QRegularExpressionPrivate::QRegularExpressionPrivate()
- : patternOptions(0), pattern(),
+ : QSharedData(),
+ patternOptions(0),
+ pattern(),
mutex(),
- compiledPattern(0), studyData(0),
- errorString(0), errorOffset(-1),
+ compiledPattern(0),
+ errorCode(0),
+ errorOffset(-1),
capturingCount(0),
usedCount(0),
usingCrLfNewlines(false),
@@ -964,13 +983,16 @@ QRegularExpressionPrivate::~QRegularExpressionPrivate()
*/
QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPrivate &other)
: QSharedData(other),
- patternOptions(other.patternOptions), pattern(other.pattern),
+ patternOptions(other.patternOptions),
+ pattern(other.pattern),
mutex(),
- compiledPattern(0), studyData(0),
- errorString(0),
- errorOffset(-1), capturingCount(0),
+ compiledPattern(0),
+ errorCode(0),
+ errorOffset(-1),
+ capturingCount(0),
usedCount(0),
- usingCrLfNewlines(false), isDirty(true)
+ usingCrLfNewlines(false),
+ isDirty(true)
{
}
@@ -979,14 +1001,13 @@ QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPri
*/
void QRegularExpressionPrivate::cleanCompiledPattern()
{
- pcre16_free(compiledPattern);
- pcre16_free_study(studyData.load());
- usedCount = 0;
+ pcre2_code_free_16(compiledPattern);
compiledPattern = 0;
- studyData.store(0);
- usingCrLfNewlines = false;
+ errorCode = 0;
errorOffset = -1;
capturingCount = 0;
+ usedCount = 0;
+ usingCrLfNewlines = false;
}
/*!
@@ -994,7 +1015,7 @@ void QRegularExpressionPrivate::cleanCompiledPattern()
*/
void QRegularExpressionPrivate::compilePattern()
{
- QMutexLocker lock(&mutex);
+ const QWriteLocker lock(&mutex);
if (!isDirty)
return;
@@ -1003,18 +1024,23 @@ void QRegularExpressionPrivate::compilePattern()
cleanCompiledPattern();
int options = convertToPcreOptions(patternOptions);
- options |= PCRE_UTF16;
+ options |= PCRE2_UTF;
- int errorCode;
- compiledPattern = pcre16_compile2(pattern.utf16(), options,
- &errorCode, &errorString, &errorOffset, 0);
+ PCRE2_SIZE patternErrorOffset;
+ compiledPattern = pcre2_compile_16(pattern.utf16(),
+ pattern.length(),
+ options,
+ &errorCode,
+ &patternErrorOffset,
+ NULL);
- if (!compiledPattern)
+ if (!compiledPattern) {
+ errorOffset = static_cast<int>(patternErrorOffset);
return;
-
- Q_ASSERT(errorCode == 0);
- Q_ASSERT(studyData.load() == 0); // studying (=>optimizing) is always done later
- errorOffset = -1;
+ } else {
+ // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
+ errorCode = 0;
+ }
getPatternInfo();
}
@@ -1025,53 +1051,31 @@ void QRegularExpressionPrivate::compilePattern()
void QRegularExpressionPrivate::getPatternInfo()
{
Q_ASSERT(compiledPattern);
- Q_ASSERT(studyData.load() == 0);
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_CAPTURECOUNT, &capturingCount);
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
// detect the settings for the newline
- unsigned long int patternNewlineSetting;
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_OPTIONS, &patternNewlineSetting);
- patternNewlineSetting &= PCRE_NEWLINE_CR | PCRE_NEWLINE_LF | PCRE_NEWLINE_CRLF
- | PCRE_NEWLINE_ANY | PCRE_NEWLINE_ANYCRLF;
- if (patternNewlineSetting == 0) {
+ unsigned int patternNewlineSetting;
+ if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
// no option was specified in the regexp, grab PCRE build defaults
- int pcreNewlineSetting;
- pcre16_config(PCRE_CONFIG_NEWLINE, &pcreNewlineSetting);
- switch (pcreNewlineSetting) {
- case 13:
- patternNewlineSetting = PCRE_NEWLINE_CR; break;
- case 10:
- patternNewlineSetting = PCRE_NEWLINE_LF; break;
- case 3338: // (13<<8 | 10)
- patternNewlineSetting = PCRE_NEWLINE_CRLF; break;
- case -2:
- patternNewlineSetting = PCRE_NEWLINE_ANYCRLF; break;
- case -1:
- patternNewlineSetting = PCRE_NEWLINE_ANY; break;
- default:
- qWarning("QRegularExpressionPrivate::compilePattern(): "
- "PCRE_CONFIG_NEWLINE returned an unknown newline");
- break;
- }
+ pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
}
- usingCrLfNewlines = (patternNewlineSetting == PCRE_NEWLINE_CRLF) ||
- (patternNewlineSetting == PCRE_NEWLINE_ANY) ||
- (patternNewlineSetting == PCRE_NEWLINE_ANYCRLF);
+ usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
+ (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
+ (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
- int hasJOptionChanged;
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_JCHANGED, &hasJOptionChanged);
- if (hasJOptionChanged) {
- qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%s'\n"
- " is using the (?J) option; duplicate capturing group names are not supported by Qt",
+ unsigned int hasJOptionChanged;
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
+ if (Q_UNLIKELY(hasJOptionChanged)) {
+ qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%s'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
qPrintable(pattern));
}
}
/*
- Simple "smartpointer" wrapper around a pcre_jit_stack, to be used with
+ Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
QThreadStorage.
*/
class QPcreJitStackPointer
@@ -1086,7 +1090,7 @@ public:
{
// The default JIT stack size in PCRE is 32K,
// we allocate from 32K up to 512K.
- stack = pcre16_jit_stack_alloc(32*1024, 512*1024);
+ stack = pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL);
}
/*!
\internal
@@ -1094,10 +1098,10 @@ public:
~QPcreJitStackPointer()
{
if (stack)
- pcre16_jit_stack_free(stack);
+ pcre2_jit_stack_free_16(stack);
}
- pcre16_jit_stack *stack;
+ pcre2_jit_stack_16 *stack;
};
Q_GLOBAL_STATIC(QThreadStorage<QPcreJitStackPointer *>, jitStacks)
@@ -1105,7 +1109,7 @@ Q_GLOBAL_STATIC(QThreadStorage<QPcreJitStackPointer *>, jitStacks)
/*!
\internal
*/
-static pcre16_jit_stack *qtPcreCallback(void *)
+static pcre2_jit_stack_16 *qtPcreCallback(void *)
{
if (jitStacks()->hasLocalData())
return jitStacks()->localData()->stack;
@@ -1135,53 +1139,32 @@ static bool isJitEnabled()
/*!
\internal
- The purpose of the function is to call pcre16_study (which allows some
- optimizations to be performed, including JIT-compiling the pattern), and
- setting the studyData member variable to the result of the study. It gets
- called by doMatch() every time a match is performed. As of now, the
- optimizations on the pattern are performed after a certain number of usages
- (i.e. the qt_qregularexpression_optimize_after_use_count constant) unless
- the DontAutomaticallyOptimizeOption option is set on the QRegularExpression
- object, or anyhow by calling optimize() (which will pass
- ImmediateOptimizeOption).
+ The purpose of the function is to call pcre2_jit_compile_16, which
+ JIT-compiles the pattern.
- Notice that although the method is protected by a mutex, one thread may
- invoke this function and return immediately (i.e. not study the pattern,
- leaving studyData to NULL); but before calling pcre16_exec to perform the
- match, another thread performs the studying and sets studyData to something
- else. Although the assignment to studyData is itself atomic, the release of
- the memory pointed by studyData isn't. Therefore, we work on a local copy
- (localStudyData) before using storeRelease on studyData. In doMatch there's
- the corresponding loadAcquire.
+ It gets called by doMatch() every time a match is performed.
+
+ As of now, the optimizations on the pattern are performed after a certain
+ number of usages (i.e. the qt_qregularexpression_optimize_after_use_count
+ constant) unless the DontAutomaticallyOptimizeOption option is set on the
+ QRegularExpression object, or anyhow by calling optimize() (which will pass
+ ImmediateOptimizeOption).
*/
void QRegularExpressionPrivate::optimizePattern(OptimizePatternOption option)
{
Q_ASSERT(compiledPattern);
- QMutexLocker lock(&mutex);
+ static const bool enableJit = isJitEnabled();
- if (studyData.load()) // already optimized
+ if (!enableJit)
return;
+ const QWriteLocker lock(&mutex);
+
if ((option == LazyOptimizeOption) && (++usedCount != qt_qregularexpression_optimize_after_use_count))
return;
- static const bool enableJit = isJitEnabled();
-
- int studyOptions = 0;
- if (enableJit)
- studyOptions |= (PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE);
-
- const char *err;
- pcre16_extra * const localStudyData = pcre16_study(compiledPattern, studyOptions, &err);
-
- if (localStudyData && localStudyData->flags & PCRE_EXTRA_EXECUTABLE_JIT)
- pcre16_assign_jit_stack(localStudyData, qtPcreCallback, 0);
-
- if (!localStudyData && err)
- qWarning("QRegularExpressionPrivate::optimizePattern(): pcre_study failed: %s", err);
-
- studyData.storeRelease(localStudyData);
+ pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
}
/*!
@@ -1197,7 +1180,7 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const
if (!compiledPattern)
return -1;
- int index = pcre16_get_stringnumber(compiledPattern, name.utf16());
+ int index = pcre2_substring_number_from_name_16(compiledPattern, name.utf16());
if (index >= 0)
return index;
@@ -1207,24 +1190,25 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const
/*!
\internal
- This is a simple wrapper for pcre16_exec for handling the case in which the
+ This is a simple wrapper for pcre2_match_16 for handling the case in which the
JIT runs out of memory. In that case, we allocate a thread-local JIT stack
- and re-run pcre16_exec.
+ and re-run pcre2_match_16.
*/
-static int pcre16SafeExec(const pcre16 *code, const pcre16_extra *extra,
- const unsigned short *subject, int length,
- int startOffset, int options,
- int *ovector, int ovecsize)
+static int safe_pcre2_match_16(const pcre2_code_16 *code,
+ const unsigned short *subject, int length,
+ int startOffset, int options,
+ pcre2_match_data_16 *matchData,
+ pcre2_match_context_16 *matchContext)
{
- int result = pcre16_exec(code, extra, subject, length,
- startOffset, options, ovector, ovecsize);
+ int result = pcre2_match_16(code, subject, length,
+ startOffset, options, matchData, matchContext);
- if (result == PCRE_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) {
+ if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) {
QPcreJitStackPointer *p = new QPcreJitStackPointer;
jitStacks()->setLocalData(p);
- result = pcre16_exec(code, extra, subject, length,
- startOffset, options, ovector, ovecsize);
+ result = pcre2_match_16(code, subject, length,
+ startOffset, options, matchData, matchContext);
}
return result;
@@ -1273,29 +1257,24 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
QRegularExpression re(*const_cast<QRegularExpressionPrivate *>(this));
+ QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
+ subjectStart, subjectLength,
+ matchType, matchOptions);
+
if (offset < 0 || offset > subjectLength)
- return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions);
+ return priv;
- if (!compiledPattern) {
+ if (Q_UNLIKELY(!compiledPattern)) {
qWarning("QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object");
- return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions);
+ return priv;
}
// skip optimizing and doing the actual matching if NoMatch type was requested
if (matchType == QRegularExpression::NoMatch) {
- QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
- subjectStart, subjectLength,
- matchType, matchOptions);
priv->isValid = true;
return priv;
}
- // capturingCount doesn't include the implicit "0" capturing group
- QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
- subjectStart, subjectLength,
- matchType, matchOptions,
- capturingCount + 1);
-
if (!(patternOptions & QRegularExpression::DontAutomaticallyOptimizeOption)) {
const OptimizePatternOption optimizePatternOption =
(patternOptions & QRegularExpression::OptimizeOnFirstUsageOption)
@@ -1306,22 +1285,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
const_cast<QRegularExpressionPrivate *>(this)->optimizePattern(optimizePatternOption);
}
- // work with a local copy of the study data, as we are running pcre_exec
- // potentially more than once, and we don't want to run call it
- // with different study data
- const pcre16_extra * const currentStudyData = studyData.loadAcquire();
-
int pcreOptions = convertToPcreOptions(matchOptions);
if (matchType == QRegularExpression::PartialPreferCompleteMatch)
- pcreOptions |= PCRE_PARTIAL_SOFT;
+ pcreOptions |= PCRE2_PARTIAL_SOFT;
else if (matchType == QRegularExpression::PartialPreferFirstMatch)
- pcreOptions |= PCRE_PARTIAL_HARD;
+ pcreOptions |= PCRE2_PARTIAL_HARD;
- if (checkSubjectStringOption == DontCheckSubjectString
- || matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption) {
- pcreOptions |= PCRE_NO_UTF16_CHECK;
- }
+ if (checkSubjectStringOption == DontCheckSubjectString)
+ pcreOptions |= PCRE2_NO_UTF_CHECK;
bool previousMatchWasEmpty = false;
if (previous && previous->hasMatch &&
@@ -1329,25 +1301,28 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
previousMatchWasEmpty = true;
}
- int * const captureOffsets = priv->capturedOffsets.data();
- const int captureOffsetsCount = priv->capturedOffsets.size();
+ pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(NULL);
+ pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, NULL);
+ pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, NULL);
const unsigned short * const subjectUtf16 = subject.utf16() + subjectStart;
int result;
+ QReadLocker lock(&mutex);
+
if (!previousMatchWasEmpty) {
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
+ matchData, matchContext);
} else {
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
+ matchData, matchContext);
- if (result == PCRE_ERROR_NOMATCH) {
+ if (result == PCRE2_ERROR_NOMATCH) {
++offset;
if (usingCrLfNewlines
@@ -1360,13 +1335,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
++offset;
}
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
+ matchData, matchContext);
}
}
+ lock.unlock();
+
#ifdef QREGULAREXPRESSION_DEBUG
qDebug() << "Matching" << pattern << "against" << subject
<< "starting at" << subjectStart << "len" << subjectLength
@@ -1386,10 +1363,10 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
priv->capturedOffsets.resize(result * 2);
} else {
// no match, partial match or error
- priv->hasPartialMatch = (result == PCRE_ERROR_PARTIAL);
- priv->isValid = (result == PCRE_ERROR_NOMATCH || result == PCRE_ERROR_PARTIAL);
+ priv->hasPartialMatch = (result == PCRE2_ERROR_PARTIAL);
+ priv->isValid = (result == PCRE2_ERROR_NOMATCH || result == PCRE2_ERROR_PARTIAL);
- if (result == PCRE_ERROR_PARTIAL) {
+ if (result == PCRE2_ERROR_PARTIAL) {
// partial match:
// leave the start and end capture offsets (i.e. cap(0))
priv->capturedCount = 1;
@@ -1401,6 +1378,35 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
}
}
+ // copy the captured substrings offsets, if any
+ if (priv->capturedCount) {
+ PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
+ int * const capturedOffsets = priv->capturedOffsets.data();
+
+ for (int i = 0; i < priv->capturedCount * 2; ++i)
+ capturedOffsets[i] = static_cast<int>(ovector[i]);
+
+ // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
+ // are involved. PCRE2 reports the real begin of the match and the maximum
+ // used lookbehind as distinct information; PCRE1 instead automatically
+ // adjusted ovector[0] to include the maximum lookbehind.
+ //
+ // For instance, given the pattern "\bstring\b", and the subject "a str":
+ // * PCRE1 reports partial, capturing " str"
+ // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
+ //
+ // To keep behavior, emulate PCRE1 here.
+ // (Eventually, we could expose the lookbehind info in a future patch.)
+ if (result == PCRE2_ERROR_PARTIAL) {
+ unsigned int maximumLookBehind;
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
+ capturedOffsets[0] -= maximumLookBehind;
+ }
+ }
+
+ pcre2_match_data_free_16(matchData);
+ pcre2_match_context_free_16(matchContext);
+
return priv;
}
@@ -1412,19 +1418,13 @@ QRegularExpressionMatchPrivate::QRegularExpressionMatchPrivate(const QRegularExp
int subjectStart,
int subjectLength,
QRegularExpression::MatchType matchType,
- QRegularExpression::MatchOptions matchOptions,
- int capturingCount)
+ QRegularExpression::MatchOptions matchOptions)
: regularExpression(re), subject(subject),
subjectStart(subjectStart), subjectLength(subjectLength),
matchType(matchType), matchOptions(matchOptions),
capturedCount(0),
hasMatch(false), hasPartialMatch(false), isValid(false)
{
- Q_ASSERT(capturingCount >= 0);
- if (capturingCount > 0) {
- const int captureOffsetsCount = capturingCount * 3;
- capturedOffsets.resize(captureOffsetsCount);
- }
}
@@ -1632,13 +1632,13 @@ QStringList QRegularExpression::namedCaptureGroups() const
// contains one ushort followed by the name, NUL terminated.
// The ushort is the numerical index of the name in the pattern.
// The length of each entry is namedCapturingTableEntrySize.
- ushort *namedCapturingTable;
- int namedCapturingTableEntryCount;
- int namedCapturingTableEntrySize;
+ PCRE2_SPTR16 *namedCapturingTable;
+ unsigned int namedCapturingTableEntryCount;
+ unsigned int namedCapturingTableEntrySize;
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMETABLE, &namedCapturingTable);
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
QStringList result;
@@ -1647,9 +1647,9 @@ QStringList QRegularExpression::namedCaptureGroups() const
for (int i = 0; i < d->capturingCount + 1; ++i)
result.append(QString());
- for (int i = 0; i < namedCapturingTableEntryCount; ++i) {
- const ushort * const currentNamedCapturingTableRow = namedCapturingTable +
- namedCapturingTableEntrySize * i;
+ for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
+ const ushort * const currentNamedCapturingTableRow =
+ reinterpret_cast<const ushort *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
const int index = *currentNamedCapturingTableRow;
result[index] = QString::fromUtf16(currentNamedCapturingTableRow + 1);
@@ -1680,8 +1680,19 @@ bool QRegularExpression::isValid() const
QString QRegularExpression::errorString() const
{
d.data()->compilePattern();
- if (d->errorString)
- return QCoreApplication::translate("QRegularExpression", d->errorString);
+ if (d->errorCode) {
+ QString errorString;
+ int errorStringLength;
+ do {
+ errorString.resize(errorString.length() + 64);
+ errorStringLength = pcre2_get_error_message_16(d->errorCode,
+ reinterpret_cast<ushort *>(errorString.data()),
+ errorString.length());
+ } while (errorStringLength < 0);
+ errorString.resize(errorStringLength);
+
+ return QCoreApplication::translate("QRegularExpression", std::move(errorString).toLatin1().constData());
+ }
return QCoreApplication::translate("QRegularExpression", "no error");
}
@@ -2583,7 +2594,8 @@ QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match)
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2015 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -2625,80 +2637,149 @@ static const char *pcreCompileErrorCodes[] =
QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in character class"),
QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "nothing to repeat"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing )"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
- QT_TRANSLATE_NOOP("QRegularExpression", "erroffset passed as NULL"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unknown option bit(s) set"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after comment"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
- QT_TRANSLATE_NOOP("QRegularExpression", "failed to get memory"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unmatched parentheses"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?<"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "letter or underscore expected after (?< or (?'"),
QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"),
QT_TRANSLATE_NOOP("QRegularExpression", "malformed number or name after (?("),
QT_TRANSLATE_NOOP("QRegularExpression", "conditional group contains more than two branches"),
- QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?("),
+ QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
QT_TRANSLATE_NOOP("QRegularExpression", "(?R or (?[+-]digits must be followed by )"),
QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
- QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
- QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UTF8 support"),
- QT_TRANSLATE_NOOP("QRegularExpression", "character value in \\x{...} sequence is too large"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"),
QT_TRANSLATE_NOOP("QRegularExpression", "invalid condition (?(0)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "\\C not allowed in lookbehind assertion"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion"),
QT_TRANSLATE_NOOP("QRegularExpression", "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u"),
- QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is > 255"),
- QT_TRANSLATE_NOOP("QRegularExpression", "closing ) for (?C expected"),
- QT_TRANSLATE_NOOP("QRegularExpression", "recursive call could loop indefinitely"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"),
QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"),
QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-8 string"),
- QT_TRANSLATE_NOOP("QRegularExpression", "support for \\P, \\p, and \\X has not been compiled"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "group name must start with a non-digit"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"),
QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"),
QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"),
- QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum 32 characters)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum 10000)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 (not in UTF-8 mode)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "10000" " characters)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "256" ")"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"),
QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE group contains more than one branch"),
- QT_TRANSLATE_NOOP("QRegularExpression", "repeating a DEFINE group is not allowed"),
- QT_TRANSLATE_NOOP("QRegularExpression", "inconsistent NEWLINE options"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"),
QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"),
QT_TRANSLATE_NOOP("QRegularExpression", "a numbered reference must not be zero"),
QT_TRANSLATE_NOOP("QRegularExpression", "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
QT_TRANSLATE_NOOP("QRegularExpression", "number is too big"),
QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+"),
- QT_TRANSLATE_NOOP("QRegularExpression", "] is an invalid data character in JavaScript compatibility mode"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"),
QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"),
- QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UCP support"),
- QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by an ASCII character"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"),
QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in find_fixedlength()"),
QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "too many forward references"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "SPARE ERROR"),
QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-16 string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"),
QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "character value in \\u.... sequence is too large"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-32 string"),
- QT_TRANSLATE_NOOP("QRegularExpression", "setting UTF is disabled by the application"),
- QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
- QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "group name must start with a non-digit"),
- QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{}")
+ QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{}"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in (?(VERSION condition"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"), /* Never returned by PCRE2 itself */
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "recursion limit exceeded"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start is not supported"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)")
};
#endif // #if 0
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp
index cb11e72435..8fa378e935 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -132,7 +132,6 @@ char *QRingBuffer::reserve(qint64 bytes)
char *writePtr = buffers.last().data() + tail;
bufferSize += bytes;
- Q_ASSERT(bytes < MaxByteArraySize);
tail += int(bytes);
return writePtr;
}
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index 373fc3a662..15573c5588 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -977,13 +977,13 @@ qobject_cast(const QWeakPointer<T> &src)
}
template<typename T>
-QWeakPointer<typename QtPrivate::QEnableIf<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::Type>
+QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qWeakPointerFromVariant(const QVariant &variant)
{
return QWeakPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).data()));
}
template<typename T>
-QSharedPointer<typename QtPrivate::QEnableIf<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::Type>
+QSharedPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qSharedPointerFromVariant(const QVariant &variant)
{
return qSharedPointerObjectCast<T>(QtSharedPointer::sharedPointerFromVariant_internal(variant));
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
index d5d887598e..28253b3ae9 100644
--- a/src/corelib/tools/qsimd_p.h
+++ b/src/corelib/tools/qsimd_p.h
@@ -166,10 +166,11 @@
# define __MIPS_DSPR2__
# endif
#elif (defined(Q_CC_INTEL) || defined(Q_CC_MSVC) \
- || (defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && (__GNUC__-0) * 100 + (__GNUC_MINOR__-0) >= 409)) \
+ || (defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && Q_CC_GNU >= 409) \
+ || (defined(Q_CC_CLANG) && Q_CC_CLANG >= 308)) \
&& !defined(QT_BOOTSTRAPPED)
# define QT_COMPILER_SUPPORTS_SIMD_ALWAYS
-# define QT_COMPILER_SUPPORTS_HERE(x) (__ ## x ## __) || QT_COMPILER_SUPPORTS(x)
+# define QT_COMPILER_SUPPORTS_HERE(x) ((__ ## x ## __) || QT_COMPILER_SUPPORTS(x))
# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
/* GCC requires attributes for a function */
# define QT_FUNCTION_TARGET(x) __attribute__((__target__(QT_FUNCTION_TARGET_STRING_ ## x)))
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 247119d178..48f3d64c4a 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -211,7 +211,8 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW
{
/* SIMD:
* Unpacking with SSE has been shown to improve performance on recent CPUs
- * The same method gives no improvement with NEON.
+ * The same method gives no improvement with NEON. On Aarch64, clang will do the vectorization
+ * itself in exactly the same way as one would do it with intrinsics.
*/
#if defined(__SSE2__)
const char *e = str + size;
@@ -491,6 +492,30 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l)
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) {
+ const QChar *end = a + l;
+ const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
+ while (a + 7 < end) {
+ uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
+ uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b));
+
+ uint8_t r = ~(uint8_t)vaddvq_u16(vandq_u16(vceqq_u16(da, db), mask));
+ if (r) {
+ // found a different QChar
+ uint idx = qCountTrailingZeroBits(r);
+ return (int)a[idx].unicode() - (int)b[idx].unicode();
+ }
+ a += 8;
+ b += 8;
+ }
+ l &= 7;
+ }
+ const auto &lambda = [=](int i) -> int {
+ return a[i].unicode() - b[i].unicode();
+ };
+ return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
+#endif // __ARM_NEON__
if (!l)
return 0;
@@ -703,6 +728,18 @@ static int findChar(const QChar *str, int len, QChar ch, int from,
[=](int i) { return n - s + i; });
# endif
#endif
+#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+ const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
+ const uint16x8_t ch_vec = vdupq_n_u16(c);
+ for (const ushort *next = n + 8; next <= e; n = next, next += 8) {
+ uint16x8_t data = vld1q_u16(n);
+ uint mask = vaddvq_u16(vandq_u16(vceqq_u16(data, ch_vec), vmask));
+ if (ushort(mask)) {
+ // found a match
+ return n - s + qCountTrailingZeroBits(mask);
+ }
+ }
+#endif // aarch64
--n;
while (++n != e)
if (*n == c)
@@ -742,7 +779,9 @@ inline char qToLower(char ch)
}
+#if QT_DEPRECATED_SINCE(5, 9)
const QString::Null QString::null = { };
+#endif
/*!
\macro QT_RESTRICTED_CAST_FROM_ASCII
@@ -1617,7 +1656,7 @@ QString::QString(QChar ch)
\internal
*/
-/*! \fn QString &QString::operator=(const Null &)
+/*! \fn QString &QString::operator=(const QString::Null &)
\internal
*/
@@ -1767,17 +1806,11 @@ void QString::resize(int size, QChar fillChar)
void QString::reallocData(uint alloc, bool grow)
{
- size_t blockSize;
- if (grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
+ auto allocOptions = d->detachFlags();
+ if (grow)
+ allocOptions |= QArrayData::Grow;
if (d->ref.isShared() || IS_RAW_DATA(d)) {
- Data::AllocationOptions allocOptions(d->capacityReserved ? Data::CapacityReserved : 0);
Data *x = Data::allocate(alloc, allocOptions);
Q_CHECK_PTR(x);
x->size = qMin(int(alloc) - 1, d->size);
@@ -1787,11 +1820,9 @@ void QString::reallocData(uint alloc, bool grow)
Data::deallocate(d);
d = x;
} else {
- Data *p = static_cast<Data *>(::realloc(d, blockSize));
+ Data *p = Data::reallocateUnaligned(d, alloc, allocOptions);
Q_CHECK_PTR(p);
d = p;
- d->alloc = alloc;
- d->offset = sizeof(QStringData);
}
}
@@ -4466,11 +4497,11 @@ bool QString::startsWith(const QStringRef &s, Qt::CaseSensitivity cs) const
\sa startsWith()
*/
-bool QString::endsWith(const QString& 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);
- }
+}
/*!
\since 4.8
@@ -4606,6 +4637,8 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
QByteArray QString::toLocal8Bit_helper(const QChar *data, int size)
{
+ if (!data)
+ return QByteArray();
#ifndef QT_NO_TEXTCODEC
QTextCodec *localeCodec = QTextCodec::codecForLocale();
if (localeCodec)
@@ -4887,6 +4920,7 @@ QString QString::fromUcs4(const uint *unicode, int size)
return QUtf32::convertToUnicode((const char *)unicode, size*4, 0);
}
+
/*!
Resizes the string to \a size characters and copies \a unicode
into the string.
@@ -5981,7 +6015,10 @@ static uint parse_flag_characters(const char * &c) Q_DECL_NOTHROW
uint flags = QLocaleData::ZeroPadExponent;
while (true) {
switch (*c) {
- case '#': flags |= QLocaleData::Alternate; break;
+ case '#':
+ flags |= QLocaleData::ShowBase | QLocaleData::AddTrailingZeroes
+ | QLocaleData::ForcePoint;
+ break;
case '0': flags |= QLocaleData::ZeroPadded; break;
case '-': flags |= QLocaleData::LeftAdjusted; break;
case ' ': flags |= QLocaleData::BlankBeforePositive; break;
@@ -6239,7 +6276,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
case 'p': {
void *arg = va_arg(ap, void*);
const quint64 i = reinterpret_cast<quintptr>(arg);
- flags |= QLocaleData::Alternate;
+ flags |= QLocaleData::ShowBase;
subst = QLocaleData::c()->unsLongLongToString(i, precision, 16, width, flags);
++c;
break;
@@ -7814,10 +7851,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
if (d.locale_occurrences > 0) {
QLocale locale;
- if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
+ const QLocale::NumberOptions numberOptions = locale.numberOptions();
+ if (!(numberOptions & QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
- if (!(locale.numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
locale_arg = locale.d->m_data->doubleToString(a, prec, form, fieldWidth, flags);
}
@@ -8025,33 +8065,12 @@ bool QString::isSimpleText() const
/*! \fn bool QString::isRightToLeft() const
Returns \c true if the string is read right to left.
+
+ \sa QStringRef::isRightToLeft()
*/
bool QString::isRightToLeft() const
{
- const ushort *p = d->data();
- const ushort * const end = p + d->size;
- while (p < end) {
- uint ucs4 = *p;
- if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
- ushort low = p[1];
- if (QChar::isLowSurrogate(low)) {
- ucs4 = QChar::surrogateToUcs4(ucs4, low);
- ++p;
- }
- }
- switch (QChar::direction(ucs4))
- {
- case QChar::DirL:
- return false;
- case QChar::DirR:
- case QChar::DirAL:
- return true;
- default:
- break;
- }
- ++p;
- }
- return false;
+ return QStringRef(this).isRightToLeft();
}
/*! \fn QChar *QString::data()
@@ -9007,7 +9026,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in
the string.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9016,7 +9035,16 @@ ownership of it, no memory is freed when instances are destroyed.
Same as begin().
- \sa begin(), cend(), rbegin(), rend()
+ \sa begin(), constBegin(), cend(), constEnd(), rbegin(), rend()
+*/
+
+/*!
+ \fn QStringRef::const_iterator QStringRef::constBegin() const
+ \since 5.9
+
+ Same as begin().
+
+ \sa begin(), cend(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9026,7 +9054,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
character after the last character in the list.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*! \fn QStringRef::const_iterator QStringRef::cend() const
@@ -9034,7 +9062,15 @@ ownership of it, no memory is freed when instances are destroyed.
Same as end().
- \sa end(), cbegin(), rbegin(), rend()
+ \sa end(), constEnd(), cbegin(), constBegin(), rbegin(), rend()
+*/
+
+/*! \fn QStringRef::const_iterator QStringRef::constEnd() const
+ \since 5.9
+
+ Same as end().
+
+ \sa end(), cend(), cbegin(), constBegin(), rbegin(), rend()
*/
/*!
@@ -9585,9 +9621,7 @@ QStringRef QStringRef::left(int n) const
*/
QStringRef QString::leftRef(int n) const
{
- if (uint(n) >= uint(d->size))
- n = d->size;
- return QStringRef(this, 0, n);
+ return QStringRef(this).left(n);
}
/*!
@@ -9624,9 +9658,7 @@ QStringRef QStringRef::right(int n) const
*/
QStringRef QString::rightRef(int n) const
{
- if (uint(n) >= uint(d->size))
- n = d->size;
- return QStringRef(this, d->size - n, n);
+ return QStringRef(this).right(n);
}
/*!
@@ -9685,19 +9717,7 @@ QStringRef QStringRef::mid(int pos, int n) const
*/
QStringRef QString::midRef(int position, int n) const
{
- using namespace QtPrivate;
- switch (QContainerImplHelper::mid(d->size, &position, &n)) {
- case QContainerImplHelper::Null:
- return QStringRef();
- case QContainerImplHelper::Empty:
- return QStringRef(this, 0, 0);
- case QContainerImplHelper::Full:
- return QStringRef(this, 0, d->size);
- case QContainerImplHelper::Subset:
- return QStringRef(this, position, n);
- }
- Q_UNREACHABLE();
- return QStringRef();
+ return QStringRef(this).mid(position, n);
}
/*!
@@ -9944,6 +9964,41 @@ int QStringRef::count(const QStringRef &str, Qt::CaseSensitivity cs) const
}
/*!
+ \since 5.9
+
+ Returns \c true if the string is read right to left.
+
+ \sa QString::isRightToLeft()
+*/
+bool QStringRef::isRightToLeft() const
+{
+ const ushort *p = reinterpret_cast<const ushort*>(unicode());
+ const ushort * const end = p + size();
+ while (p < end) {
+ uint ucs4 = *p;
+ if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
+ ushort low = p[1];
+ if (QChar::isLowSurrogate(low)) {
+ ucs4 = QChar::surrogateToUcs4(ucs4, low);
+ ++p;
+ }
+ }
+ switch (QChar::direction(ucs4))
+ {
+ case QChar::DirL:
+ return false;
+ case QChar::DirR:
+ case QChar::DirAL:
+ return true;
+ default:
+ break;
+ }
+ ++p;
+ }
+ return false;
+}
+
+/*!
\since 4.8
Returns \c true if the string reference starts with \a str; otherwise
@@ -10309,6 +10364,8 @@ 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());
}
@@ -10347,9 +10404,11 @@ QByteArray QStringRef::toLatin1() const
QByteArray QStringRef::toLocal8Bit() const
{
#ifndef QT_NO_TEXTCODEC
- QTextCodec *localeCodec = QTextCodec::codecForLocale();
- if (localeCodec)
- return localeCodec->fromUnicode(unicode(), length());
+ if (!isNull()) {
+ QTextCodec *localeCodec = QTextCodec::codecForLocale();
+ if (localeCodec)
+ return localeCodec->fromUnicode(unicode(), length());
+ }
#endif // QT_NO_TEXTCODEC
return toLatin1();
}
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index b50b2ee4e5..1bd436c387 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -144,15 +144,10 @@ typedef QLatin1String QLatin1Literal;
typedef QTypedArrayData<ushort> QStringData;
-#if defined(Q_COMPILER_UNICODE_STRINGS)
-
-#define QT_UNICODE_LITERAL_II(str) u"" str
-typedef char16_t qunicodechar;
-
-#elif defined(Q_OS_WIN) \
- || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) \
- || (!defined(__SIZEOF_WCHAR_T__) && defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536))
-// wchar_t is 2 bytes
+#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
@@ -162,21 +157,22 @@ typedef char16_t qunicodechar;
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_NO_UNICODE_LITERAL
-typedef ushort qunicodechar;
+#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");
-#ifndef QT_NO_UNICODE_LITERAL
-# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
-# if defined(Q_COMPILER_LAMBDA)
-
-# define QStringLiteral(str) \
- ([]() -> QString { \
+#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), \
@@ -187,17 +183,6 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
}()) \
/**/
-# endif
-#endif // QT_NO_UNICODE_LITERAL
-
-#ifndef QStringLiteral
-// no lambdas, not GCC, or GCC in C++98 mode with 4-byte wchar_t
-// fallback, return a temporary QString
-// source code is assumed to be encoded in UTF-8
-
-# define QStringLiteral(str) QString::fromUtf8("" str "", sizeof(str) - 1)
-#endif
-
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
/**/
@@ -397,7 +382,7 @@ public:
QString leftJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT;
QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT;
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT")
@@ -522,7 +507,7 @@ public:
const ushort *utf16() const;
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
QByteArray toLatin1() const & Q_REQUIRED_RESULT
{ return toLatin1_helper(*this); }
QByteArray toLatin1() && Q_REQUIRED_RESULT
@@ -532,9 +517,9 @@ public:
QByteArray toUtf8() && Q_REQUIRED_RESULT
{ return toUtf8_helper(*this); }
QByteArray toLocal8Bit() const & Q_REQUIRED_RESULT
- { return toLocal8Bit_helper(constData(), size()); }
+ { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
QByteArray toLocal8Bit() && Q_REQUIRED_RESULT
- { return toLocal8Bit_helper(constData(), size()); }
+ { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
#else
QByteArray toLatin1() const Q_REQUIRED_RESULT;
QByteArray toUtf8() const Q_REQUIRED_RESULT;
@@ -785,10 +770,13 @@ public:
NSString *toNSString() const Q_DECL_NS_RETURNS_AUTORELEASED;
#endif
// compatibility
+#if QT_DEPRECATED_SINCE(5, 9)
struct Null { };
+ QT_DEPRECATED_X("use QString()")
static const Null null;
inline QString(const Null &): d(Data::sharedNull()) {}
inline QString &operator=(const Null &) { *this = QString(); return *this; }
+#endif
inline bool isNull() const { return d == Data::sharedNull(); }
@@ -1149,13 +1137,18 @@ inline bool QString::contains(QLatin1String s, Qt::CaseSensitivity cs) const
inline bool QString::contains(QChar c, Qt::CaseSensitivity cs) const
{ return indexOf(c, 0, cs) != -1; }
-
+#if QT_DEPRECATED_SINCE(5, 9)
inline bool operator==(QString::Null, QString::Null) { return true; }
+QT_DEPRECATED_X("use QString::isNull()")
inline bool operator==(QString::Null, const QString &s) { return s.isNull(); }
+QT_DEPRECATED_X("use QString::isNull()")
inline bool operator==(const QString &s, QString::Null) { return s.isNull(); }
inline bool operator!=(QString::Null, QString::Null) { return false; }
+QT_DEPRECATED_X("use !QString::isNull()")
inline bool operator!=(QString::Null, const QString &s) { return !s.isNull(); }
+QT_DEPRECATED_X("use !QString::isNull()")
inline bool operator!=(const QString &s, QString::Null) { return !s.isNull(); }
+#endif
inline bool operator==(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ return s1.size() == s2.size() && (!s1.size() || !memcmp(s1.latin1(), s2.latin1(), s1.size())); }
@@ -1400,7 +1393,8 @@ public:
QStringRef(QStringRef &&other) Q_DECL_NOTHROW : m_string(other.m_string), m_position(other.m_position), m_size(other.m_size) {}
QStringRef &operator=(QStringRef &&other) Q_DECL_NOTHROW { return *this = other; }
#endif
- QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW {
+ QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW
+ {
m_string = other.m_string; m_position = other.m_position;
m_size = other.m_size; return *this;
}
@@ -1449,6 +1443,8 @@ public:
m_size -= n;
}
+ bool isRightToLeft() const;
+
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
@@ -1461,7 +1457,8 @@ public:
inline QStringRef &operator=(const QString *string);
- inline const QChar *unicode() const {
+ inline const QChar *unicode() const
+ {
if (!m_string)
return reinterpret_cast<const QChar *>(QString::Data::sharedNull()->data());
return m_string->unicode() + m_position;
@@ -1471,8 +1468,10 @@ public:
inline const_iterator begin() const { return unicode(); }
inline const_iterator cbegin() const { return unicode(); }
+ inline const_iterator constBegin() const { return unicode(); }
inline const_iterator end() const { return unicode() + size(); }
inline const_iterator cend() const { return unicode() + size(); }
+ inline const_iterator constEnd() const { return unicode() + size(); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
inline const_reverse_iterator crbegin() const { return rbegin(); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
diff --git a/src/corelib/tools/qstring_compat.cpp b/src/corelib/tools/qstring_compat.cpp
index 300f8467b1..45bb816e4b 100644
--- a/src/corelib/tools/qstring_compat.cpp
+++ b/src/corelib/tools/qstring_compat.cpp
@@ -80,7 +80,7 @@ QByteArray QString::toLatin1() const
QByteArray QString::toLocal8Bit() const
{
- return toLocal8Bit_helper(constData(), size());
+ return toLocal8Bit_helper(isNull() ? nullptr : constData(), size());
}
QByteArray QString::toUtf8() const
diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h
index b2832b5fbe..9a40abcfed 100644
--- a/src/corelib/tools/qstringbuilder.h
+++ b/src/corelib/tools/qstringbuilder.h
@@ -277,9 +277,9 @@ template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
+template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
{
- typedef char type[N];
+ typedef const char type[N];
typedef QByteArray ConvertTo;
enum { ExactSize = false };
static int size(const char[N]) { return N - 1; }
@@ -296,23 +296,9 @@ template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
+template <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
{
- typedef const char type[N];
- typedef QByteArray ConvertTo;
- enum { ExactSize = false };
- static int size(const char[N]) { return N - 1; }
-#ifndef QT_NO_CAST_FROM_ASCII
- static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
- {
- QAbstractConcatenable::convertFromAscii(a, N - 1, out);
- }
-#endif
- static inline void appendTo(const char a[N], char *&out)
- {
- while (*a)
- *out++ = *a++;
- }
+ typedef char type[N];
};
template <> struct QConcatenable<const char *> : private QAbstractConcatenable
diff --git a/src/corelib/tools/qtimezone.h b/src/corelib/tools/qtimezone.h
index 083f87f39f..bd87139f5b 100644
--- a/src/corelib/tools/qtimezone.h
+++ b/src/corelib/tools/qtimezone.h
@@ -47,6 +47,11 @@
QT_REQUIRE_CONFIG(timezone);
+#if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+Q_FORWARD_DECLARE_CF_TYPE(CFTimeZone);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
+#endif
+
QT_BEGIN_NAMESPACE
class QTimeZonePrivate;
@@ -142,6 +147,13 @@ public:
static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Country country);
+#if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+ static QTimeZone fromCFTimeZone(CFTimeZoneRef timeZone);
+ CFTimeZoneRef toCFTimeZone() const Q_DECL_CF_RETURNS_RETAINED;
+ static QTimeZone fromNSTimeZone(const NSTimeZone *timeZone);
+ NSTimeZone *toNSTimeZone() const Q_DECL_NS_RETURNS_AUTORELEASED;
+#endif
+
private:
QTimeZone(QTimeZonePrivate &dd);
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qtimezoneprivate.cpp b/src/corelib/tools/qtimezoneprivate.cpp
index 2ff03eddec..7b780ecf7d 100644
--- a/src/corelib/tools/qtimezoneprivate.cpp
+++ b/src/corelib/tools/qtimezoneprivate.cpp
@@ -49,10 +49,6 @@
QT_BEGIN_NAMESPACE
-enum {
- MSECS_TRAN_WINDOW = 21600000 // 6 hour window for possible recent transitions
-};
-
/*
Static utilities for looking up Windows ID tables
*/
@@ -140,7 +136,7 @@ QTimeZonePrivate::~QTimeZonePrivate()
{
}
-QTimeZonePrivate *QTimeZonePrivate::clone()
+QTimeZonePrivate *QTimeZonePrivate::clone() const
{
return new QTimeZonePrivate(*this);
}
@@ -248,67 +244,206 @@ QTimeZonePrivate::Data QTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
}
// Private only method for use by QDateTime to convert local msecs to epoch msecs
-// TODO Could be platform optimised if needed
-QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs) const
+QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, int hint) const
{
- if (!hasDaylightTime() ||!hasTransitions()) {
- // No DST means same offset for all local msecs
- // Having DST but no transitions means we can't calculate, so use nearest
- return data(forLocalMSecs - (standardTimeOffset(forLocalMSecs) * 1000));
- }
+ if (!hasDaylightTime()) // No DST means same offset for all local msecs
+ return data(forLocalMSecs - standardTimeOffset(forLocalMSecs) * 1000);
- // Get the transition for the local msecs which most of the time should be the right one
- // Only around the transition times might it not be the right one
- Data tran = previousTransition(forLocalMSecs);
- Data nextTran;
-
- // If the local msecs is less than the real local time of the transition
- // then get the previous transition to use instead
- if (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
- while (tran.atMSecsSinceEpoch != invalidMSecs()
- && forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
- nextTran = tran;
- tran = previousTransition(tran.atMSecsSinceEpoch);
- }
- } else {
- // The zone msecs is after the transition, so check it is before the next tran
- // If not try use the next transition instead
- nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ /*
+ We need a UTC time at which to ask for the offset, in order to be able to
+ add that offset to forLocalMSecs, to get the UTC time we
+ need. Fortunately, no time-zone offset is more than 14 hours; and DST
+ transitions happen (much) more than thirty-two hours apart. So sampling
+ offset sixteen hours each side gives us information we can be sure
+ brackets the correct time and at most one DST transition.
+ */
+ const qint64 sixteenHoursInMSecs(16 * 3600 * 1000);
+ /*
+ Offsets are Local - UTC, positive to the east of Greenwich, negative to
+ the west; DST offset always exceeds standard offset, when DST applies.
+ When we have offsets on either side of a transition, the lower one is
+ standard, the higher is DST.
+
+ Non-DST transitions (jurisdictions changing time-zone and time-zones
+ changing their standard offset, typically) are described below as if they
+ were DST transitions (since these are more usual and familiar); the code
+ mostly concerns itself with offsets from UTC, described in terms of the
+ common case for changes in that. If there is no actual change in offset
+ (e.g. a DST transition cancelled by a standard offset change), this code
+ should handle it gracefully; without transitions, it'll see early == late
+ and take the easy path; with transitions, tran and nextTran get the
+ correct UTC time as atMSecsSinceEpoch so comparing to nextStart selects
+ the right one. In all other cases, the transition changes offset and the
+ reasoning that applies to DST applies just the same. Aside from hinting,
+ the only thing that looks at DST-ness at all, other than inferred from
+ offset changes, is the case without transition data handling an invalid
+ time in the gap that a transition passed over.
+
+ The handling of hint (see below) is apt to go wrong in non-DST
+ transitions. There isn't really a great deal we can hope to do about that
+ without adding yet more unreliable complexity to the heuristics in use for
+ already obscure corner-cases.
+ */
+
+ /*
+ The hint (really a QDateTimePrivate::DaylightStatus) is > 0 if caller
+ thinks we're in DST, 0 if in standard. A value of -2 means never-DST, so
+ should have been handled above; if it slips through, it's wrong but we
+ should probably treat it as standard anyway (never-DST means
+ always-standard, after all). If the hint turns out to be wrong, fall back
+ on trying the other possibility: which makes it harmless to treat -1
+ (meaning unknown) as standard (i.e. try standard first, then try DST). In
+ practice, away from a transition, the only difference hint makes is to
+ which candidate we try first: if the hint is wrong (or unknown and
+ standard fails), we'll try the other candidate and it'll work.
+
+ For the obscure (and invalid) case where forLocalMSecs falls in a
+ spring-forward's missing hour, a common case is that we started with a
+ date/time for which the hint was valid and adjusted it naively; for that
+ case, we should correct the adjustment by shunting across the transition
+ into where hint is wrong. So half-way through the gap, arrived at from
+ the DST side, should be read as an hour earlier, in standard time; but, if
+ arrived at from the standard side, should be read as an hour later, in
+ DST. (This shall be wrong in some cases; for example, when a country
+ changes its transition dates and changing a date/time by more than six
+ months lands it on a transition. However, these cases are even more
+ obscure than those where the heuristic is good.)
+ */
+
+ if (hasTransitions()) {
+ /*
+ We have transitions.
+
+ Each transition gives the offsets to use until the next; so we need the
+ most recent transition before the time forLocalMSecs describes. If it
+ describes a time *in* a transition, we'll need both that transition and
+ the one before it. So find one transition that's probably after (and not
+ much before, otherwise) and another that's definitely before, then work
+ out which one to use. When both or neither work on forLocalMSecs, use
+ hint to disambiguate.
+ */
+
+ // Get a transition definitely before the local MSecs; usually all we need.
+ // Only around the transition times might we need another.
+ Data tran = previousTransition(forLocalMSecs - sixteenHoursInMSecs);
+ Q_ASSERT(forLocalMSecs < 0 || // Pre-epoch TZ info may be unavailable
+ forLocalMSecs >= tran.atMSecsSinceEpoch + tran.offsetFromUtc * 1000);
+ Data nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ /*
+ Now walk those forward until they bracket forLocalMSecs with transitions.
+
+ One of the transitions should then be telling us the right offset to use.
+ In a transition, we need the transition before it (to describe the run-up
+ to the transition) and the transition itself; so we need to stop when
+ nextTran is that transition.
+ */
while (nextTran.atMSecsSinceEpoch != invalidMSecs()
- && forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
+ && forLocalMSecs > nextTran.atMSecsSinceEpoch + nextTran.offsetFromUtc * 1000) {
+ Data newTran = nextTransition(nextTran.atMSecsSinceEpoch);
+ if (newTran.atMSecsSinceEpoch == invalidMSecs()
+ || newTran.atMSecsSinceEpoch + newTran.offsetFromUtc * 1000
+ > forLocalMSecs + sixteenHoursInMSecs) {
+ // Definitely not a relevant tansition: too far in the future.
+ break;
+ }
tran = nextTran;
- nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ nextTran = newTran;
}
+
+ // Check we do *really* have transitions for this zone:
+ if (tran.atMSecsSinceEpoch != invalidMSecs()) {
+
+ /*
+ So now tran is definitely before and nextTran is either after or only
+ slightly before. The one with the larger offset is in DST; the other in
+ standard time. Our hint tells us which of those to use (defaulting to
+ standard if no hint): try it first; if that fails, try the other; if both
+ fail life's tricky.
+ */
+ Q_ASSERT(forLocalMSecs < 0
+ || forLocalMSecs > tran.atMSecsSinceEpoch + tran.offsetFromUtc * 1000);
+ const qint64 nextStart = nextTran.atMSecsSinceEpoch;
+ // Work out the UTC values it might make sense to return:
+ nextTran.atMSecsSinceEpoch = forLocalMSecs - nextTran.offsetFromUtc * 1000;
+ tran.atMSecsSinceEpoch = forLocalMSecs - tran.offsetFromUtc * 1000;
+
+ const bool nextIsDst = tran.offsetFromUtc < nextTran.offsetFromUtc;
+ // If that agrees with hint > 0, our first guess is to use nextTran; else tran.
+ const bool nextFirst = nextIsDst == (hint > 0) && nextStart != invalidMSecs();
+ for (int i = 0; i < 2; i++) {
+ /*
+ On the first pass, the case we consider is what hint told us to expect
+ (except when hint was -1 and didn't actually tell us what to expect),
+ so it's likely right. We only get a second pass if the first failed,
+ by which time the second case, that we're trying, is likely right. If
+ an overwhelming majority of calls have hint == -1, the Q_LIKELY here
+ shall be wrong half the time; otherwise, its errors shall be rarer
+ than that.
+ */
+ if (nextFirst ? i == 0 : i) {
+ Q_ASSERT(nextStart != invalidMSecs());
+ if (Q_LIKELY(nextStart <= nextTran.atMSecsSinceEpoch))
+ return nextTran;
+ } else {
+ // If next is invalid, nextFirst is false, to route us here first:
+ if (nextStart == invalidMSecs() || Q_LIKELY(nextStart > tran.atMSecsSinceEpoch))
+ return tran;
+ }
+ }
+
+ /*
+ Neither is valid (e.g. in a spring-forward's gap) and
+ nextTran.atMSecsSinceEpoch < nextStart <= tran.atMSecsSinceEpoch, so
+ 0 < tran.atMSecsSinceEpoch - nextTran.atMSecsSinceEpoch
+ = (nextTran.offsetFromUtc - tran.offsetFromUtc) * 1000
+ */
+ int dstStep = nextTran.offsetFromUtc - tran.offsetFromUtc;
+ Q_ASSERT(dstStep > 0); // How else could we get here ?
+ if (nextFirst) { // hint thought we needed nextTran, so use tran
+ tran.atMSecsSinceEpoch -= dstStep;
+ return tran;
+ }
+ nextTran.atMSecsSinceEpoch += dstStep;
+ return nextTran;
+ }
+ // System has transitions but not for this zone.
+ // Try falling back to offsetFromUtc
}
- if (tran.daylightTimeOffset == 0) {
- // If tran is in StandardTime, then need to check if falls close to either DST transition.
- // If it does, then it may need adjusting for missing hour or for second occurrence
- qint64 diffPrevTran = forLocalMSecs
- - (tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000));
- qint64 diffNextTran = nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)
- - forLocalMSecs;
- if (diffPrevTran >= 0 && diffPrevTran < MSECS_TRAN_WINDOW) {
- // If tran picked is for standard time check if changed from DST in last 6 hours,
- // as the local msecs may be ambiguous and represent two valid utc msecs.
- // If in last 6 hours then get prev tran and if diff falls within the DST offset
- // then use the prev tran as we default to the FirstOccurrence
- // TODO Check if faster to just always get prev tran, or if faster using 6 hour check.
- Data dstTran = previousTransition(tran.atMSecsSinceEpoch);
- if (dstTran.atMSecsSinceEpoch != invalidMSecs()
- && dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
- tran = dstTran;
- } else if (diffNextTran >= 0 && diffNextTran <= (nextTran.daylightTimeOffset * 1000)) {
- // If time falls within last hour of standard time then is actually the missing hour
- // So return the next tran instead and adjust the local time to be valid
- tran = nextTran;
- forLocalMSecs = forLocalMSecs + (nextTran.daylightTimeOffset * 1000);
+ /* Bracket and refine to discover offset. */
+ qint64 utcEpochMSecs;
+
+ int early = offsetFromUtc(forLocalMSecs - sixteenHoursInMSecs);
+ int late = offsetFromUtc(forLocalMSecs + sixteenHoursInMSecs);
+ if (Q_LIKELY(early == late)) { // > 99% of the time
+ utcEpochMSecs = forLocalMSecs - early * 1000;
+ } else {
+ // Close to a DST transition: early > late is near a fall-back,
+ // early < late is near a spring-forward.
+ const int offsetInDst = qMax(early, late);
+ const int offsetInStd = qMin(early, late);
+ // Candidate values for utcEpochMSecs (if forLocalMSecs is valid):
+ const qint64 forDst = forLocalMSecs - offsetInDst * 1000;
+ const qint64 forStd = forLocalMSecs - offsetInStd * 1000;
+ // Best guess at the answer:
+ const qint64 hinted = hint > 0 ? forDst : forStd;
+ if (Q_LIKELY(offsetFromUtc(hinted) == (hint > 0 ? offsetInDst : offsetInStd))) {
+ utcEpochMSecs = hinted;
+ } else if (hint <= 0 && offsetFromUtc(forDst) == offsetInDst) {
+ utcEpochMSecs = forDst;
+ } else if (hint > 0 && offsetFromUtc(forStd) == offsetInStd) {
+ utcEpochMSecs = forStd;
+ } else {
+ // Invalid forLocalMSecs: in spring-forward gap.
+ const int dstStep = daylightTimeOffset(early < late ?
+ forLocalMSecs + sixteenHoursInMSecs :
+ forLocalMSecs - sixteenHoursInMSecs);
+ Q_ASSERT(dstStep); // There can't be a transition without it !
+ utcEpochMSecs = (hint > 0) ? forStd - dstStep : forDst + dstStep;
}
}
- // tran should now hold the right transition offset to use
- tran.atMSecsSinceEpoch = forLocalMSecs - (tran.offsetFromUtc * 1000);
- return tran;
+ return data(utcEpochMSecs);
}
bool QTimeZonePrivate::hasTransitions() const
@@ -649,7 +784,7 @@ QUtcTimeZonePrivate::~QUtcTimeZonePrivate()
{
}
-QTimeZonePrivate *QUtcTimeZonePrivate::clone()
+QUtcTimeZonePrivate *QUtcTimeZonePrivate::clone() const
{
return new QUtcTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qtimezoneprivate_android.cpp b/src/corelib/tools/qtimezoneprivate_android.cpp
index 53bf90f01d..c3f8c3e0d9 100644
--- a/src/corelib/tools/qtimezoneprivate_android.cpp
+++ b/src/corelib/tools/qtimezoneprivate_android.cpp
@@ -88,7 +88,7 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId)
m_id = ianaId;
}
-QTimeZonePrivate *QAndroidTimeZonePrivate::clone()
+QAndroidTimeZonePrivate *QAndroidTimeZonePrivate::clone() const
{
return new QAndroidTimeZonePrivate(*this);
}
@@ -207,58 +207,6 @@ QTimeZonePrivate::Data QAndroidTimeZonePrivate::previousTransition(qint64 before
return invalidData();
}
-// Since Android does not provide an API to access transitions,
-// dataForLocalTime needs to be reimplemented without direct use of transitions
-QTimeZonePrivate::Data QAndroidTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs) const
-{
- if (!androidTimeZone.isValid()) {
- return invalidData();
- } else {
- qint64 UTCepochMSecs;
-
- // compare the UTC time with standard offset against normal DST offset of one hour
- qint64 standardUTCMSecs(forLocalMSecs - (standardTimeOffset(forLocalMSecs) * 1000));
- qint64 daylightUTCMsecs;
-
- // Check if daylight-saving time applies,
- // checking also for DST boundaries
- if (isDaylightTime(standardUTCMSecs)) {
- // If DST does apply, then standardUTCMSecs will be an hour or so ahead of the real epoch time
- // so check that time
- daylightUTCMsecs = standardUTCMSecs - daylightTimeOffset(standardUTCMSecs)*1000;
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST confirmed
- UTCepochMSecs = daylightUTCMsecs;
- } else {
- // DST has just finished
- UTCepochMSecs = standardUTCMSecs;
- }
- } else {
- // Standard time indicated, but check for a false negative.
- // Would a standard one-hour DST offset indicate DST?
- daylightUTCMsecs = standardUTCMSecs - 3600000; // 3600000 MSECS_PER_HOUR
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST may have just started,
- // but double check against timezone's own DST offset
- // (don't necessarily assume a one-hour offset)
- daylightUTCMsecs = standardUTCMSecs - daylightTimeOffset(daylightUTCMsecs)*1000;
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST confirmed
- UTCepochMSecs = daylightUTCMsecs;
- } else {
- // false positive, apply standard time after all
- UTCepochMSecs = standardUTCMSecs;
- }
- } else {
- // confirmed standard time
- UTCepochMSecs = standardUTCMSecs;
- }
- }
-
- return data(UTCepochMSecs);
- }
-}
-
QByteArray QAndroidTimeZonePrivate::systemTimeZoneId() const
{
QJNIObjectPrivate androidSystemTimeZone = QJNIObjectPrivate::callStaticObjectMethod("java.util.TimeZone", "getDefault", "()Ljava/util/TimeZone;");
diff --git a/src/corelib/tools/qtimezoneprivate_icu.cpp b/src/corelib/tools/qtimezoneprivate_icu.cpp
index c088fe7694..a7226f2720 100644
--- a/src/corelib/tools/qtimezoneprivate_icu.cpp
+++ b/src/corelib/tools/qtimezoneprivate_icu.cpp
@@ -98,7 +98,7 @@ static QByteArray ucalDefaultTimeZoneId()
// If successful on first or second go, resize and return
if (U_SUCCESS(status)) {
result.resize(size);
- return result.toUtf8();
+ return std::move(result).toUtf8();
}
return QByteArray();
@@ -305,7 +305,7 @@ QIcuTimeZonePrivate::~QIcuTimeZonePrivate()
ucal_close(m_ucal);
}
-QTimeZonePrivate *QIcuTimeZonePrivate::clone()
+QIcuTimeZonePrivate *QIcuTimeZonePrivate::clone() const
{
return new QIcuTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qtimezoneprivate_mac.mm b/src/corelib/tools/qtimezoneprivate_mac.mm
index 5dfffeaf36..4e9a432fbf 100644
--- a/src/corelib/tools/qtimezoneprivate_mac.mm
+++ b/src/corelib/tools/qtimezoneprivate_mac.mm
@@ -82,7 +82,7 @@ QMacTimeZonePrivate::~QMacTimeZonePrivate()
[m_nstz release];
}
-QTimeZonePrivate *QMacTimeZonePrivate::clone()
+QMacTimeZonePrivate *QMacTimeZonePrivate::clone() const
{
return new QMacTimeZonePrivate(*this);
}
@@ -273,4 +273,9 @@ QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds() const
return list;
}
+NSTimeZone *QMacTimeZonePrivate::nsTimeZone() const
+{
+ return m_nstz;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h
index d06784b0f9..0038908160 100644
--- a/src/corelib/tools/qtimezoneprivate_p.h
+++ b/src/corelib/tools/qtimezoneprivate_p.h
@@ -60,13 +60,9 @@
#include <unicode/ucal.h>
#endif
-#ifdef Q_OS_MAC
-#ifdef __OBJC__
-@class NSTimeZone;
-#else
-class NSTimeZone;
-#endif // __OBJC__
-#endif // Q_OS_MAC
+#ifdef Q_OS_DARWIN
+Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
+#endif // Q_OS_DARWIN
#ifdef Q_OS_WIN
#include <qt_windows.h>
@@ -78,7 +74,7 @@ class NSTimeZone;
QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QTimeZonePrivate : public QSharedData
+class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData
{
public:
//Version of QTimeZone::OffsetData struct using msecs for efficiency
@@ -96,7 +92,7 @@ public:
QTimeZonePrivate(const QTimeZonePrivate &other);
virtual ~QTimeZonePrivate();
- virtual QTimeZonePrivate *clone();
+ virtual QTimeZonePrivate *clone() const;
bool operator==(const QTimeZonePrivate &other) const;
bool operator!=(const QTimeZonePrivate &other) const;
@@ -123,7 +119,7 @@ public:
virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
virtual Data data(qint64 forMSecsSinceEpoch) const;
- virtual Data dataForLocalTime(qint64 forLocalMSecs) const;
+ Data dataForLocalTime(qint64 forLocalMSecs, int hint) const;
virtual bool hasTransitions() const;
virtual Data nextTransition(qint64 afterMSecsSinceEpoch) const;
@@ -191,7 +187,7 @@ public:
QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other);
virtual ~QUtcTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QUtcTimeZonePrivate *clone() const override;
Data data(qint64 forMSecsSinceEpoch) const Q_DECL_OVERRIDE;
@@ -238,7 +234,7 @@ public:
QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other);
~QIcuTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QIcuTimeZonePrivate *clone() const override;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const Q_DECL_OVERRIDE;
@@ -291,15 +287,15 @@ Q_DECL_CONSTEXPR inline bool operator!=(const QTzTransitionRule &lhs, const QTzT
class Q_AUTOTEST_EXPORT QTzTimeZonePrivate Q_DECL_FINAL : public QTimeZonePrivate
{
+ QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default;
public:
// Create default time zone
QTzTimeZonePrivate();
// Create named time zone
QTzTimeZonePrivate(const QByteArray &ianaId);
- QTzTimeZonePrivate(const QTzTimeZonePrivate &other);
~QTzTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QTzTimeZonePrivate *clone() const override;
QLocale::Country country() const Q_DECL_OVERRIDE;
QString comment() const Q_DECL_OVERRIDE;
@@ -355,7 +351,7 @@ public:
QMacTimeZonePrivate(const QMacTimeZonePrivate &other);
~QMacTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QMacTimeZonePrivate *clone() const override;
QString comment() const Q_DECL_OVERRIDE;
@@ -380,6 +376,8 @@ public:
QList<QByteArray> availableTimeZoneIds() const Q_DECL_OVERRIDE;
+ NSTimeZone *nsTimeZone() const;
+
private:
void init(const QByteArray &zoneId);
@@ -406,7 +404,7 @@ public:
QWinTimeZonePrivate(const QWinTimeZonePrivate &other);
~QWinTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QWinTimeZonePrivate *clone() const override;
QString comment() const Q_DECL_OVERRIDE;
@@ -456,7 +454,7 @@ public:
QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &other);
~QAndroidTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QAndroidTimeZonePrivate *clone() const override;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const Q_DECL_OVERRIDE;
@@ -475,8 +473,6 @@ public:
Data nextTransition(qint64 afterMSecsSinceEpoch) const Q_DECL_OVERRIDE;
Data previousTransition(qint64 beforeMSecsSinceEpoch) const Q_DECL_OVERRIDE;
- Data dataForLocalTime(qint64 forLocalMSecs) const Q_DECL_OVERRIDE;
-
QByteArray systemTimeZoneId() const Q_DECL_OVERRIDE;
QList<QByteArray> availableTimeZoneIds() const Q_DECL_OVERRIDE;
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
index 10b61c3a40..1714c9802f 100644
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
@@ -199,7 +199,7 @@ static QVector<QTzTransition> parseTzTransitions(QDataStream &ds, int tzh_timecn
}
} else {
// Parse tzh_timecnt x 4-byte transition times
- int val;
+ qint32 val;
for (int i = 0; i < tzh_timecnt && ds.status() == QDataStream::Ok; ++i) {
ds >> val;
transitions[i].tz_time = val;
@@ -452,13 +452,31 @@ static inline bool asciiIsLetter(char ch)
return ch >= 'a' && ch <= 'z';
}
+namespace {
+
+struct PosixZone
+{
+ enum {
+ InvalidOffset = INT_MIN,
+ };
+
+ QString name;
+ int offset;
+
+ static PosixZone invalid() { return {QString(), InvalidOffset}; }
+ static PosixZone parse(const char *&pos, const char *end);
+
+ bool hasValidOffset() const Q_DECL_NOTHROW { return offset != InvalidOffset; }
+};
+
+} // unnamed namespace
+
// Returns the zone name, the offset (in seconds) and advances \a begin to
// where the parsing ended. Returns a zone of INT_MIN in case an offset
// couldn't be read.
-static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end)
+PosixZone PosixZone::parse(const char *&pos, const char *end)
{
static const char offsetChars[] = "0123456789:";
- QPair<QString, int> result = qMakePair(QString(), INT_MIN);
const char *nameBegin = pos;
const char *nameEnd;
@@ -480,7 +498,7 @@ static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const c
pos = nameEnd;
}
if (nameEnd - nameBegin < 3)
- return result; // name must be at least 3 characters long
+ return invalid(); // name must be at least 3 characters long
// zone offset, form [+-]hh:mm:ss
const char *zoneBegin = pos;
@@ -493,11 +511,10 @@ static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const c
++zoneEnd;
}
- result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
- if (zoneEnd > zoneBegin)
- result.second = parsePosixOffset(zoneBegin, zoneEnd);
+ QString name = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
+ const int offset = zoneEnd > zoneBegin ? parsePosixOffset(zoneBegin, zoneEnd) : InvalidOffset;
pos = zoneEnd;
- return result;
+ return {std::move(name), offset};
}
static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,
@@ -517,19 +534,19 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
QList<QByteArray> parts = posixRule.split(',');
- QPair<QString, int> stdZone, dstZone;
+ PosixZone stdZone, dstZone;
{
const QByteArray &zoneinfo = parts.at(0);
const char *begin = zoneinfo.constBegin();
- stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
- if (stdZone.second == INT_MIN) {
- stdZone.second = 0; // reset to UTC if we failed to parse
+ stdZone = PosixZone::parse(begin, zoneinfo.constEnd());
+ if (!stdZone.hasValidOffset()) {
+ stdZone.offset = 0; // reset to UTC if we failed to parse
} else if (begin < zoneinfo.constEnd()) {
- dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
- if (dstZone.second == INT_MIN) {
+ dstZone = PosixZone::parse(begin, zoneinfo.constEnd());
+ if (!dstZone.hasValidOffset()) {
// if the dst offset isn't provided, it is 1 hour ahead of the standard offset
- dstZone.second = stdZone.second + (60 * 60);
+ dstZone.offset = stdZone.offset + (60 * 60);
}
}
}
@@ -538,10 +555,10 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
if (parts.count() == 1) {
QTimeZonePrivate::Data data;
data.atMSecsSinceEpoch = lastTranMSecs;
- data.offsetFromUtc = stdZone.second;
- data.standardTimeOffset = stdZone.second;
+ data.offsetFromUtc = stdZone.offset;
+ data.standardTimeOffset = stdZone.offset;
data.daylightTimeOffset = 0;
- data.abbreviation = stdZone.first;
+ data.abbreviation = stdZone.name;
result << data;
return result;
}
@@ -568,18 +585,18 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
for (int year = startYear; year <= endYear; ++year) {
QTimeZonePrivate::Data dstData;
QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC);
- dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000);
- dstData.offsetFromUtc = dstZone.second;
- dstData.standardTimeOffset = stdZone.second;
- dstData.daylightTimeOffset = dstZone.second - stdZone.second;
- dstData.abbreviation = dstZone.first;
+ dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.offset * 1000);
+ dstData.offsetFromUtc = dstZone.offset;
+ dstData.standardTimeOffset = stdZone.offset;
+ dstData.daylightTimeOffset = dstZone.offset - stdZone.offset;
+ dstData.abbreviation = dstZone.name;
QTimeZonePrivate::Data stdData;
QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC);
- stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000);
- stdData.offsetFromUtc = stdZone.second;
- stdData.standardTimeOffset = stdZone.second;
+ stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.offset * 1000);
+ stdData.offsetFromUtc = stdZone.offset;
+ stdData.standardTimeOffset = stdZone.offset;
stdData.daylightTimeOffset = 0;
- stdData.abbreviation = stdZone.first;
+ stdData.abbreviation = stdZone.name;
// Part of the high year will overflow
if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) {
if (dstData.atMSecsSinceEpoch > 0) {
@@ -598,37 +615,21 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// Create the system default time zone
QTzTimeZonePrivate::QTzTimeZonePrivate()
-#if QT_CONFIG(icu)
- : m_icu(0)
-#endif
{
init(systemTimeZoneId());
}
// Create a named time zone
QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId)
-#if QT_CONFIG(icu)
- : m_icu(0)
-#endif
{
init(ianaId);
}
-QTzTimeZonePrivate::QTzTimeZonePrivate(const QTzTimeZonePrivate &other)
- : QTimeZonePrivate(other), m_tranTimes(other.m_tranTimes),
- m_tranRules(other.m_tranRules), m_abbreviations(other.m_abbreviations),
-#if QT_CONFIG(icu)
- m_icu(other.m_icu),
-#endif
- m_posixRule(other.m_posixRule)
-{
-}
-
QTzTimeZonePrivate::~QTzTimeZonePrivate()
{
}
-QTimeZonePrivate *QTzTimeZonePrivate::clone()
+QTzTimeZonePrivate *QTzTimeZonePrivate::clone() const
{
return new QTzTimeZonePrivate(*this);
}
@@ -725,19 +726,61 @@ void QTzTimeZonePrivate::init(const QByteArray &ianaId)
}
}
- // Now for each transition time calculate our rule and save them
- m_tranTimes.reserve(tranList.count());
- for (const QTzTransition &tz_tran : qAsConst(tranList)) {
+ // Now for each transition time calculate and store our rule:
+ const int tranCount = tranList.count();;
+ m_tranTimes.reserve(tranCount);
+ // The DST offset when in effect: usually stable, usually an hour:
+ int lastDstOff = 3600;
+ for (int i = 0; i < tranCount; i++) {
+ const QTzTransition &tz_tran = tranList.at(i);
QTzTransitionTime tran;
QTzTransitionRule rule;
const QTzType tz_type = typeList.at(tz_tran.tz_typeind);
// Calculate the associated Rule
- if (!tz_type.tz_isdst)
+ if (!tz_type.tz_isdst) {
utcOffset = tz_type.tz_gmtoff;
+ } else if (Q_UNLIKELY(tz_type.tz_gmtoff != utcOffset + lastDstOff)) {
+ /*
+ This might be a genuine change in DST offset, but could also be
+ DST starting at the same time as the standard offset changed. See
+ if DST's end gives a more plausible utcOffset (i.e. one closer to
+ the last we saw, or a simple whole hour):
+ */
+ // Standard offset inferred from net offset and expected DST offset:
+ const int inferStd = tz_type.tz_gmtoff - lastDstOff; // != utcOffset
+ for (int j = i + 1; j < tranCount; j++) {
+ const QTzType new_type = typeList.at(tranList.at(j).tz_typeind);
+ if (!new_type.tz_isdst) {
+ const int newUtc = new_type.tz_gmtoff;
+ if (newUtc == utcOffset) {
+ // DST-end can't help us, avoid lots of messy checks.
+ // else: See if the end matches the familiar DST offset:
+ } else if (newUtc == inferStd) {
+ utcOffset = newUtc;
+ // else: let either end shift us to one hour as DST offset:
+ } else if (tz_type.tz_gmtoff - 3600 == utcOffset) {
+ // Start does it
+ } else if (tz_type.tz_gmtoff - 3600 == newUtc) {
+ utcOffset = newUtc; // End does it
+ // else: prefer whichever end gives DST offset closer to
+ // last, but consider any offset > 0 "closer" than any <= 0:
+ } else if (newUtc < tz_type.tz_gmtoff
+ ? (utcOffset >= tz_type.tz_gmtoff
+ || qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))
+ : (utcOffset >= tz_type.tz_gmtoff
+ && qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))) {
+ utcOffset = newUtc;
+ }
+ break;
+ }
+ }
+ lastDstOff = tz_type.tz_gmtoff - utcOffset;
+ }
rule.stdOffset = utcOffset;
rule.dstOffset = tz_type.tz_gmtoff - utcOffset;
rule.abbreviationIndex = tz_type.tz_abbrind;
+
// If the rule already exist then use that, otherwise add it
int ruleIndex = m_tranRules.indexOf(rule);
if (ruleIndex == -1) {
diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp
index 4febeda537..f963e10333 100644
--- a/src/corelib/tools/qtimezoneprivate_win.cpp
+++ b/src/corelib/tools/qtimezoneprivate_win.cpp
@@ -299,7 +299,7 @@ static QByteArray windowsSystemZoneId()
id = readRegistryString(key, L"TimeZoneKeyName");
RegCloseKey(key);
if (!id.isEmpty())
- return id.toUtf8();
+ return std::move(id).toUtf8();
}
// On XP we have to iterate over the zones until we find a match on
@@ -415,7 +415,7 @@ QWinTimeZonePrivate::~QWinTimeZonePrivate()
{
}
-QTimeZonePrivate *QWinTimeZonePrivate::clone()
+QWinTimeZonePrivate *QWinTimeZonePrivate::clone() const
{
return new QWinTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 8b9df7c12b..d99eebd4b9 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -165,6 +165,16 @@ public:
}
}
+ void append(T &&t) {
+ if (s == a)
+ realloc(s, s << 1);
+ const int idx = s++;
+ if (QTypeInfo<T>::isComplex)
+ new (ptr + idx) T(std::move(t));
+ else
+ ptr[idx] = std::move(t);
+ }
+
void append(const T *buf, int size);
inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
{ append(t); return *this; }
@@ -218,6 +228,7 @@ public:
// STL compatibility:
inline bool empty() const { return isEmpty(); }
inline void push_back(const T &t) { append(t); }
+ void push_back(T &&t) { append(std::move(t)); }
inline void pop_back() { removeLast(); }
inline T &front() { return first(); }
inline const T &front() const { return first(); }
@@ -363,7 +374,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
a = Prealloc;
}
s = 0;
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
QT_TRY {
// copy all the old elements
while (s < copySize) {
@@ -456,7 +467,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
if (n != 0) {
resize(s + n);
const T copy(t);
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
T *b = ptr + offset;
T *j = ptr + s;
T *i = j - n;
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 5e53a969e8..127afcd069 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -303,6 +303,34 @@
*/
/*!
+ \fn void QVarLengthArray::append(T &&t)
+ \overload append
+ \since 5.9
+
+ \note Unlike the lvalue overload of append(), passing a reference to
+ an object that is already an element of \c *this leads to undefined
+ behavior:
+
+ \code
+ vla.append(std::move(vla[0])); // BUG: passing an object that is already in the container
+ \endcode
+*/
+
+/*!
+ \fn void QVarLengthArray::push_back(T &&t)
+ \overload push_back
+ \since 5.9
+
+ \note Unlike the lvalue overload of push_back(), passing a reference to
+ an object that is already an element of \c *this leads to undefined
+ behavior:
+
+ \code
+ vla.push_back(std::move(vla[0])); // BUG: passing an object that is already in the container
+ \endcode
+*/
+
+/*!
\fn inline void QVarLengthArray::removeLast()
\since 4.5
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index e345163c2f..57e80ae125 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -554,7 +554,7 @@ void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::Allo
T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
T *dst = x->begin();
- if (QTypeInfo<T>::isStatic || (isShared && QTypeInfo<T>::isComplex)) {
+ if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
// we can not move the data, we need to copy construct it
while (srcBegin != srcEnd) {
new (dst++) T(*srcBegin++);
@@ -599,7 +599,7 @@ void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::Allo
}
if (d != x) {
if (!d->ref.deref()) {
- if (QTypeInfo<T>::isStatic || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
+ if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
// data was copy constructed, we need to call destructors
// or if !alloc we did nothing to the old 'd'.
freeData(d);
@@ -698,7 +698,7 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
const T copy(t);
if (!isDetached() || d->size + n > int(d->alloc))
reallocData(d->size, d->size + n, QArrayData::Grow);
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
T *b = d->end();
T *i = d->end() + n;
while (i != b)
@@ -747,7 +747,7 @@ typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
detach();
abegin = d->begin() + itemsUntouched;
aend = abegin + itemsToErase;
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
iterator moveBegin = abegin + itemsToErase;
iterator moveEnd = d->end();
while (moveBegin != moveEnd) {
diff --git a/src/corelib/tools/qvsnprintf.cpp b/src/corelib/tools/qvsnprintf.cpp
index 472b1f282c..43a21771a1 100644
--- a/src/corelib/tools/qvsnprintf.cpp
+++ b/src/corelib/tools/qvsnprintf.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_VSNPRINTF
+#if !defined(QT_VSNPRINTF) || defined(Q_CLANG_QDOC)
/*!
\relates QByteArray
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 1c9b34dacd..b93ec824ed 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -125,7 +125,6 @@ else:unix {
}
else:win32 {
SOURCES += tools/qlocale_win.cpp
- winphone: LIBS_PRIVATE += -lWindowsPhoneGlobalizationUtil
winrt-*-msvc2013: LIBS += advapi32.lib
} else:integrity {
SOURCES += tools/qlocale_unix.cpp
@@ -172,7 +171,7 @@ qtConfig(timezone) {
}
qtConfig(regularexpression) {
- QMAKE_USE_PRIVATE += pcre
+ QMAKE_USE_PRIVATE += pcre2
HEADERS += tools/qregularexpression.h
SOURCES += tools/qregularexpression.cpp
diff --git a/src/corelib/xml/qxmlutils_p.h b/src/corelib/xml/qxmlutils_p.h
index d8d25e0efe..6db347b3ee 100644
--- a/src/corelib/xml/qxmlutils_p.h
+++ b/src/corelib/xml/qxmlutils_p.h
@@ -73,7 +73,7 @@ public:
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(&ncName); }
+ static inline bool isNCName(const QString &ncName) { return isNCName(QStringRef(&ncName)); }
static bool isPublicID(const QString &candidate);
private: