summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/CMakeLists.txt6
-rw-r--r--src/corelib/Qt6CoreConfigExtras.cmake.in3
-rw-r--r--src/corelib/Qt6CoreMacros.cmake28
-rw-r--r--src/corelib/configure.cmake2
-rw-r--r--src/corelib/doc/snippets/code/doc_src_containers.cpp12
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qtimer.cpp2
-rw-r--r--src/corelib/doc/src/cmake/cmake-properties.qdoc20
-rw-r--r--src/corelib/doc/src/containers.qdoc17
-rw-r--r--src/corelib/doc/src/external-resources.qdoc30
-rw-r--r--src/corelib/doc/src/includes/android-content-uri-limitations.qdocinc13
-rw-r--r--src/corelib/doc/src/io.qdoc2
-rw-r--r--src/corelib/global/qglobal.cpp5
-rw-r--r--src/corelib/global/qlogging.cpp13
-rw-r--r--src/corelib/global/qtypeinfo.h8
-rw-r--r--src/corelib/io/qabstractfileengine_p.h2
-rw-r--r--src/corelib/io/qbuffer.cpp4
-rw-r--r--src/corelib/io/qdir.cpp19
-rw-r--r--src/corelib/io/qfile.cpp11
-rw-r--r--src/corelib/io/qfiledevice.cpp5
-rw-r--r--src/corelib/io/qfileinfo.cpp22
-rw-r--r--src/corelib/io/qfsfileengine.cpp2
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp2
-rw-r--r--src/corelib/io/qresource.cpp18
-rw-r--r--src/corelib/io/qstandardpaths.cpp17
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp161
-rw-r--r--src/corelib/io/qurl.cpp14
-rw-r--r--src/corelib/kernel/qcore_mac.mm8
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp78
-rw-r--r--src/corelib/kernel/qobject.cpp33
-rw-r--r--src/corelib/kernel/qproperty.cpp8
-rw-r--r--src/corelib/platform/android/qandroidnativeinterface.cpp43
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration.cpp89
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration_p.h88
-rw-r--r--src/corelib/plugin/qpluginloader.cpp11
-rw-r--r--src/corelib/serialization/qtextstream.cpp7
-rw-r--r--src/corelib/text/qanystringview.qdoc66
-rw-r--r--src/corelib/text/qbytearray.cpp20
-rw-r--r--src/corelib/text/qlocale.cpp23
-rw-r--r--src/corelib/text/qlocale_win.cpp17
-rw-r--r--src/corelib/text/qstring.cpp7
-rw-r--r--src/corelib/text/qstring.h13
-rw-r--r--src/corelib/text/qstringconverter.cpp9
-rw-r--r--src/corelib/text/qstringconverter_p.h27
-rw-r--r--src/corelib/text/qt_attribution.json2
-rw-r--r--src/corelib/thread/qfuture_impl.h12
-rw-r--r--src/corelib/thread/qfutureinterface.cpp1
-rw-r--r--src/corelib/thread/qpromise.qdoc2
-rw-r--r--src/corelib/tools/qcontainertools_impl.h20
-rw-r--r--src/corelib/tools/qcryptographichash.cpp8
-rw-r--r--src/corelib/tools/qlist.qdoc17
-rw-r--r--src/corelib/tools/qpair.h3
-rw-r--r--src/corelib/tools/qsharedpointer.cpp49
-rw-r--r--src/corelib/tools/qsharedpointer.h8
-rw-r--r--src/corelib/tools/qtools_p.h6
-rw-r--r--src/corelib/tools/qvarlengtharray.h78
55 files changed, 880 insertions, 311 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 457bbfaeff..993242547c 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -985,6 +985,12 @@ qt_internal_extend_target(Core CONDITION ANDROID AND NOT ANDROID_EMBEDDED
platform/android/qandroidnativeinterface.cpp
)
+qt_internal_extend_target(Core CONDITION WIN32
+ SOURCES
+ platform/windows/qfactorycacheregistration_p.h
+ platform/windows/qfactorycacheregistration.cpp
+)
+
qt_internal_extend_target(Core CONDITION HAIKU AND (ANDROID_EMBEDDED OR NOT ANDROID)
SOURCES
io/qstandardpaths_haiku.cpp
diff --git a/src/corelib/Qt6CoreConfigExtras.cmake.in b/src/corelib/Qt6CoreConfigExtras.cmake.in
index bd273da0cf..4626283757 100644
--- a/src/corelib/Qt6CoreConfigExtras.cmake.in
+++ b/src/corelib/Qt6CoreConfigExtras.cmake.in
@@ -20,7 +20,8 @@ if (NOT QT_NO_CREATE_TARGETS)
set_property(TARGET @QT_CMAKE_EXPORT_NAMESPACE@::Core PROPERTY INTERFACE_COMPILE_FEATURES cxx_decltype)
endif()
-set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE" "Q_NAMESPACE_EXPORT")
+list(APPEND CMAKE_AUTOMOC_MACRO_NAMES Q_OBJECT Q_GADGET Q_NAMESPACE Q_NAMESPACE_EXPORT)
+list(REMOVE_DUPLICATES CMAKE_AUTOMOC_MACRO_NAMES)
# install layout information, following what qmake -query provides
get_filename_component(QT@PROJECT_VERSION_MAJOR@_INSTALL_PREFIX ${CMAKE_CURRENT_LIST_DIR}/../@QT_INVERSE_CONFIG_INSTALL_DIR@ ABSOLUTE)
diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake
index 141d0598c1..5e96369df0 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -2295,6 +2295,10 @@ function(qt6_add_plugin target)
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
+ if (arg_UNPARSED_ARGUMENTS)
+ message(AUTHOR_WARNING "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}. If these are source files, consider using target_sources() instead.")
+ endif()
+
# Handle the inconsistent CLASSNAME/CLASS_NAME keyword naming between commands
if(arg_CLASSNAME)
if(arg_CLASS_NAME AND NOT arg_CLASSNAME STREQUAL arg_CLASS_NAME)
@@ -2577,30 +2581,6 @@ function(_qt_internal_apply_strict_cpp target)
endif()
endfunction()
-# Wraps a tool command with a script that contains the necessary environment for the tool to run
-# correctly.
-# _qt_internal_wrap_tool_command(var <SET|APPEND> <command> [args...])
-# Arguments:
-# APPEND Selects the 'append' mode for the out_variable argument.
-# SET Selects the 'set' mode for the out_variable argument.
-function(_qt_internal_wrap_tool_command out_variable action)
- set(append FALSE)
- if(action STREQUAL "APPEND")
- set(append TRUE)
- elseif(NOT action STREQUAL "SET")
- message(FATAL_ERROR "Invalid action specified ${action}. Supported actions: SET, APPEND")
- endif()
-
- set(cmd COMMAND ${QT_TOOL_COMMAND_WRAPPER_PATH} ${ARGN})
-
- if(append)
- list(APPEND ${out_variable} ${cmd})
- else()
- set(${out_variable} ${cmd})
- endif()
- set(${out_variable} "${${out_variable}}" PARENT_SCOPE)
-endfunction()
-
# Copies properties of the dependency to the target.
# Arguments:
# PROPERTIES list of properties to copy. If not specified the following properties are copied
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index aa7c6fc386..5cb8d04409 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -723,7 +723,7 @@ qt_feature("xmlstream" PUBLIC
LABEL "XML Streaming APIs"
PURPOSE "Provides a simple streaming API for XML."
)
-qt_feature("cpp-winrt" PRIVATE
+qt_feature("cpp-winrt" PRIVATE PUBLIC
LABEL "cpp/winrt base"
PURPOSE "basic cpp/winrt language projection support"
CONDITION WIN32 AND TEST_cpp_winrt
diff --git a/src/corelib/doc/snippets/code/doc_src_containers.cpp b/src/corelib/doc/snippets/code/doc_src_containers.cpp
index 15380da378..9cb5ec556c 100644
--- a/src/corelib/doc/snippets/code/doc_src_containers.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_containers.cpp
@@ -294,9 +294,9 @@ target_compile_definitions(my_app PRIVATE QT_NO_KEYWORDS)
QString onlyLetters(const QString &in)
{
QString out;
- for (int j = 0; j < in.size(); ++j) {
- if (in[j].isLetter())
- out += in[j];
+ for (qsizetype j = 0; j < in.size(); ++j) {
+ if (in.at(j).isLetter())
+ out += in.at(j);
}
return out;
}
@@ -333,15 +333,15 @@ int j = *i; // Undefined behavior!
//! [24]
//! [25]
-QList<int> list { 1, 2, 3, 4, 4, 5 };
-QSet<int> set(list.begin(), list.end());
+QList<int> list = {1, 2, 3, 4, 4, 5};
+QSet<int> set(list.cbegin(), list.cend());
/*
Will generate a QSet containing 1, 2, 3, 4, 5.
*/
//! [25]
//! [26]
-QList<int> list { 2, 3, 1 };
+QList<int> list = {2, 3, 1};
std::sort(list.begin(), list.end());
/*
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qtimer.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qtimer.cpp
index 548e32dc5d..ed84a7e372 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qtimer.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qtimer.cpp
@@ -55,7 +55,7 @@
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
- QTimer::singleShot(600000, &app, SLOT(quit()));
+ QTimer::singleShot(600000, &app, QCoreApplication::quit);
...
return app.exec();
}
diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc
index 7234f783d3..e6b74caabb 100644
--- a/src/corelib/doc/src/cmake/cmake-properties.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc
@@ -191,6 +191,26 @@ Specifies the target Android API level for the target.
*/
/*!
+\page cmake-target-property-qt-android-sdk-build-tools-revision.html
+\ingroup cmake-properties-qtcore
+\ingroup cmake-target-properties-qtcore
+
+\title QT_ANDROID_SDK_BUILD_TOOLS_REVISION
+\target cmake-target-property-QT_ANDROID_SDK_BUILD_TOOLS_REVISION
+
+\summary {Revision of Android build tools to use.}
+
+\cmakepropertysince 6.0
+\preliminarycmakeproperty
+\cmakepropertyandroidonly
+
+Specifies the Android SDK build tools revision to use. If this is not set then
+CMake will attempt to use the latest installed version.
+
+\sa{qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}
+*/
+
+/*!
\page cmake-target-property-QT_ANDROID_VERSION_CODE.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc
index 93ba5b456d..3cf1871fb2 100644
--- a/src/corelib/doc/src/containers.qdoc
+++ b/src/corelib/doc/src/containers.qdoc
@@ -63,7 +63,8 @@
\note Since Qt 5.14, range constructors are available for most of the
container classes. QMultiMap is a notable exception. Their use is
- encouraged in place of the various from/to methods. For example:
+ encouraged to replace of the various deprecated from/to methods of Qt 5.
+ For example:
\snippet code/doc_src_containers.cpp 25
@@ -309,12 +310,10 @@
In the code snippets so far, we used the unary \c * operator to
retrieve the item (of type QString) stored at a certain iterator
- position, and we then called QString::toLower() on it. Most C++
- compilers also allow us to write \c{i->toLower()}, but some
- don't.
+ position, and we then called QString::toLower() on it.
- For read-only access, you can use const_iterator, \l{QList::constBegin}{constBegin()},
- and \l{QList::constEnd()}{constEnd()}. For example:
+ For read-only access, you can use const_iterator, \l{QList::cbegin}{cbegin()},
+ and \l{QList::cend()}{cend()}. For example:
\snippet code/doc_src_containers.cpp 12
@@ -430,7 +429,7 @@
\li Similar to std::queue<T>, inherits from \l{QList}.
\row \li \l{QSet}<T>
- \li Similar to std::set<T>. Internally, \l{QSet} is implemented with a
+ \li Similar to std::unordered_set<T>. Internally, \l{QSet} is implemented with a
\l{QHash}.
\row \li \l{QMap}<Key, T>
@@ -440,10 +439,10 @@
\li Similar to std::multimap<T>.
\row \li \l{QHash}<Key, T>
- \li Most similar to std::map<T>.
+ \li Most similar to std::unordered_map<T>.
\row \li \l{QMultiHash}<Key, T>
- \li Most similar to std::multimap<T>.
+ \li Most similar to std::unordered_multimap<T>.
\endtable
diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc
index 50a19a4e09..7cb84ae3af 100644
--- a/src/corelib/doc/src/external-resources.qdoc
+++ b/src/corelib/doc/src/external-resources.qdoc
@@ -105,3 +105,33 @@
\externalpage https://developer.android.com/training/articles/perf-anr
\title Android: Keeping your app responsive
*/
+
+/*!
+ \externalpage https://developer.android.com/training/data-storage/shared/documents-files
+ \title Android: Access documents and other files from shared storage
+*/
+
+/*!
+ \externalpage https://developer.android.com/reference/androidx/documentfile/provider/DocumentFile#getParentFile()
+ \title Android: DocumentFile.getParentFile()
+*/
+
+/*!
+ \externalpage https://developer.android.com/guide/topics/providers/content-provider-basics#ContentURIs
+ \title Android: Content URIs
+*/
+
+/*!
+ \externalpage https://developer.android.com/training/data-storage#scoped-storage
+ \title Android: Scoped storage
+*/
+
+/*!
+ \externalpage https://developer.android.com/training/data-storage/use-cases
+ \title Android: storage best practices
+*/
+
+/*!
+ \externalpage https://developer.android.com/reference/android/provider/MediaStore
+ \title Android: MediaStore
+*/
diff --git a/src/corelib/doc/src/includes/android-content-uri-limitations.qdocinc b/src/corelib/doc/src/includes/android-content-uri-limitations.qdocinc
new file mode 100644
index 0000000000..f08086407e
--- /dev/null
+++ b/src/corelib/doc/src/includes/android-content-uri-limitations.qdocinc
@@ -0,0 +1,13 @@
+On Android, some limitations apply when dealing with
+\l {Android: Content URIs}{content URIs}:
+\list
+ \li Access permissions might be needed by prompting the user through the
+ \l QFileDialog which implements
+ \l {Access documents and other files from shared storage}{Android's native file picker}.
+ \li Aim to follow the \l {Android: Scoped storage}{Scoped storage} guidelines,
+ such as using app specific directories instead of other public external directories.
+ For more information, also see
+ \l {Android: storage best practices}{storage best practices}.
+ \li Due to the design of Qt APIs (e.g. QFile), it's not possible to fully
+ integrate the latter APIs with Android's \l {Android: MediaStore}{MediaStore} APIs.
+\endlist
diff --git a/src/corelib/doc/src/io.qdoc b/src/corelib/doc/src/io.qdoc
index a1bbc623a1..6315a069aa 100644
--- a/src/corelib/doc/src/io.qdoc
+++ b/src/corelib/doc/src/io.qdoc
@@ -34,7 +34,7 @@
network handling.
These \l{Qt Core} classes are used to handle input and output to and from
- external devices, processes, files etc. as well as manipulating files and
+ external devices, processes, files etc., as well as manipulating files and
directories.
*/
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 384310d9c9..100410b96d 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -3822,8 +3822,9 @@ bool qunsetenv(const char *varName)
Replaces the value of \a obj with \a newValue and returns the old value of \a obj.
This is Qt's implementation of std::exchange(). It differs from std::exchange()
- only in that it is \c constexpr already in C++14, and available on all supported
- compilers.
+ only in that it is \c constexpr already before C++20.
+
+ We strongly advise to use std::exchange() when you don't need the C++20 variant.
Here is how to use qExchange() to implement move constructors:
\code
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index d5c448094f..564acae2a6 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -932,6 +932,12 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
// Don't know how to parse this function name
return info;
}
+ if (info.indexOf('>', pos) != -1
+ || info.indexOf(':', pos) != -1) {
+ // that wasn't the function argument list.
+ pos = info.size();
+ break;
+ }
// find the beginning of the argument list
--pos;
@@ -1251,11 +1257,8 @@ void QMessagePattern::setPattern(const QString &pattern)
.arg(lexeme);
}
} else {
- char *literal = new char[lexeme.size() + 1];
- strncpy(literal, lexeme.toLatin1().constData(), lexeme.size());
- literal[lexeme.size()] = '\0';
- literalsVar.emplace_back(literal);
- tokens[i] = literal;
+ using UP = std::unique_ptr<char[]>;
+ tokens[i] = literalsVar.emplace_back(UP(qstrdup(lexeme.toLatin1().constData()))).get();
}
}
if (nestedIfError)
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index 7759eff370..ccc765009f 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -117,6 +117,12 @@ public:
static constexpr bool isIntegral = false;
};
+// QTypeInfo for std::pair:
+// std::pair is spec'ed to be struct { T1 first; T2 second; }, so, unlike tuple<>,
+// we _can_ specialize QTypeInfo for pair<>:
+template <class T1, class T2>
+class QTypeInfo<std::pair<T1, T2>> : public QTypeInfoMerger<std::pair<T1, T2>, T1, T2> {};
+
#define Q_DECLARE_MOVABLE_CONTAINER(CONTAINER) \
template <typename ...T> \
class QTypeInfo<CONTAINER<T...>> \
@@ -165,7 +171,7 @@ public: \
enum { \
isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0) && !std::is_trivial_v<TYPE>, \
isRelocatable = !isComplex || ((FLAGS) & Q_RELOCATABLE_TYPE) || qIsRelocatable<TYPE>, \
- isPointer = false, \
+ isPointer = std::is_pointer_v< TYPE >, \
isIntegral = std::is_integral< TYPE >::value, \
}; \
}
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
index bed4aa56d9..1322df1f68 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -238,7 +238,7 @@ public:
virtual QString currentFileName() const = 0;
virtual QFileInfo currentFileInfo() const;
- QString currentFilePath() const;
+ virtual QString currentFilePath() const;
protected:
enum EntryInfoType {
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index 48150bdea3..a0b8fd8000 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -319,6 +319,10 @@ void QBuffer::setData(const QByteArray &data)
/*!
\reimp
+
+ Unlike QFile, opening a QBuffer QIODevice::WriteOnly does not truncate it.
+ However, pos() is set to 0. Use QIODevice::Append or QIODevice::Truncate to
+ change either behavior.
*/
bool QBuffer::open(OpenMode flags)
{
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 01340828c2..e2a410c64b 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -536,6 +536,10 @@ inline void QDirPrivate::initFileEngine()
\snippet qdir-listfiles/main.cpp 0
+ \section1 Platform Specific Issues
+
+ \include android-content-uri-limitations.qdocinc
+
\sa QFileInfo, QFile, QFileDialog, QCoreApplication::applicationDirPath(), {Find Files Example}
*/
@@ -655,8 +659,12 @@ QString QDir::path() const
QString QDir::absolutePath() const
{
const QDirPrivate* d = d_ptr.constData();
- d->resolveAbsoluteEntry();
- return d->absoluteDirEntry.filePath();
+ if (!d->fileEngine) {
+ d->resolveAbsoluteEntry();
+ return d->absoluteDirEntry.filePath();
+ }
+
+ return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
}
/*!
@@ -699,7 +707,9 @@ QString QDir::canonicalPath() const
QString QDir::dirName() const
{
const QDirPrivate* d = d_ptr.constData();
- return d->dirEntry.fileName();
+ if (!d_ptr->fileEngine)
+ return d->dirEntry.fileName();
+ return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
}
@@ -1016,6 +1026,9 @@ bool QDir::cd(const QString &dirName)
otherwise returns \c false. Note that the logical cdUp() operation is
not performed if the new directory does not exist.
+ \note On Android, this is not supported for content URIs. For more information,
+ see \l {Android: DocumentFile.getParentFile()}{DocumentFile.getParentFile()}.
+
\sa cd(), isReadable(), exists(), path()
*/
bool QDir::cdUp()
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index e031e9c091..0bc206cbe8 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -226,6 +226,8 @@ QAbstractFileEngine *QFilePrivate::engine() const
function mostly useless for NTFS volumes. It may still be of use for USB
sticks that use VFAT file systems. POSIX ACLs are not manipulated, either.
+ \include android-content-uri-limitations.qdocinc
+
\sa QTextStream, QDataStream, QFileInfo, QDir, {The Qt Resource System}
*/
@@ -759,6 +761,9 @@ QFile::link(const QString &fileName, const QString &linkName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa setFileName()
*/
@@ -867,6 +872,9 @@ QFile::copy(const QString &newName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa rename()
*/
@@ -887,6 +895,9 @@ QFile::copy(const QString &fileName, const QString &newName)
\note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite}
mode, if the relevant file does not already exist, this function
will try to create a new file before opening it.
+ On Android, it's expected to have access permission to the parent
+ of the file name, otherwise, it won't be possible to create this
+ non-existing file.
\sa QIODevice::OpenMode, setFileName()
*/
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index ff8de7c0bb..4b73060025 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -145,6 +145,11 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
decrementing \c qt_ntfs_permission_lookup by 1.
\snippet ntfsp.cpp 1
+
+ \note Since this is a non-atomic global variable, it is only safe
+ to increment or decrement \c qt_ntfs_permission_lookup before any
+ threads other than the main thread have started or after every thread
+ other than the main thread has ended.
*/
//************* QFileDevice
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 326dc01577..fab5ae91e7 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -297,6 +297,11 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
\snippet ntfsp.cpp 1
+ \note Since this is a non-atomic global variable, it is only safe
+ to increment or decrement \c qt_ntfs_permission_lookup before any
+ threads other than the main thread have started or after every thread
+ other than the main thread has ended.
+
\section1 Performance Issues
Some of QFileInfo's functions query the file system, but for
@@ -317,6 +322,10 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
If you want to make sure that all information is read from the
file system, use stat().
+ \section1 Platform Specific Issues
+
+ \include android-content-uri-limitations.qdocinc
+
\sa QDir, QFile
*/
@@ -772,7 +781,9 @@ QString QFileInfo::fileName() const
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return QLatin1String("");
- return d->fileEntry.fileName();
+ if (!d->fileEngine)
+ return d->fileEntry.fileName();
+ return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
}
/*!
@@ -816,7 +827,9 @@ QString QFileInfo::baseName() const
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return QLatin1String("");
- return d->fileEntry.baseName();
+ if (!d->fileEngine)
+ return d->fileEntry.baseName();
+ return QFileSystemEntry(d->fileEngine->fileName(QAbstractFileEngine::BaseName)).baseName();
}
/*!
@@ -835,7 +848,10 @@ QString QFileInfo::completeBaseName() const
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return QLatin1String("");
- return d->fileEntry.completeBaseName();
+ if (!d->fileEngine)
+ return d->fileEntry.completeBaseName();
+ const QString fileEngineBaseName = d->fileEngine->fileName(QAbstractFileEngine::BaseName);
+ return QFileSystemEntry(fileEngineBaseName).completeBaseName();
}
/*!
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 394f21bd6d..4960bd6270 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -361,7 +361,7 @@ bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
// Seek to the end when in Append mode.
if (openMode & QFile::Append) {
- int ret;
+ QT_OFF_T ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index 33d1047925..afee63b968 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -141,7 +141,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
// Seek to the end when in Append mode.
if (flags & QFile::Append) {
- int ret;
+ QT_OFF_T ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index a1b818da8b..684d362251 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -201,7 +201,6 @@ struct QResourceGlobalData
{
QRecursiveMutex resourceMutex;
ResourceList resourceList;
- QStringList resourceSearchPaths;
};
Q_GLOBAL_STATIC(QResourceGlobalData, resourceGlobalData)
@@ -211,9 +210,6 @@ static inline QRecursiveMutex &resourceMutex()
static inline ResourceList *resourceList()
{ return &resourceGlobalData->resourceList; }
-static inline QStringList *resourceSearchPaths()
-{ return &resourceGlobalData->resourceSearchPaths; }
-
/*!
\class QResource
\inmodule QtCore
@@ -394,16 +390,10 @@ void QResourcePrivate::ensureInitialized() const
if (path.startsWith(QLatin1Char('/'))) {
that->load(path.toString());
} else {
- const auto locker = qt_scoped_lock(resourceMutex());
- QStringList searchPaths = *resourceSearchPaths();
- searchPaths << QLatin1String("");
- for (int i = 0; i < searchPaths.size(); ++i) {
- const QString searchPath(searchPaths.at(i) + QLatin1Char('/') + path);
- if (that->load(searchPath)) {
- that->absoluteFilePath = QLatin1Char(':') + searchPath;
- break;
- }
- }
+ // Should we search QDir::searchPath() before falling back to root ?
+ const QString searchPath(u'/' + path);
+ if (that->load(searchPath))
+ that->absoluteFilePath = u':' + searchPath;
}
}
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index 1984316a4e..33b0545ffe 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -267,7 +267,7 @@ QT_BEGIN_NAMESPACE
\li "<APPROOT>/files"
\li "<APPROOT>/Documents/Desktop"
\row \li DocumentsLocation
- \li "<USER>/Documents", "<USER>/<APPNAME>/Documents"
+ \li "<USER>/Documents" [*], "<USER>/<APPNAME>/Documents"
\li "<APPROOT>/Documents"
\row \li FontsLocation
\li "/system/fonts" (not writable)
@@ -276,13 +276,13 @@ QT_BEGIN_NAMESPACE
\li not supported (directory not readable)
\li not supported
\row \li MusicLocation
- \li "<USER>/Music", "<USER>/<APPNAME>/Music"
+ \li "<USER>/Music" [*], "<USER>/<APPNAME>/Music"
\li "<APPROOT>/Documents/Music"
\row \li MoviesLocation
- \li "<USER>/Movies", "<USER>/<APPNAME>/Movies"
+ \li "<USER>/Movies" [*], "<USER>/<APPNAME>/Movies"
\li "<APPROOT>/Documents/Movies"
\row \li PicturesLocation
- \li "<USER>/Pictures", "<USER>/<APPNAME>/Pictures"
+ \li "<USER>/Pictures" [*], "<USER>/<APPNAME>/Pictures"
\li "<APPROOT>/Documents/Pictures", "assets-library://"
\row \li TempLocation
\li "<APPROOT>/cache"
@@ -297,7 +297,7 @@ QT_BEGIN_NAMESPACE
\li "<APPROOT>/cache", "<USER>/<APPNAME>/cache"
\li "<APPROOT>/Library/Caches"
\row \li GenericDataLocation
- \li "<USER>"
+ \li "<USER>" [*] or "<USER>/<APPNAME>/files"
\li "<APPROOT>/Library/Application Support"
\row \li RuntimeLocation
\li "<APPROOT>/cache"
@@ -309,7 +309,7 @@ QT_BEGIN_NAMESPACE
\li "<APPROOT>/files/settings" (there is no shared settings)
\li "<APPROOT>/Library/Preferences"
\row \li DownloadLocation
- \li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads"
+ \li "<USER>/Downloads" [*], "<USER>/<APPNAME>/Downloads"
\li "<APPROOT>/Documents/Downloads"
\row \li GenericCacheLocation
\li "<APPROOT>/cache" (there is no shared cache)
@@ -339,6 +339,11 @@ QT_BEGIN_NAMESPACE
\note On Android, reading/writing to GenericDataLocation needs the READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE permission granted.
+ \note [*] On Android 11 and above, public directories are no longer directly accessible
+ in scoped storage mode. Thus, paths of the form \c "<USER>/DirName" are not returned.
+ Instead, you can use \l QFileDialog which uses the Storage Access Framework (SAF)
+ to access such directories.
+
\note On iOS, if you do pass \c {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()}
as argument to \l{QFileDialog::setDirectory()},
a native image picker dialog will be used for accessing the user's photo album.
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index d5ece85818..2ff47d74d0 100644
--- a/src/corelib/io/qstandardpaths_android.cpp
+++ b/src/corelib/io/qstandardpaths_android.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -70,6 +70,51 @@ static inline QString getAbsolutePath(const QJniObject &file)
}
/*
+ * The root of the external storage
+ *
+ */
+static QString getExternalStorageDirectory()
+{
+ QString &path = (*androidDirCache)[QStringLiteral("EXT_ROOT")];
+ if (!path.isEmpty())
+ return path;
+
+ QJniObject file = QJniObject::callStaticObjectMethod("android/os/Environment",
+ "getExternalStorageDirectory",
+ "()Ljava/io/File;");
+ if (!file.isValid())
+ return QString();
+
+ return (path = getAbsolutePath(file));
+}
+
+/*
+ * Locations where applications can place user files shared by all apps (public).
+ * E.g., /storage/Music
+ */
+static QString getExternalStoragePublicDirectory(const char *directoryField)
+{
+ QString &path = (*androidDirCache)[QLatin1String(directoryField)];
+ if (!path.isEmpty())
+ return path;
+
+ QJniObject dirField = QJniObject::getStaticObjectField("android/os/Environment",
+ directoryField,
+ "Ljava/lang/String;");
+ if (!dirField.isValid())
+ return QString();
+
+ QJniObject file = QJniObject::callStaticObjectMethod("android/os/Environment",
+ "getExternalStoragePublicDirectory",
+ "(Ljava/lang/String;)Ljava/io/File;",
+ dirField.object());
+ if (!file.isValid())
+ return QString();
+
+ return (path = getAbsolutePath(file));
+}
+
+/*
* Locations where applications can place persistent files it owns.
* E.g., /storage/org.app/Music
*/
@@ -168,25 +213,35 @@ static QString getFilesDir()
return (path = getAbsolutePath(file));
}
+static QString getSdkBasedExternalDir(const char *directoryField = nullptr)
+{
+ return (QNativeInterface::QAndroidApplication::sdkVersion() >= 30)
+ ? getExternalFilesDir(directoryField)
+ : getExternalStoragePublicDirectory(directoryField);
+}
+
QString QStandardPaths::writableLocation(StandardLocation type)
{
switch (type) {
case QStandardPaths::MusicLocation:
- return getExternalFilesDir("DIRECTORY_MUSIC");
+ return getSdkBasedExternalDir("DIRECTORY_MUSIC");
case QStandardPaths::MoviesLocation:
- return getExternalFilesDir("DIRECTORY_MOVIES");
+ return getSdkBasedExternalDir("DIRECTORY_MOVIES");
case QStandardPaths::PicturesLocation:
- return getExternalFilesDir("DIRECTORY_PICTURES");
+ return getSdkBasedExternalDir("DIRECTORY_PICTURES");
case QStandardPaths::DocumentsLocation:
- return getExternalFilesDir("DIRECTORY_DOCUMENTS");
+ return getSdkBasedExternalDir("DIRECTORY_DOCUMENTS");
case QStandardPaths::DownloadLocation:
- return getExternalFilesDir("DIRECTORY_DOWNLOADS");
+ return getSdkBasedExternalDir("DIRECTORY_DOWNLOADS");
case QStandardPaths::GenericConfigLocation:
case QStandardPaths::ConfigLocation:
case QStandardPaths::AppConfigLocation:
return getFilesDir() + testDir() + QLatin1String("/settings");
case QStandardPaths::GenericDataLocation:
- return getExternalFilesDir() + testDir();
+ {
+ return QAndroidApplication::sdkVersion() >= 30 ?
+ getExternalFilesDir() + testDir() : getExternalStorageDirectory() + testDir();
+ }
case QStandardPaths::AppDataLocation:
case QStandardPaths::AppLocalDataLocation:
return getFilesDir() + testDir();
@@ -209,59 +264,53 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QStringList QStandardPaths::standardLocations(StandardLocation type)
{
- if (type == MusicLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_MUSIC")
- << getExternalFilesDir("DIRECTORY_PODCASTS")
- << getExternalFilesDir("DIRECTORY_NOTIFICATIONS")
- << getExternalFilesDir("DIRECTORY_ALARMS");
- }
-
- if (type == MoviesLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_MOVIES");
- }
-
- if (type == PicturesLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_PICTURES");
- }
+ QStringList locations;
- if (type == DocumentsLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_DOCUMENTS");
- }
-
- if (type == DownloadLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_DOWNLOADS");
- }
-
- if (type == AppDataLocation || type == AppLocalDataLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir();
- }
-
- if (type == CacheLocation) {
- return QStringList() << writableLocation(type)
- << getExternalCacheDir();
- }
-
- if (type == FontsLocation) {
+ if (type == MusicLocation) {
+ locations << getExternalFilesDir("DIRECTORY_MUSIC");
+ // Place the public dirs before the app own dirs
+ if (QNativeInterface::QAndroidApplication::sdkVersion() < 30) {
+ locations << getExternalStoragePublicDirectory("DIRECTORY_PODCASTS")
+ << getExternalStoragePublicDirectory("DIRECTORY_NOTIFICATIONS")
+ << getExternalStoragePublicDirectory("DIRECTORY_ALARMS");
+ }
+ locations << getExternalFilesDir("DIRECTORY_PODCASTS")
+ << getExternalFilesDir("DIRECTORY_NOTIFICATIONS")
+ << getExternalFilesDir("DIRECTORY_ALARMS");
+ } else if (type == MoviesLocation) {
+ locations << getExternalFilesDir("DIRECTORY_MOVIES");
+ } else if (type == PicturesLocation) {
+ locations << getExternalFilesDir("DIRECTORY_PICTURES");
+ } else if (type == DocumentsLocation) {
+ locations << getExternalFilesDir("DIRECTORY_DOCUMENTS");
+ } else if (type == DownloadLocation) {
+ locations << getExternalFilesDir("DIRECTORY_DOWNLOADS");
+ } else if (type == AppDataLocation || type == AppLocalDataLocation) {
+ locations << getExternalFilesDir();
+ } else if (type == CacheLocation) {
+ locations << getExternalCacheDir();
+ } else if (type == FontsLocation) {
QString &fontLocation = (*androidDirCache)[QStringLiteral("FONT_LOCATION")];
- if (!fontLocation.isEmpty())
- return QStringList(fontLocation);
-
- const QByteArray ba = qgetenv("QT_ANDROID_FONT_LOCATION");
- if (!ba.isEmpty())
- return QStringList((fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba))));
-
- // Don't cache the fallback, as we might just have been called before
- // QT_ANDROID_FONT_LOCATION has been set.
- return QStringList(QLatin1String("/system/fonts"));
+ if (!fontLocation.isEmpty()) {
+ locations << fontLocation;
+ } else {
+ const QByteArray ba = qgetenv("QT_ANDROID_FONT_LOCATION");
+ if (!ba.isEmpty()) {
+ locations << (fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba)));
+ } else {
+ // Don't cache the fallback, as we might just have been called before
+ // QT_ANDROID_FONT_LOCATION has been set.
+ locations << QLatin1String("/system/fonts");
+ }
+ }
}
- return QStringList(writableLocation(type));
+ const QString writable = writableLocation(type);
+ if (!writable.isEmpty())
+ locations.prepend(writable);
+
+ locations.removeDuplicates();
+ return locations;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 27388ab2a4..ccf836c2a6 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -834,14 +834,16 @@ recodeFromUser(const QString &input, const ushort *actions, int from, int to)
static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
const ushort *actions)
{
- // Test ComponentFormattingOptions, ignore FormattingOptions.
- if ((options & 0xFFFF0000) == QUrl::PrettyDecoded) {
+ // The stored value is already QUrl::PrettyDecoded, so there's nothing to
+ // do if that's what the user asked for (test only
+ // ComponentFormattingOptions, ignore FormattingOptions).
+ if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
+ !qt_urlRecode(appendTo, value, options, actions))
appendTo += value;
- return;
- }
- if (!qt_urlRecode(appendTo, value, options, actions))
- appendTo += value;
+ // copy nullness, if necessary, because QString::operator+=(QStringView) doesn't
+ if (appendTo.isNull() && !value.isNull())
+ appendTo.detach();
}
inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index f0d273cfbd..bd9b17a808 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -515,6 +515,14 @@ void qt_apple_check_os_version()
const NSOperatingSystemVersion required = (NSOperatingSystemVersion){
version / 10000, version / 100 % 100, version % 100};
const NSOperatingSystemVersion current = NSProcessInfo.processInfo.operatingSystemVersion;
+
+#if defined(Q_OS_MACOS)
+ // Check for compatibility version, in which case we can't do a
+ // comparison to the deployment target, which might be e.g. 11.0
+ if (current.majorVersion == 10 && current.minorVersion >= 16)
+ return; // FIXME: Find a way to detect the real OS version
+#endif
+
if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:required]) {
NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
NSString *applicationName = plist[@"CFBundleDisplayName"];
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 6ca028f9e4..d0d11e6af5 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -588,24 +588,47 @@ QString qAppName()
void QCoreApplicationPrivate::initLocale()
{
-#if defined(Q_OS_UNIX) && !defined(QT_BOOTSTRAPPED)
+#if defined(QT_BOOTSTRAPPED)
+ // Don't try to control bootstrap library locale or encoding.
+#elif defined(Q_OS_UNIX)
static bool qt_locale_initialized = false;
if (qt_locale_initialized)
return;
qt_locale_initialized = true;
-#ifdef Q_OS_INTEGRITY
+ // By default the portable "C"/POSIX locale is selected and active.
+ // Apply the locale from the environment, via setlocale(), which will
+ // read LC_ALL, LC_<category>, and LANG, in order (for each category).
+ setlocale(LC_ALL, "");
+
+ // Next, let's ensure that LC_CTYPE is UTF-8, since QStringConverter's
+ // QLocal8Bit hard-codes this, and we need to be consistent.
+# if defined(Q_OS_INTEGRITY)
setlocale(LC_CTYPE, "UTF-8");
-#else
- // Android's Bionic didn't get nl_langinfo until NDK 15 (Android 8.0),
- // which is too new for Qt, so we just assume it's always UTF-8.
- auto nl_langinfo = [](int) { return "UTF-8"; };
-
- const char *locale = setlocale(LC_ALL, "");
- const char *codec = nl_langinfo(CODESET);
- if (Q_UNLIKELY(strcmp(codec, "UTF-8") != 0 && strcmp(codec, "utf8") != 0)) {
- QByteArray oldLocale = locale;
- QByteArray newLocale = setlocale(LC_CTYPE, nullptr);
+# elif defined(Q_OS_QNX)
+ // QNX has no nl_langinfo, so we can't check.
+ // FIXME: Shouldn't we still setlocale("UTF-8")?
+# elif defined(Q_OS_ANDROID) && __ANDROID_API__ < __ANDROID_API_O__
+ // Android 6 still lacks nl_langinfo(), so we can't check.
+ // FIXME: Shouldn't we still setlocale("UTF-8")?
+# else
+ const char *charEncoding = nl_langinfo(CODESET);
+ if (Q_UNLIKELY(qstricmp(charEncoding, "UTF-8") != 0 && qstricmp(charEncoding, "utf8") != 0)) {
+ const QByteArray oldLocale = setlocale(LC_ALL, nullptr);
+ QByteArray newLocale;
+ bool warnOnOverride = true;
+# if defined(Q_OS_DARWIN)
+ // Don't warn unless the char encoding has been changed from the
+ // default "C" encoding, or the user touched any of the locale
+ // environment variables to force the "C" char encoding.
+ warnOnOverride = qstrcmp(setlocale(LC_CTYPE, nullptr), "C") != 0
+ || getenv("LC_ALL") || getenv("LC_CTYPE") || getenv("LANG");
+
+ // No need to try language or region specific CTYPEs, as they
+ // all point back to the same generic UTF-8 CTYPE.
+ newLocale = setlocale(LC_CTYPE, "UTF-8");
+# else
+ newLocale = setlocale(LC_CTYPE, nullptr);
if (qsizetype dot = newLocale.indexOf('.'); dot != -1)
newLocale.truncate(dot); // remove encoding, if any
if (qsizetype at = newLocale.indexOf('@'); at != -1)
@@ -613,23 +636,30 @@ void QCoreApplicationPrivate::initLocale()
newLocale += ".UTF-8";
newLocale = setlocale(LC_CTYPE, newLocale);
- // if locale doesn't exist, try some fallbacks
-# ifdef Q_OS_DARWIN
- if (newLocale.isEmpty())
- newLocale = setlocale(LC_CTYPE, "UTF-8");
-# endif
+ // If that locale doesn't exist, try some fallbacks:
if (newLocale.isEmpty())
newLocale = setlocale(LC_CTYPE, "C.UTF-8");
if (newLocale.isEmpty())
newLocale = setlocale(LC_CTYPE, "C.utf8");
-
- qWarning("Detected system locale encoding (%s, locale \"%s\") is not UTF-8.\n"
- "Qt shall use a UTF-8 locale (\"%s\") instead. If this causes problems,\n"
- "reconfigure your locale. See the locale(1) manual for more information.",
- codec, oldLocale.constData(), newLocale.constData());
+# endif
+
+ if (newLocale.isEmpty()) {
+ // Failed to set a UTF-8 locale.
+ qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
+ "Qt depends on a UTF-8 locale, but has failed to switch to one.\n"
+ "If this causes problems, reconfigure your locale. See the locale(1) manual\n"
+ "for more information.", oldLocale.constData(), charEncoding);
+ } else if (warnOnOverride) {
+ // Let the user know we over-rode their configuration.
+ qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
+ "Qt depends on a UTF-8 locale, and has switched to \"%s\" instead.\n"
+ "If this causes problems, reconfigure your locale. See the locale(1) manual\n"
+ "for more information.",
+ oldLocale.constData(), charEncoding, newLocale.constData());
+ }
}
-#endif
-#endif
+# endif // Platform choice
+#endif // Unix
}
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 1de6070388..0135b7a1b1 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2620,13 +2620,15 @@ int QObject::receivers(const char *signal) const
\snippet code/src_corelib_kernel_qobject.cpp 49
- As the code snippet above illustrates, you can use this function
- to avoid emitting a signal that nobody listens to.
+ As the code snippet above illustrates, you can use this function to avoid
+ expensive initialization or emitting a signal that nobody listens to.
+ However, in a multithreaded application, connections might change after
+ this function returns and before the signal gets emitted.
\warning This function violates the object-oriented principle of
- modularity. However, it might be useful when you need to perform
- expensive initialization only if something is connected to a
- signal.
+ modularity. In particular, this function must not be called from an
+ override of connectNotify() or disconnectNotify(), as those might get
+ called from any thread.
*/
bool QObject::isSignalConnected(const QMetaMethod &signal) const
{
@@ -3308,8 +3310,13 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
signal.
\warning This function is called from the thread which performs the
- connection, which may be a different thread from the thread in
- which this object lives.
+ connection, which may be a different thread from the thread in which
+ this object lives. This function may also be called with a QObject internal
+ mutex locked. It is therefore not allowed to re-enter any QObject
+ functions, including isSignalConnected(), from your reimplementation. If
+ you lock a mutex in your reimplementation, make sure that you don't call
+ QObject functions with that mutex held in other places or it will result in
+ a deadlock.
\sa connect(), disconnectNotify()
*/
@@ -3338,12 +3345,12 @@ void QObject::connectNotify(const QMetaMethod &signal)
expensive resources.
\warning This function is called from the thread which performs the
- disconnection, which may be a different thread from the thread in
- which this object lives. This function may also be called with a QObject
- internal mutex locked. It is therefore not allowed to re-enter any
- of any QObject functions from your reimplementation and if you lock
- a mutex in your reimplementation, make sure that you don't call QObject
- functions with that mutex held in other places or it will result in
+ disconnection, which may be a different thread from the thread in which
+ this object lives. This function may also be called with a QObject internal
+ mutex locked. It is therefore not allowed to re-enter any QObject
+ functions, including isSignalConnected(), from your reimplementation. If
+ you lock a mutex in your reimplementation, make sure that you don't call
+ QObject functions with that mutex held in other places or it will result in
a deadlock.
\sa disconnect(), connectNotify()
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index a6cdb06326..c02ae65248 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -154,7 +154,7 @@ struct QPropertyDelayedNotifications
Change notifications are sent later with notify (following the logic of separating
binding updates and notifications used in non-deferred updates).
*/
- void evaluateBindings(int index, QBindingStatus *status) {
+ void evaluateBindings(qsizetype index, QBindingStatus *status) {
auto *delayed = delayedProperties + index;
auto *bindingData = delayed->originalBindingData;
if (!bindingData)
@@ -182,7 +182,7 @@ struct QPropertyDelayedNotifications
\li sends any pending notifications.
\endlist
*/
- void notify(int index) {
+ void notify(qsizetype index) {
auto *delayed = delayedProperties + index;
auto *bindingData = delayed->originalBindingData;
if (!bindingData)
@@ -252,14 +252,14 @@ void Qt::endPropertyUpdateGroup()
// update all delayed properties
auto start = data;
while (data) {
- for (int i = 0; i < data->used; ++i)
+ for (qsizetype i = 0; i < data->used; ++i)
data->evaluateBindings(i, status);
data = data->next;
}
// notify all delayed properties
data = start;
while (data) {
- for (int i = 0; i < data->used; ++i)
+ for (qsizetype i = 0; i < data->used; ++i)
data->notify(i);
auto *next = data->next;
delete data;
diff --git a/src/corelib/platform/android/qandroidnativeinterface.cpp b/src/corelib/platform/android/qandroidnativeinterface.cpp
index b8e2cbb424..b3a3c105fc 100644
--- a/src/corelib/platform/android/qandroidnativeinterface.cpp
+++ b/src/corelib/platform/android/qandroidnativeinterface.cpp
@@ -43,8 +43,10 @@
#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/qjniobject.h>
#if QT_CONFIG(future) && !defined(QT_NO_QOBJECT)
-#include <QtConcurrent/QtConcurrent>
+#include <QtCore/qfuture.h>
+#include <QtCore/qfuturewatcher.h>
#include <QtCore/qpromise.h>
+#include <QtCore/qthreadpool.h>
#include <deque>
#endif
@@ -53,8 +55,12 @@ QT_BEGIN_NAMESPACE
#if QT_CONFIG(future) && !defined(QT_NO_QOBJECT)
static const char qtNativeClassName[] = "org/qtproject/qt/android/QtNative";
-typedef std::pair<std::function<QVariant()>, QSharedPointer<QPromise<QVariant>>> RunnablePair;
-typedef std::deque<RunnablePair> PendingRunnables;
+struct PendingRunnable {
+ std::function<QVariant()> function;
+ QSharedPointer<QPromise<QVariant>> promise;
+};
+
+using PendingRunnables = std::deque<PendingRunnable>;
Q_GLOBAL_STATIC(PendingRunnables, g_pendingRunnables);
static QBasicMutex g_pendingRunnablesMutex;
#endif
@@ -195,8 +201,8 @@ QFuture<QVariant> QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
QFuture<QVariant> future = promise->future();
promise->start();
- (void) QtConcurrent::run([=, &future]() {
- if (!timeout.isForever()) {
+ if (!timeout.isForever()) {
+ QThreadPool::globalInstance()->start([=]() mutable {
QEventLoop loop;
QTimer::singleShot(timeout.remainingTime(), &loop, [&]() {
future.cancel();
@@ -212,12 +218,24 @@ QFuture<QVariant> QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
loop.quit();
});
watcher.setFuture(future);
+
+ // we're going to sleep, make sure we don't block
+ // QThreadPool::globalInstance():
+
+ QThreadPool::globalInstance()->releaseThread();
+ const auto sg = qScopeGuard([] {
+ QThreadPool::globalInstance()->reserveThread();
+ });
loop.exec();
- }
- });
+ });
+ }
QMutexLocker locker(&g_pendingRunnablesMutex);
- g_pendingRunnables->push_back(std::pair(runnable, promise));
+#ifdef __cpp_aggregate_paren_init
+ g_pendingRunnables->emplace_back(runnable, std::move(promise));
+#else
+ g_pendingRunnables->push_back({runnable, std::move(promise)});
+#endif
locker.unlock();
QJniObject::callStaticMethod<void>(qtNativeClassName,
@@ -235,15 +253,14 @@ static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/)
if (g_pendingRunnables->empty())
break;
- std::pair pair = std::move(g_pendingRunnables->front());
+ PendingRunnable r = std::move(g_pendingRunnables->front());
g_pendingRunnables->pop_front();
locker.unlock();
// run the runnable outside the sync block!
- auto promise = pair.second;
- if (!promise->isCanceled())
- promise->addResult(pair.first());
- promise->finish();
+ if (!r.promise->isCanceled())
+ r.promise->addResult(r.function());
+ r.promise->finish();
}
}
#endif
diff --git a/src/corelib/platform/windows/qfactorycacheregistration.cpp b/src/corelib/platform/windows/qfactorycacheregistration.cpp
new file mode 100644
index 0000000000..504ddf7e4b
--- /dev/null
+++ b/src/corelib/platform/windows/qfactorycacheregistration.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+******************************************************************************/
+
+#include "qfactorycacheregistration_p.h"
+
+#include <QtCore/QMutex>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
+
+static QBasicMutex registrationMutex;
+static detail::QWinRTFactoryCacheRegistration *firstElement;
+
+detail::QWinRTFactoryCacheRegistration::QWinRTFactoryCacheRegistration(
+ QFunctionPointer clearFunction)
+ : m_clearFunction(clearFunction)
+{
+ QMutexLocker lock(&registrationMutex);
+
+ // forward pointers
+ m_next = std::exchange(firstElement, this);
+
+ // backward pointers
+ m_prevNext = &firstElement;
+ if (m_next)
+ m_next->m_prevNext = &m_next;
+}
+
+detail::QWinRTFactoryCacheRegistration::~QWinRTFactoryCacheRegistration()
+{
+ QMutexLocker lock(&registrationMutex);
+
+ *m_prevNext = m_next;
+
+ if (m_next)
+ m_next->m_prevNext = m_prevNext;
+}
+
+void detail::QWinRTFactoryCacheRegistration::clearAllCaches()
+{
+ QMutexLocker lock(&registrationMutex);
+
+ detail::QWinRTFactoryCacheRegistration *element;
+
+ for (element = firstElement; element != nullptr; element = element->m_next) {
+ element->m_clearFunction();
+ }
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/platform/windows/qfactorycacheregistration_p.h b/src/corelib/platform/windows/qfactorycacheregistration_p.h
new file mode 100644
index 0000000000..f875d66654
--- /dev/null
+++ b/src/corelib/platform/windows/qfactorycacheregistration_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+******************************************************************************/
+
+#ifndef QFACTORYCACHEREGISTRATION_P_H
+#define QFACTORYCACHEREGISTRATION_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/qglobal.h>
+
+#if !defined(QT_BOOTSTRAPPED) && defined(Q_OS_WIN) && !defined(Q_CC_CLANG) && QT_CONFIG(cpp_winrt)
+# define QT_USE_FACTORY_CACHE_REGISTRATION
+#endif
+
+#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
+
+#include <winrt/base.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace detail {
+
+class QWinRTFactoryCacheRegistration
+{
+public:
+ Q_CORE_EXPORT explicit QWinRTFactoryCacheRegistration(QFunctionPointer clearFunction);
+ Q_CORE_EXPORT ~QWinRTFactoryCacheRegistration();
+ Q_CORE_EXPORT static void clearAllCaches();
+
+ Q_DISABLE_COPY_MOVE(QWinRTFactoryCacheRegistration)
+private:
+ QWinRTFactoryCacheRegistration **m_prevNext = nullptr;
+ QWinRTFactoryCacheRegistration *m_next = nullptr;
+ QFunctionPointer m_clearFunction;
+};
+
+inline QWinRTFactoryCacheRegistration reg([]() noexcept { winrt::clear_factory_cache(); });
+}
+
+QT_END_NAMESPACE
+
+#endif
+#endif // QFACTORYCACHEREGISTRATION_P_H
diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp
index 742c958940..fa9b125544 100644
--- a/src/corelib/plugin/qpluginloader.cpp
+++ b/src/corelib/plugin/qpluginloader.cpp
@@ -429,12 +429,11 @@ void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin plugin)
QObjectList QPluginLoader::staticInstances()
{
QObjectList instances;
- const StaticPluginList *plugins = staticPluginList();
- if (plugins) {
- const int numPlugins = plugins->size();
- instances.reserve(numPlugins);
- for (int i = 0; i < numPlugins; ++i)
- instances += plugins->at(i).instance();
+ if (staticPluginList.exists()) {
+ const StaticPluginList &plugins = *staticPluginList;
+ instances.reserve(plugins.size());
+ for (QStaticPlugin plugin : plugins)
+ instances += plugin.instance();
}
return instances;
}
diff --git a/src/corelib/serialization/qtextstream.cpp b/src/corelib/serialization/qtextstream.cpp
index 56818890c7..f73b0e0eb3 100644
--- a/src/corelib/serialization/qtextstream.cpp
+++ b/src/corelib/serialization/qtextstream.cpp
@@ -1434,7 +1434,8 @@ QTextStream::RealNumberNotation QTextStream::realNumberNotation() const
/*!
Sets the precision of real numbers to \a precision. This value
describes the number of fraction digits QTextStream should
- write when generating real numbers.
+ write when generating real numbers (FixedNotation, ScientificNotation), or
+ the maximum number of significant digits (SmartNotation).
The precision cannot be a negative value. The default value is 6.
@@ -1453,7 +1454,9 @@ void QTextStream::setRealNumberPrecision(int precision)
/*!
Returns the current real number precision, or the number of fraction
- digits QTextStream will write when generating real numbers.
+ digits QTextStream will write when generating real numbers
+ (FixedNotation, ScientificNotation), or the maximum number of significant
+ digits (SmartNotation).
\sa setRealNumberNotation(), realNumberNotation(), numberFlags(), integerBase()
*/
diff --git a/src/corelib/text/qanystringview.qdoc b/src/corelib/text/qanystringview.qdoc
index 0c8bd82613..cfbb17a8cf 100644
--- a/src/corelib/text/qanystringview.qdoc
+++ b/src/corelib/text/qanystringview.qdoc
@@ -358,6 +358,72 @@
\sa front(), {Sizes and Sub-Strings}
*/
+/*! \fn template <typename Visitor> decltype(auto) QAnyStringView::visit(Visitor &&v) const
+
+ Calls \a v with either a QUtf8StringView, QLatin1String, or QStringView, depending
+ on the encoding of the string data this string-view references.
+
+ This is how most functions taking QAnyStringView fork off into per-encoding
+ functions:
+
+ \code
+ void processImpl(QLatin1String s) { ~~~ }
+ void processImpl(QUtf8StringView s) { ~~~ }
+ void processImpl(QStringView s) { ~~~ }
+
+ void process(QAnyStringView s)
+ {
+ s.visit([](auto s) { processImpl(s); });
+ }
+ \endcode
+
+ Here, we're reusing the same name, \c s, for both the QAnyStringView
+ object, as well as the lambda's parameter. This is idiomatic code and helps
+ track the identity of the objects through visit() calls, for example in more
+ complex situations such as
+
+ \code
+ bool equal(QAnyStringView lhs, QAnyStringView rhs)
+ {
+ // assuming operator==(QAnyStringView, QAnyStringView) didn't, yet, exist:
+ return lhs.visit([rhs](auto lhs) {
+ rhs.visit([lhs](auto rhs) {
+ return lhs == rhs;
+ });
+ });
+ }
+ \endcode
+
+ visit() requires that all lambda instantiations have the same return type.
+ If they differ, you get a compile error, even if there is a common type. To
+ fix, you can use explicit return types on the lambda, or cast in the return
+ statements:
+
+ \code
+ // wrong:
+ QAnyStringView firstHalf(QAnyStringView input)
+ {
+ return input.visit([](auto input) { // ERROR: lambdas return different types
+ return input.sliced(0, input.size() / 2);
+ });
+ }
+ // correct:
+ QAnyStringView firstHalf(QAnyStringView input)
+ {
+ return input.visit([](auto input) -> QAnyStringView { // OK, explicit return type
+ return input.sliced(0, input.size() / 2);
+ });
+ }
+ // also correct:
+ QAnyStringView firstHalf(QAnyStringView input)
+ {
+ return input.visit([](auto input) {
+ return QAnyStringView(input.sliced(0, input.size() / 2)); // OK, cast to common type
+ });
+ }
+ \endcode
+*/
+
/*!
\fn QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs)
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index adf2a8de9a..3329310ab1 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -146,23 +146,29 @@ char *qstrcpy(char *dst, const char *src)
A safe \c strncpy() function.
Copies at most \a len bytes from \a src (stopping at \a len or the
- terminating '\\0' whichever comes first) into \a dst and returns a
- pointer to \a dst. Guarantees that \a dst is '\\0'-terminated. If
- \a src or \a dst is \nullptr, returns \nullptr immediately.
+ terminating '\\0' whichever comes first) into \a dst. Guarantees that \a
+ dst is '\\0'-terminated, except when \a dst is \nullptr or \a len is 0. If
+ \a src is \nullptr, returns \nullptr, otherwise returns \a dst.
This function assumes that \a dst is at least \a len characters
long.
\note If \a dst and \a src overlap, the behavior is undefined.
+ \note Unlike strncpy(), this function does \e not write '\\0' to all \a
+ len bytes of \a dst, but stops after the terminating '\\0'. In this sense,
+ it's similar to C11's strncpy_s().
+
\sa qstrcpy()
*/
char *qstrncpy(char *dst, const char *src, size_t len)
{
- if (!src || !dst)
- return nullptr;
- if (len > 0) {
+ if (dst && len > 0) {
+ if (!src) {
+ *dst = '\0';
+ return nullptr;
+ }
#ifdef Q_CC_MSVC
strncpy_s(dst, len, src, len - 1);
#else
@@ -170,7 +176,7 @@ char *qstrncpy(char *dst, const char *src, size_t len)
#endif
dst[len-1] = '\0';
}
- return dst;
+ return src ? dst : nullptr;
}
/*! \fn size_t qstrlen(const char *str)
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index c7aaa7006d..bf70778535 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -2536,21 +2536,18 @@ static char qToLower(char c)
The \a format defaults to \c{'g'}. It can be any of the following:
\table
- \header \li Format \li Meaning
- \row \li \c 'e' \li format as [-]9.9e[+|-]999
- \row \li \c 'E' \li format as [-]9.9E[+|-]999
- \row \li \c 'f' \li format as [-]9.9
- \row \li \c 'g' \li use \c 'e' or \c 'f' format, whichever is more concise
- \row \li \c 'G' \li use \c 'E' or \c 'f' format, whichever is more concise
+ \header \li Format \li Meaning \li Meaning of \a precision
+ \row \li \c 'e' \li format as [-]9.9e[+|-]999 \li number of digits \e after the decimal point
+ \row \li \c 'E' \li format as [-]9.9E[+|-]999 \li "
+ \row \li \c 'f' \li format as [-]9.9 \li "
+ \row \li \c 'g' \li use \c 'e' or \c 'f' format, whichever is more concise \li maximum number of significant digits (trailing zeroes are omitted)
+ \row \li \c 'G' \li use \c 'E' or \c 'f' format, whichever is more concise \li "
\endtable
- For the \c 'e', \c 'E', and \c 'f' formats, the \a precision represents the
- number of digits \e after the decimal point. For the \c 'g' and \c 'G'
- formats, the \a precision represents the maximum number of significant
- digits (trailing zeroes are omitted). The special \a precision value
- QLocale::FloatingPointShortest selects the shortest representation that,
- when read as a number, gets back the original floating-point value. Aside
- from that, any negative \a precision is ignored in favor of the default, 6.
+ The special \a precision value QLocale::FloatingPointShortest selects the
+ shortest representation that, when read as a number, gets back the original floating-point
+ value. Aside from that, any negative \a precision is ignored in favor of the
+ default, 6.
For the \c 'e', \c 'f' and \c 'g' formats, positive infinity is represented
as "inf", negative infinity as "-inf" and floating-point NaN (not-a-number)
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp
index 5566d44449..bd7bbd735f 100644
--- a/src/corelib/text/qlocale_win.cpp
+++ b/src/corelib/text/qlocale_win.cpp
@@ -53,6 +53,7 @@
#if QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG)
# include <winrt/base.h>
+# include <QtCore/private/qfactorycacheregistration_p.h>
// Workaround for Windows SDK bug.
// See https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/47
namespace winrt::impl
@@ -456,15 +457,17 @@ QVariant QSystemLocalePrivate::toString(QTime time, QLocale::FormatType type)
DWORD flags = 0;
// keep the same conditional as timeFormat() above
- if (type == QLocale::ShortFormat)
- flags = TIME_NOSECONDS;
+ const QString format = type == QLocale::ShortFormat
+ ? getLocaleInfo(LOCALE_SSHORTTIME).toString()
+ : QString();
+ auto formatStr = reinterpret_cast<const wchar_t *>(format.isEmpty() ? nullptr : format.utf16());
wchar_t buf[255];
- if (getTimeFormat(flags, &st, NULL, buf, 255)) {
- QString format = QString::fromWCharArray(buf);
+ if (getTimeFormat(flags, &st, formatStr, buf, int(std::size(buf)))) {
+ QString text = QString::fromWCharArray(buf);
if (substitution() == SAlways)
- format = substituteDigits(std::move(format));
- return format;
+ text = substituteDigits(std::move(text));
+ return text;
}
return {};
}
@@ -1010,6 +1013,8 @@ static const char *winLangCodeToIsoName(int code)
LCID qt_inIsoNametoLCID(const char *name)
{
+ if (!name)
+ return LOCALE_USER_DEFAULT;
// handle norwegian manually, the list above will fail
if (!strncmp(name, "nb", 2))
return 0x0414;
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index a8365e8aef..febf5bb632 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -7546,14 +7546,15 @@ QStringList QString::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensit
\fn QList<QStringView> QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
- Splits the string into substring views wherever \a sep occurs, and
+ Splits the view into substring views wherever \a sep occurs, and
returns the list of those string views.
See QString::split() for how \a sep, \a behavior and \a cs interact to form
the result.
- \note All views are valid as long as this string is. Destroying this
- string will cause all views to be dangling pointers.
+ \note All the returned views are valid as long as the data referenced by
+ this string view is valid. Destroying the data will cause all views to
+ become dangling.
\since 6.0
*/
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index f4e451fbb3..bb90e4d61a 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -471,14 +471,11 @@ public:
QChar fillChar = QLatin1Char(' ')) const;
private:
template <typename T>
- struct is_convertible_to_view_or_qstring_helper
- : std::integral_constant<bool,
- std::is_convertible<T, QString>::value ||
- std::is_convertible<T, QStringView>::value ||
- std::is_convertible<T, QLatin1String>::value> {};
- template <typename T>
- struct is_convertible_to_view_or_qstring
- : is_convertible_to_view_or_qstring_helper<typename std::decay<T>::type> {};
+ using is_convertible_to_view_or_qstring = std::disjunction<
+ std::is_convertible<T, QString>,
+ std::is_convertible<T, QStringView>,
+ std::is_convertible<T, QLatin1String>
+ >;
public:
template <typename...Args>
[[nodiscard]]
diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp
index 5045137fd5..32f04e9d00 100644
--- a/src/corelib/text/qstringconverter.cpp
+++ b/src/corelib/text/qstringconverter.cpp
@@ -1204,6 +1204,11 @@ QChar *QUtf32::convertToUnicode(QChar *out, QByteArrayView in, QStringConverter:
}
#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
+int QLocal8Bit::checkUtf8()
+{
+ return GetACP() == CP_UTF8 ? 1 : -1;
+}
+
static QString convertToUnicodeCharByChar(QByteArrayView in, QStringConverter::State *state)
{
qsizetype length = in.size();
@@ -1257,7 +1262,7 @@ static QString convertToUnicodeCharByChar(QByteArrayView in, QStringConverter::S
}
-QString QLocal8Bit::convertToUnicode(QByteArrayView in, QStringConverter::State *state)
+QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, QStringConverter::State *state)
{
qsizetype length = in.size();
@@ -1345,7 +1350,7 @@ QString QLocal8Bit::convertToUnicode(QByteArrayView in, QStringConverter::State
return s;
}
-QByteArray QLocal8Bit::convertFromUnicode(QStringView in, QStringConverter::State *state)
+QByteArray QLocal8Bit::convertFromUnicode_sys(QStringView in, QStringConverter::State *state)
{
const QChar *ch = in.data();
qsizetype uclen = in.size();
diff --git a/src/corelib/text/qstringconverter_p.h b/src/corelib/text/qstringconverter_p.h
index a7e3606d17..c6a5dc1d69 100644
--- a/src/corelib/text/qstringconverter_p.h
+++ b/src/corelib/text/qstringconverter_p.h
@@ -368,8 +368,31 @@ struct Q_CORE_EXPORT QLocal8Bit
static QByteArray convertFromUnicode(QStringView in, QStringConverter::State *state)
{ return QUtf8::convertFromUnicode(in, state); }
#else
- static QString convertToUnicode(QByteArrayView, QStringConverter::State *);
- static QByteArray convertFromUnicode(QStringView, QStringConverter::State *);
+ static int checkUtf8();
+ static bool isUtf8()
+ {
+ static QBasicAtomicInteger<qint8> result = { 0 };
+ int r = result.loadRelaxed();
+ if (r == 0) {
+ r = checkUtf8();
+ result.storeRelaxed(r);
+ }
+ return r > 0;
+ }
+ static QString convertToUnicode_sys(QByteArrayView, QStringConverter::State *);
+ static QString convertToUnicode(QByteArrayView in, QStringConverter::State *state)
+ {
+ if (isUtf8())
+ return QUtf8::convertToUnicode(in, state);
+ return convertToUnicode_sys(in, state);
+ }
+ static QByteArray convertFromUnicode_sys(QStringView, QStringConverter::State *);
+ static QByteArray convertFromUnicode(QStringView in, QStringConverter::State *state)
+ {
+ if (isUtf8())
+ return QUtf8::convertFromUnicode(in, state);
+ return convertFromUnicode_sys(in, state);
+ }
#endif
};
diff --git a/src/corelib/text/qt_attribution.json b/src/corelib/text/qt_attribution.json
index d3c4ab65f4..2d19195d59 100644
--- a/src/corelib/text/qt_attribution.json
+++ b/src/corelib/text/qt_attribution.json
@@ -24,7 +24,7 @@
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core (QTimeZone, QLocale).",
"Files": "For update, see qtbase/util/locale_database/cldr2qlocalexml.py",
- "Files": "qlocale_data_p.h qtimezoneprivate_data_p.h",
+ "Files": "qlocale_data_p.h ../time/qtimezoneprivate_data_p.h",
"Description": "The Unicode CLDR provides key building blocks for software to support the
world's languages, with the largest and most extensive standard repository of locale data
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 06b618873d..3eeabdd96a 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -580,14 +580,14 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
{
Q_ASSERT(f);
- auto continuation = [func = std::forward<F>(func), promise = QPromise(fi),
+ auto continuation = [func = std::forward<F>(func), fi,
context = QPointer<QObject>(context)](
const QFutureInterfaceBase &parentData) mutable {
Q_ASSERT(context);
const auto parent = QFutureInterface<ParentResultType>(parentData).future();
QMetaObject::invokeMethod(
context,
- [func = std::forward<F>(func), promise = std::move(promise), parent]() mutable {
+ [func = std::forward<F>(func), promise = QPromise(fi), parent]() mutable {
SyncContinuation<Function, ResultType, ParentResultType> continuationJob(
std::forward<Function>(func), parent, std::move(promise));
continuationJob.execute();
@@ -679,13 +679,13 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy
Q_ASSERT(future);
auto failureContinuation =
- [function = std::forward<F>(function), promise = QPromise(fi),
+ [function = std::forward<F>(function), fi,
context = QPointer<QObject>(context)](const QFutureInterfaceBase &parentData) mutable {
Q_ASSERT(context);
const auto parent = QFutureInterface<ResultType>(parentData).future();
QMetaObject::invokeMethod(context,
[function = std::forward<F>(function),
- promise = std::move(promise), parent]() mutable {
+ promise = QPromise(fi), parent]() mutable {
FailureHandler<Function, ResultType> failureHandler(
std::forward<Function>(function), parent, std::move(promise));
failureHandler.run();
@@ -776,13 +776,13 @@ public:
QObject *context)
{
Q_ASSERT(future);
- auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler),
+ auto canceledContinuation = [fi, handler = std::forward<F>(handler),
context = QPointer<QObject>(context)](
const QFutureInterfaceBase &parentData) mutable {
Q_ASSERT(context);
auto parentFuture = QFutureInterface<ResultType>(parentData).future();
QMetaObject::invokeMethod(context,
- [promise = std::move(promise), parentFuture,
+ [promise = QPromise(fi), parentFuture,
handler = std::forward<F>(handler)]() mutable {
run(std::forward<F>(handler), parentFuture, std::move(promise));
});
diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp
index 6b35ed1eb8..588683ff0a 100644
--- a/src/corelib/thread/qfutureinterface.cpp
+++ b/src/corelib/thread/qfutureinterface.cpp
@@ -804,6 +804,7 @@ void QFutureInterfaceBase::cleanContinuation()
QMutexLocker lock(&d->continuationMutex);
d->continuation = nullptr;
d->continuationState = QFutureInterfaceBasePrivate::Cleaned;
+ d->continuationData = nullptr;
}
void QFutureInterfaceBase::runContinuation() const
diff --git a/src/corelib/thread/qpromise.qdoc b/src/corelib/thread/qpromise.qdoc
index f9040d4cd1..31e5c9b653 100644
--- a/src/corelib/thread/qpromise.qdoc
+++ b/src/corelib/thread/qpromise.qdoc
@@ -62,6 +62,8 @@
\snippet snippet_qpromise.cpp multithread_init
\codeline
\snippet snippet_qpromise.cpp multithread_main
+ \codeline
+ \snippet snippet_qpromise.cpp multithread_cleanup
\sa QFuture
*/
diff --git a/src/corelib/tools/qcontainertools_impl.h b/src/corelib/tools/qcontainertools_impl.h
index edb548cf02..3a26977a7a 100644
--- a/src/corelib/tools/qcontainertools_impl.h
+++ b/src/corelib/tools/qcontainertools_impl.h
@@ -89,6 +89,26 @@ void q_uninitialized_relocate_n(T* first, N n, T* out)
}
}
+/*!
+ \internal
+
+ A wrapper around std::rotate(), with an optimization for
+ Q_RELOCATABLE_TYPEs. We omit the return value, as it would be more work to
+ compute in the Q_RELOCATABLE_TYPE case and, unlike std::rotate on
+ ForwardIterators, callers can compute the result in constant time
+ themselves.
+*/
+template <typename T>
+void q_rotate(T *first, T *mid, T *last)
+{
+ if constexpr (QTypeInfo<T>::isRelocatable) {
+ const auto cast = [](T *p) { return reinterpret_cast<uchar*>(p); };
+ std::rotate(cast(first), cast(mid), cast(last));
+ } else {
+ std::rotate(first, mid, last);
+ }
+}
+
template<typename iterator, typename N>
void q_relocate_overlap_n_left_move(iterator first, N n, iterator d_first)
{
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index f6db6b976c..e0db1a33eb 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -40,6 +40,8 @@
#include <qcryptographichash.h>
#include <qiodevice.h>
+#include <qmutex.h>
+#include <private/qlocking_p.h>
#include "../../3rdparty/sha1/sha1.cpp"
@@ -164,6 +166,8 @@ public:
};
void sha3Finish(int bitCount, Sha3Variant sha3Variant);
#endif
+ // protects result in result()
+ QBasicMutex finalizeMutex;
QByteArray result;
};
@@ -468,6 +472,9 @@ bool QCryptographicHash::addData(QIODevice *device)
*/
QByteArray QCryptographicHash::result() const
{
+ // result() is a const function, so concurrent calls are allowed; protect:
+ const auto lock = qt_scoped_lock(d->finalizeMutex);
+ // check that no other thread already finalized before us:
if (!d->result.isEmpty())
return d->result;
@@ -575,6 +582,7 @@ QByteArray QCryptographicHash::result() const
}
#endif
}
+
return d->result;
}
diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc
index e366a30324..5ca8385485 100644
--- a/src/corelib/tools/qlist.qdoc
+++ b/src/corelib/tools/qlist.qdoc
@@ -573,17 +573,14 @@
Removes all the elements from the list.
- \note Until Qt 5.6, this also released the memory used by
- the list. From Qt 5.7, the capacity is preserved. To shed
- all capacity, swap with a default-constructed list:
- \code
- QList<T> l ...;
- QList<T>().swap(l);
- Q_ASSERT(l.capacity() == 0);
- \endcode
- or call squeeze().
+ If this list is not shared, the capacity() is preserved. Use squeeze() to
+ shed excess capacity.
+
+ \note In Qt versions prior to 5.7 (for QVector) and 6.0 (for QList), this
+ function released the memory used by the list instead of preserving the
+ capacity.
- \sa squeeze()
+ \sa resize(), squeeze()
*/
/*! \fn template <typename T> const T &QList<T>::at(qsizetype i) const
diff --git a/src/corelib/tools/qpair.h b/src/corelib/tools/qpair.h
index 6cb7fc5079..c19ed148db 100644
--- a/src/corelib/tools/qpair.h
+++ b/src/corelib/tools/qpair.h
@@ -58,9 +58,6 @@ constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2)
return std::make_pair(std::forward<T1>(value1), std::forward<T2>(value2));
}
-template<class T1, class T2>
-class QTypeInfo<std::pair<T1, T2>> : public QTypeInfoMerger<std::pair<T1, T2>, T1, T2> {};
-
QT_END_NAMESPACE
#endif // QPAIR_H
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index bd4d6c906b..1c45d54ece 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -479,6 +479,46 @@
*/
/*!
+ \fn template <class T> QSharedPointer<T>::QSharedPointer(QSharedPointer &&other)
+
+ Move-constructs a QSharedPointer instance, making it point at the same
+ object that \a other was pointing to.
+
+ \since 5.4
+*/
+
+/*!
+ \fn template <class T> QSharedPointer<T>::operator=(QSharedPointer &&other)
+
+ Move-assigns \a other to this QSharedPointer instance.
+
+ \since 5.0
+*/
+
+/*!
+ \fn template <class T> template <class X> QSharedPointer<T>::QSharedPointer(QSharedPointer<X> &&other)
+
+ Move-constructs a QSharedPointer instance, making it point at the same
+ object that \a other was pointing to.
+
+ This constructor participates in overload resolution only if \c{X*}
+ implicitly converts to \c{T*}.
+
+ \since 5.6
+*/
+
+/*!
+ \fn template <class T> template <class X> QSharedPointer<T>::operator=(QSharedPointer<X> &&other)
+
+ Move-assigns \a other to this QSharedPointer instance.
+
+ This assignment operator participates in overload resolution only if \c{X*}
+ implicitly converts to \c{T*}.
+
+ \since 5.6
+*/
+
+/*!
\fn template <class T> QSharedPointer<T>::QSharedPointer(const QWeakPointer<T> &other)
Creates a QSharedPointer by promoting the weak reference \a other
@@ -932,6 +972,15 @@
*/
/*!
+ \fn template <class T> qHash(const QSharedPointer<T> &key, size_t seed)
+ \relates QSharedPointer
+
+ Returns the hash value for \a key, using \a seed to seed the calculation.
+
+ \since 5.0
+*/
+
+/*!
\fn template <class T> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h
index a7365aecf1..1c22b185c3 100644
--- a/src/corelib/tools/qsharedpointer.h
+++ b/src/corelib/tools/qsharedpointer.h
@@ -84,6 +84,11 @@ public:
QSharedPointer<T> &operator=(QSharedPointer<T> &&other) noexcept;
QSharedPointer<T> &operator=(const QWeakPointer<T> &other);
+ template <class X>
+ QSharedPointer(QSharedPointer<X> && other) noexcept;
+ template <class X>
+ QSharedPointer &operator=(QSharedPointer<X> && other) noexcept;
+
void swap(QSharedPointer<T> &other) noexcept;
QWeakPointer<T> toWeakRef() const;
@@ -106,6 +111,9 @@ public:
};
template <class T>
+size_t qHash(const QSharedPointer<T> &key, size_t seed = 0) noexcept;
+
+template <class T>
class QWeakPointer
{
public:
diff --git a/src/corelib/tools/qtools_p.h b/src/corelib/tools/qtools_p.h
index 9d4a3ffe60..334e609208 100644
--- a/src/corelib/tools/qtools_p.h
+++ b/src/corelib/tools/qtools_p.h
@@ -89,6 +89,12 @@ constexpr inline char toAsciiLower(char ch) noexcept
{
return (ch >= 'A' && ch <= 'Z') ? ch - 'A' + 'a' : ch;
}
+
+constexpr inline char toAsciiUpper(char ch) noexcept
+{
+ return (ch >= 'a' && ch <= 'z') ? ch - 'a' + 'A' : ch;
+}
+
}
// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size.
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 1702ab04e9..2434402eaf 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -183,7 +183,12 @@ public:
}
inline bool isEmpty() const { return (s == 0); }
inline void resize(qsizetype size);
- inline void clear() { resize(0); }
+ void clear()
+ {
+ if constexpr (QTypeInfo<T>::isComplex)
+ std::destroy_n(data(), size());
+ s = 0;
+ }
inline void squeeze();
inline qsizetype capacity() const { return a; }
@@ -368,6 +373,20 @@ public:
private:
void reallocate(qsizetype size, qsizetype alloc);
+ void resize_impl(qsizetype newSize, const T &t)
+ {
+ const auto increment = newSize - size();
+ if (increment > 0 && QtPrivate::q_points_into_range(&t, cbegin(), cend())) {
+ resize_impl(newSize, T(t));
+ return;
+ }
+ reallocate(qMin(size(), newSize), qMax(newSize, capacity()));
+
+ if (increment > 0)
+ std::uninitialized_fill_n(end(), increment, t);
+ s = newSize;
+ }
+
qsizetype a; // capacity
qsizetype s; // size
T *ptr; // data
@@ -625,29 +644,12 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
Q_ASSERT(s <= a);
Q_ASSERT(a > 0);
- qsizetype offset = qsizetype(before - ptr);
- if (s == a)
- reserve(s * 2);
- if (!QTypeInfo<T>::isRelocatable) {
- T *b = ptr + offset;
- T *i = ptr + s;
- T *j = i + 1;
- // The new end-element needs to be constructed, the rest must be move assigned
- if (i != b) {
- new (--j) T(std::move(*--i));
- while (i != b)
- *--j = std::move(*--i);
- *b = std::move(t);
- } else {
- new (b) T(std::move(t));
- }
- } else {
- T *b = ptr + offset;
- memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (s - offset) * sizeof(T));
- new (b) T(std::move(t));
- }
- s += 1;
- return ptr + offset;
+ const qsizetype offset = qsizetype(before - ptr);
+ append(std::move(t));
+ const auto b = begin() + offset;
+ const auto e = end();
+ QtPrivate::q_rotate(b, e - 1, e);
+ return b;
}
template <class T, qsizetype Prealloc>
@@ -655,28 +657,12 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
{
Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
- qsizetype offset = qsizetype(before - ptr);
- if (n != 0) {
- const T copy(t); // `t` could alias an element in [begin(), end()[
- resize(s + n);
- if (!QTypeInfo<T>::isRelocatable) {
- T *b = ptr + offset;
- T *j = ptr + s;
- T *i = j - n;
- while (i != b)
- *--j = *--i;
- i = b + n;
- while (i != b)
- *--i = copy;
- } else {
- T *b = ptr + offset;
- T *i = b + n;
- memmove(static_cast<void *>(i), static_cast<const void *>(b), (s - offset - n) * sizeof(T));
- while (i != b)
- new (--i) T(copy);
- }
- }
- return ptr + offset;
+ const qsizetype offset = qsizetype(before - cbegin());
+ resize_impl(size() + n, t);
+ const auto b = begin() + offset;
+ const auto e = end();
+ QtPrivate::q_rotate(b, e - n, e);
+ return b;
}
template <class T, qsizetype Prealloc>