summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/CMakeLists.txt24
-rw-r--r--src/corelib/Qt6CoreMacros.cmake15
-rw-r--r--src/corelib/animation/qabstractanimation.cpp1
-rw-r--r--src/corelib/configure.cmake34
-rw-r--r--src/corelib/doc/images/javaiterators1.svg60
-rw-r--r--src/corelib/doc/images/javaiterators2.svg57
-rw-r--r--src/corelib/doc/images/stliterators1.svg90
-rw-r--r--src/corelib/doc/src/cmake/cmake-configure-variables.qdoc7
-rw-r--r--src/corelib/doc/src/cmake/cmake-properties.qdoc2
-rw-r--r--src/corelib/doc/src/cmake/qt_deploy_translations.qdoc1
-rw-r--r--src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc1
-rw-r--r--src/corelib/doc/src/cmake/qt_finalize_project.qdoc1
-rw-r--r--src/corelib/doc/src/containers.qdoc2
-rw-r--r--src/corelib/doc/src/external-resources.qdoc5
-rw-r--r--src/corelib/doc/src/java-style-iterators.qdoc2
-rw-r--r--src/corelib/global/patches/tlexpected/0006-Namespace-TL_-macros-with-Q23_.patch914
-rw-r--r--src/corelib/global/qcompilerdetection.h2
-rw-r--r--src/corelib/global/qexpected_p.h312
-rw-r--r--src/corelib/global/qnumeric.h21
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp6
-rw-r--r--src/corelib/global/qoperatingsystemversion.h1
-rw-r--r--src/corelib/global/qttranslation.qdoc2
-rw-r--r--src/corelib/io/qfsfileengine.cpp6
-rw-r--r--src/corelib/io/qiooperation_p.h20
-rw-r--r--src/corelib/io/qioring.cpp30
-rw-r--r--src/corelib/io/qioring_linux.cpp13
-rw-r--r--src/corelib/io/qioring_p.h45
-rw-r--r--src/corelib/io/qioring_win.cpp818
-rw-r--r--src/corelib/io/qrandomaccessasyncfile.cpp25
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_darwin.mm103
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_p_p.h241
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_qioring.cpp61
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_threadpool.cpp79
-rw-r--r--src/corelib/io/qwindowspipereader.cpp5
-rw-r--r--src/corelib/itemmodels/qrangemodel_impl.h52
-rw-r--r--src/corelib/itemmodels/qrangemodeladapter.h232
-rw-r--r--src/corelib/itemmodels/qrangemodeladapter.qdoc61
-rw-r--r--src/corelib/kernel/qassociativeiterable.h2
-rw-r--r--src/corelib/kernel/qcore_mac.mm32
-rw-r--r--src/corelib/kernel/qcore_mac_p.h17
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf.mm1
-rw-r--r--src/corelib/kernel/qiterable.h6
-rw-r--r--src/corelib/kernel/qjniobject.cpp76
-rw-r--r--src/corelib/kernel/qmetaassociation.h6
-rw-r--r--src/corelib/kernel/qmetacontainer.h9
-rw-r--r--src/corelib/kernel/qmetaobject.cpp27
-rw-r--r--src/corelib/kernel/qmetaobject_p.h1
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp55
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h4
-rw-r--r--src/corelib/kernel/qmetasequence.cpp40
-rw-r--r--src/corelib/kernel/qmetasequence.h76
-rw-r--r--src/corelib/kernel/qobjectdefs.h2
-rw-r--r--src/corelib/kernel/qpermissions.cpp2
-rw-r--r--src/corelib/kernel/qproperty.cpp20
-rw-r--r--src/corelib/kernel/qsequentialiterable.h3
-rw-r--r--src/corelib/kernel/qtmocconstants.h3
-rw-r--r--src/corelib/kernel/qtmochelpers.h7
-rw-r--r--src/corelib/kernel/qtranslator.cpp4
-rw-r--r--src/corelib/kernel/qvariant.h10
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp16
-rw-r--r--src/corelib/platform/windows/qbstr_p.h3
-rw-r--r--src/corelib/platform/windows/qcomobject_p.h1
-rw-r--r--src/corelib/platform/windows/qcomptr_p.h1
-rw-r--r--src/corelib/platform/windows/qcomvariant_p.h1
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration.cpp1
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration_p.h1
-rw-r--r--src/corelib/platform/windows/qt_winrtbase_p.h1
-rw-r--r--src/corelib/serialization/qcborvalue.cpp1
-rw-r--r--src/corelib/serialization/qdatastream.cpp1
-rw-r--r--src/corelib/serialization/qdatastream.h5
-rw-r--r--src/corelib/serialization/qxmlstream.cpp6
-rw-r--r--src/corelib/text/qlocale.cpp1
-rw-r--r--src/corelib/text/qstringconverter.cpp4
-rw-r--r--src/corelib/thread/qfuture.qdoc2
-rw-r--r--src/corelib/thread/qfuture_impl.h9
-rw-r--r--src/corelib/thread/qfutureinterface.h4
-rw-r--r--src/corelib/thread/qreadwritelock.cpp8
-rw-r--r--src/corelib/time/qdatetimeparser.cpp1
-rw-r--r--src/corelib/tools/qarraydata.cpp2
-rw-r--r--src/corelib/tools/qeasingcurve.cpp14
-rw-r--r--src/corelib/tools/qmargins.h15
-rw-r--r--src/corelib/tools/qpoint.h7
-rw-r--r--src/corelib/tools/qsize.h9
83 files changed, 3144 insertions, 724 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index dec68c5f9f4..539ad753ca6 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -583,24 +583,21 @@ if(QT_FEATURE_async_io)
SOURCES
io/qrandomaccessasyncfile_darwin.mm
)
- elseif(LINUX AND QT_FEATURE_liburing)
+ elseif((LINUX AND QT_FEATURE_liburing) OR (WIN32 AND QT_FEATURE_windows_ioring))
qt_internal_extend_target(Core
SOURCES
io/qrandomaccessasyncfile_qioring.cpp
DEFINES
QT_RANDOMACCESSASYNCFILE_QIORING
)
- elseif(QT_FEATURE_thread AND QT_FEATURE_future)
- # TODO: This should become the last (fallback) condition later.
- # We migth also want to rewrite it so that it does not depend on
- # QT_FEATURE_future.
- qt_internal_extend_target(Core
- SOURCES
- io/qrandomaccessasyncfile_threadpool.cpp
- DEFINES
- QT_RANDOMACCESSASYNCFILE_THREAD
- )
endif()
+ # This is the fallback condition that should be always available.
+ # TODO: try to rewrite it so that it does not depend on
+ # QT_FEATURE_future.
+ qt_internal_extend_target(Core
+ SOURCES
+ io/qrandomaccessasyncfile_threadpool.cpp
+ )
endif()
# This needs to be done before one below adds kernel32 because the symbols we use
@@ -763,6 +760,11 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_liburing
uring
)
+qt_internal_extend_target(Core CONDITION QT_FEATURE_windows_ioring
+ SOURCES
+ io/qioring.cpp io/qioring_win.cpp io/qioring_p.h
+)
+
# Workaround for QTBUG-101411
# Remove if QCC (gcc version 8.3.0) for QNX 7.1.0 is no longer supported
qt_internal_extend_target(Core CONDITION QCC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "8.3.0")
diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake
index b69d0285de2..c1f9aee0180 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -3677,21 +3677,6 @@ macro(qt6_standard_project_setup)
if(NOT DEFINED QT_I18N_SOURCE_LANGUAGE)
set(QT_I18N_SOURCE_LANGUAGE ${__qt_sps_arg_I18N_SOURCE_LANGUAGE})
endif()
-
- if(CMAKE_GENERATOR STREQUAL "Xcode")
- # Ensure we always use device SDK for Xcode for single-arch Qt builds
- set(qt_osx_arch_count 0)
- if(QT_OSX_ARCHITECTURES)
- list(LENGTH QT_OSX_ARCHITECTURES qt_osx_arch_count)
- endif()
- if(NOT qt_osx_arch_count GREATER 1 AND "${CMAKE_OSX_SYSROOT}" MATCHES "^[a-z]+simulator$")
- # Xcode expects the base SDK to be the device SDK
- set(simulator_sysroot "${CMAKE_OSX_SYSROOT}")
- string(REGEX REPLACE "simulator" "os" CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}")
- set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}" CACHE STRING "" FORCE)
- set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "${simulator_sysroot}")
- endif()
- endif()
endif()
endmacro()
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index c3e1ba4010f..8a343b15eeb 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -858,6 +858,7 @@ qint64 QAnimationDriver::elapsed() const
*/
/*!
+ \internal
The default animation driver just spins the timer...
*/
QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer)
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index c1d15c75054..7274b51cc0a 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -605,6 +605,31 @@ int main(void)
"
)
+qt_config_compile_test(windows_ioring
+ LABEL "Windows SDK: IORing"
+ CODE
+"#include <windows.h>
+#include <ioringapi.h>
+
+int main(void)
+{
+ /* BEGIN TEST: */
+ IORING_CREATE_FLAGS flags;
+ memset(&flags, 0, sizeof(flags));
+ HIORING ioRingHandle = nullptr;
+ HRESULT hr = CreateIoRing(IORING_VERSION_3, flags, 1, 1, &ioRingHandle);
+ if (hr == IORING_E_SUBMISSION_QUEUE_FULL) // not valid, but test that this #define exists
+ return 0;
+ IORING_HANDLE_REF ref(HANDLE(nullptr));
+ IORING_BUFFER_REF bufRef(nullptr);
+ // The newest API addition that we require:
+ BuildIoRingWriteFile(ioRingHandle, ref, bufRef, -1, 0, FILE_WRITE_FLAGS_NONE, 0, IOSQE_FLAGS_NONE);
+ /* END TEST: */
+ return 0;
+}
+"
+)
+
# cpp_winrt
qt_config_compile_test(cpp_winrt
LABEL "cpp/winrt"
@@ -785,6 +810,11 @@ qt_feature("winsdkicu" PRIVATE
CONDITION TEST_winsdkicu
DISABLE QT_FEATURE_icu
)
+qt_feature("windows-ioring" PRIVATE
+ LABEL "Windows I/O Ring"
+ AUTODETECT WIN32 AND CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 10.0.22000
+ CONDITION TEST_windows_ioring
+)
qt_feature("inotify" PUBLIC PRIVATE
LABEL "inotify"
CONDITION TEST_inotify OR TEST_fsnotify
@@ -1252,14 +1282,13 @@ qt_feature("permissions" PUBLIC
)
qt_feature("openssl-hash" PRIVATE
LABEL "OpenSSL based cryptographic hash"
- AUTODETECT OFF
CONDITION QT_FEATURE_openssl_linked AND QT_FEATURE_opensslv30
PURPOSE "Uses OpenSSL based implementation of cryptographic hash algorithms."
)
qt_feature("async-io" PRIVATE
LABEL "Async File I/O"
PURPOSE "Provides support for asynchronous file I/O."
- CONDITION (QT_FEATURE_thread AND QT_FEATURE_future) OR APPLE
+ CONDITION QT_FEATURE_thread AND QT_FEATURE_future
)
qt_configure_add_summary_section(NAME "Qt Core")
@@ -1272,6 +1301,7 @@ qt_configure_add_summary_entry(ARGS "glib")
qt_configure_add_summary_entry(ARGS "icu")
qt_configure_add_summary_entry(ARGS "jemalloc")
qt_configure_add_summary_entry(ARGS "liburing")
+qt_configure_add_summary_entry(ARGS "windows-ioring")
qt_configure_add_summary_entry(ARGS "timezone_tzdb")
qt_configure_add_summary_entry(ARGS "system-libb2")
qt_configure_add_summary_entry(ARGS "mimetype-database")
diff --git a/src/corelib/doc/images/javaiterators1.svg b/src/corelib/doc/images/javaiterators1.svg
index 468dbe5371c..c10329ab480 100644
--- a/src/corelib/doc/images/javaiterators1.svg
+++ b/src/corelib/doc/images/javaiterators1.svg
@@ -12,6 +12,11 @@
svg .text-style { font: 20px arial; fill: black }
svg .fill-style { stroke: none; fill: red }
+ svg.dark .box-style { stroke: #f2f2f2; fill: black }
+ svg.dark .line-style { stroke: red; fill: none }
+ svg.dark .text-style { font: 20px arial; fill: #f2f2f2 }
+ svg.dark .fill-style { stroke: none; fill: red }
+
[data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black }
[data-theme="dark"] svg .line-style { stroke: red; fill: none }
[data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 }
@@ -24,36 +29,53 @@
</style>
<g transform="translate(10.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">A</text>
-<path d="M 0,60 v 30" class="line-style" />
-<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" />
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">A</text>
+<path d="M 0,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red"
+ class="fill-style" />
</g>
<g transform="translate(90.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">B</text>
-<path d="M 0,60 v 30" class="line-style" />
-<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" />
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">B</text>
+<path d="M 0,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red"
+ class="fill-style" />
</g>
<g transform="translate(170.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">C</text>
-<path d="M 0,60 v 30" class="line-style" />
-<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" />
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">C</text>
+<path d="M 0,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red"
+ class="fill-style" />
</g>
<g transform="translate(250.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">D</text>
-<path d="M 0,60 v 30" class="line-style" />
-<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" />
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">D</text>
+<path d="M 0,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red"
+ class="fill-style" />
</g>
<g transform="translate(330.5, 10.5)">
-<path d="M 0,60 v 30" class="line-style" />
-<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" />
+<path d="M 0,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red"
+ class="fill-style" />
</g>
-
</svg>
diff --git a/src/corelib/doc/images/javaiterators2.svg b/src/corelib/doc/images/javaiterators2.svg
index df4c6b352a6..3b41b3f8730 100644
--- a/src/corelib/doc/images/javaiterators2.svg
+++ b/src/corelib/doc/images/javaiterators2.svg
@@ -15,6 +15,14 @@
svg .text-style { font: 20px arial; fill: black }
svg .small-text-style { font: 12px monospace; fill: black }
+ svg.dark .box-style { stroke: #f2f2f2; fill: black }
+ svg.dark .line-style { stroke: red; fill: none }
+ svg.dark .fill-style { stroke: none; fill: red }
+ svg.dark .np-line-style { stroke: #4080ff; fill: none; stroke-width: 1.5 }
+ svg.dark .np-fill-style { stroke: none; fill: #4080ff }
+ svg.dark .text-style { font: 20px arial; fill: #f2f2f2 }
+ svg.dark .small-text-style { font: 12px monospace; fill: #f2f2f2 }
+
[data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black }
[data-theme="dark"] svg .line-style { stroke: red; fill: none }
[data-theme="dark"] svg .fill-style { stroke: none; fill: red }
@@ -33,31 +41,46 @@
</style>
<g transform="translate(10.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">A</text>
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">A</text>
</g>
<g transform="translate(90.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">B</text>
-<path d="M 0,60 c 0,30 50,40 80,30" class="np-line-style" />
-<path d="M 0,60 l -2,14 l 11,-4 z" class="np-fill-style" />
-<text x="-15" y="110" class="small-text-style">previous()</text>
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">B</text>
+<path d="M 0,60 c 0,30 50,40 80,30" stroke="blue" fill="none"
+ class="np-line-style" />
+<path d="M 0,60 l -2,14 l 11,-4 z" stroke="none" fill="blue"
+ class="np-fill-style" />
+<text x="-15" y="110"
+ class="small-text-style">previous()</text>
</g>
<g transform="translate(170.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">C</text>
-<path d="M 0,60 v 50" class="line-style" />
-<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" />
-<text x="30" y="110" class="small-text-style">next()</text>
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">C</text>
+<path d="M 0,60 v 50" stroke="red"
+ class="line-style" />
+<path d="M 0,60 l -5,10 l 10,0 z" stroke="none" fill="red"
+ class="fill-style" />
+<text x="30" y="110"
+ class="small-text-style">next()</text>
</g>
<g transform="translate(250.5, 10.5)">
-<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" />
-<text x="35" y="36" class="text-style">D</text>
-<path d="M 0,60 c 0,30 -50,40 -80,30" class="np-line-style" />
-<path d="M 0,60 l 2,14 l -11,-4 z" class="np-fill-style" />
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">D</text>
+<path d="M 0,60 c 0,30 -50,40 -80,30" stroke="blue" fill="none"
+ class="np-line-style" />
+<path d="M 0,60 l 2,14 l -11,-4 z" stroke="none" fill="blue"
+ class="np-fill-style" />
</g>
-
</svg>
diff --git a/src/corelib/doc/images/stliterators1.svg b/src/corelib/doc/images/stliterators1.svg
new file mode 100644
index 00000000000..478211c78d7
--- /dev/null
+++ b/src/corelib/doc/images/stliterators1.svg
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ width="420"
+ height="110"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+
+<style>
+ svg .box-style { stroke: black; fill: white }
+ svg .line-style { stroke: red; fill: none }
+ svg .text-style { font: 20px arial; fill: black }
+ svg .fill-style { stroke: none; fill: red }
+ svg .fn-text-style { font: 14px monospace; fill: black }
+
+ svg.dark .box-style { stroke: #f2f2f2; fill: black }
+ svg.dark .line-style { stroke: red; fill: none }
+ svg.dark .text-style { font: 20px arial; fill: #f2f2f2 }
+ svg.dark .fill-style { stroke: none; fill: red }
+ svg.dark .fn-text-style { font: 14px monospace; fill: #f2f2f2 }
+
+ [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black }
+ [data-theme="dark"] svg .line-style { stroke: red; fill: none }
+ [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 }
+ [data-theme="dark"] svg .fill-style { stroke: none; fill: red }
+ [data-theme="dark"] svg .fn-text-style { font: 14px monospace; fill: #f2f2f2 }
+
+ [data-theme="light"] svg .box-style { stroke: black; fill: white }
+ [data-theme="light"] svg .line-style { stroke: red; fill: none }
+ [data-theme="light"] svg .text-style { font: 20px arial; fill: black }
+ [data-theme="light"] svg .fill-style { stroke: none; fill: red }
+ [data-theme="light"] svg .fn-text-style { font: 14px monospace; fill: black }
+</style>
+
+<g transform="translate(10.5, 10.5)">
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">A</text>
+<path d="M 40,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red"
+ class="fill-style" />
+</g>
+
+<g transform="translate(90.5, 10.5)">
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">B</text>
+<path d="M 40,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red"
+ class="fill-style" />
+</g>
+
+<g transform="translate(170.5, 10.5)">
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">C</text>
+<path d="M 40,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red"
+ class="fill-style" />
+</g>
+
+<g transform="translate(250.5, 10.5)">
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ class="box-style" />
+<text x="35" y="36" font-family="arial" font-size="20px"
+ class="text-style">D</text>
+<path d="M 40,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red"
+ class="fill-style" />
+</g>
+
+<g transform="translate(330.5, 10.5)">
+<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white"
+ stroke-dasharray="3,3"
+ class="box-style" />
+<text x="20" y="36" font-family="monospace" font-size="14px"
+ class="fn-text-style">end()</text>
+<path d="M 40,60 v 30" stroke="red"
+ class="line-style" />
+<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red"
+ class="fill-style" />
+</g>
+</svg>
diff --git a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
index 0a0dc0b3c50..7cd3f91b901 100644
--- a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
@@ -133,7 +133,6 @@ use, for example, library files referenced from a Qt installation.
\summary {Forces or disables release package signing regardless of the build type.}
\cmakevariablesince 6.7
-\preliminarycmakevariable
\cmakevariableandroidonly
When set to \c Release, the \c --release flag is passed to the \c
@@ -143,6 +142,10 @@ effectively disables release package signing even in Release or RelWithDebInfo
builds. When not set, the default behavior is to use release package signing in
build types other than Debug.
+This variable is not supposed to be set in CMake project files. Rather set it
+when configuring your project on the command line or in the CMake settings of
+your IDE.
+
\sa {androiddeployqt}
*/
@@ -522,7 +525,6 @@ To prevent this, set \c QT_NO_SET_XCODE_BUNDLE_IDENTIFIER to \c TRUE.
\summary {Enables verbose mode of deployment tools.}
\cmakevariablesince 6.3
-\preliminarycmakevariable
Enables verbose mode of the \l androiddeployqt deployment tool when it is called
internally at build time, usually during target finalization.
@@ -542,7 +544,6 @@ must be set before the first \c{find_package(Qt6)} call to have that effect.
\summary {Name of the file to include for setting up deployment support.}
\cmakevariablesince 6.3
-\preliminarycmakevariable
\note The value of this variable should never be modified by project code.
This configure-phase variable is set by the Core package. It is intended to be
diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc
index 821862494a2..c7b1a27a4b4 100644
--- a/src/corelib/doc/src/cmake/cmake-properties.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc
@@ -665,7 +665,6 @@ UTF-8 input). Use the \l QT_NO_CAST_FROM_ASCII and
\summary {Specifies the default Qt resource prefix.}
\cmakepropertysince 6.0
-\preliminarycmakeproperty
When using \l{qt6_add_resources}{qt_add_resources} without a \c PREFIX
argument, then the value of this target property will be used as
@@ -773,7 +772,6 @@ CMake properties:
\brief Sets the FOLDER property for Qt-internal targets.
\cmakepropertysince 6.5
-\preliminarycmakeproperty
Name of the \l FOLDER for internal targets that are added by Qt's CMake
commands.
diff --git a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc
index 43ff23a35a1..e6d3edbbdc4 100644
--- a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc
+++ b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc
@@ -17,7 +17,6 @@ can only be called from a deployment script. It cannot be called directly by the
project during the configure stage.
\cmakecommandsince 6.5
-\preliminarycmakecommand
\note This command does not usually need to be called directly. It is used
internally by other higher level commands, but projects wishing to
implement more customized deployment logic may find it useful.
diff --git a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc
index 7ec8d90f9b1..24112b1cf87 100644
--- a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc
+++ b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc
@@ -11,7 +11,6 @@
\summary {Extracts metatypes from a Qt target and generates an associated metatypes.json file.}
\cmakecommandsince 6.0
-\preliminarycmakecommand
\section1 Synopsis
diff --git a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc
index 5506712691e..f60b850fcdb 100644
--- a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc
+++ b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc
@@ -9,7 +9,6 @@
\keyword qt6_finalize_project
\summary {Handles various common platform-specific tasks associated with a Qt project.}
-\preliminarycmakecommand
\include cmake-find-package-core.qdocinc
diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc
index 874ab807609..38ce2188e13 100644
--- a/src/corelib/doc/src/containers.qdoc
+++ b/src/corelib/doc/src/containers.qdoc
@@ -275,7 +275,7 @@
The diagram below shows the valid iterator positions as red
arrows for a list containing four items:
- \image stliterators1.png
+ \image stliterators1.svg STL-style iterators point to items
Iterating backward with an STL-style iterator is done with reverse iterators:
diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc
index 2232b49bf23..5d357c65496 100644
--- a/src/corelib/doc/src/external-resources.qdoc
+++ b/src/corelib/doc/src/external-resources.qdoc
@@ -28,11 +28,6 @@
*/
/*!
- \externalpage https://marcmutz.wordpress.com/effective-qt/containers/#containers-qlist
- \title Pros and Cons of Using QList
-*/
-
-/*!
\externalpage https://marcmutz.wordpress.com/effective-qt/containers/
\title Understand the Qt Containers
*/
diff --git a/src/corelib/doc/src/java-style-iterators.qdoc b/src/corelib/doc/src/java-style-iterators.qdoc
index a0e5c53d633..fc1378bb718 100644
--- a/src/corelib/doc/src/java-style-iterators.qdoc
+++ b/src/corelib/doc/src/java-style-iterators.qdoc
@@ -70,7 +70,7 @@
\l{QListIterator::next()}{next()} and
\l{QListIterator::previous()}{previous()} on an iterator:
- \image javaiterators2.png Iterating to the next and previous items
+ \image javaiterators2.svg Iterating to the next and previous items
The following table summarizes the QListIterator API:
diff --git a/src/corelib/global/patches/tlexpected/0006-Namespace-TL_-macros-with-Q23_.patch b/src/corelib/global/patches/tlexpected/0006-Namespace-TL_-macros-with-Q23_.patch
new file mode 100644
index 00000000000..f3c45f07594
--- /dev/null
+++ b/src/corelib/global/patches/tlexpected/0006-Namespace-TL_-macros-with-Q23_.patch
@@ -0,0 +1,914 @@
+From 5676e5f83597dc1fb32b551c863633eff102e879 Mon Sep 17 00:00:00 2001
+From: Marc Mutz <[email protected]>
+Date: Thu, 27 Nov 2025 07:51:19 +0100
+Subject: [PATCH] Namespace TL_ macros with Q23_
+
+Change-Id: Ib5762ec8ebe81e0c750da84be29531b7179c5025
+---
+ src/corelib/global/qexpected_p.h | 312 +++++++++++++++----------------
+ 1 file changed, 156 insertions(+), 156 deletions(-)
+
+diff --git a/src/corelib/global/qexpected_p.h b/src/corelib/global/qexpected_p.h
+index 24ea5be1e5e..54bcae51102 100644
+--- a/src/corelib/global/qexpected_p.h
++++ b/src/corelib/global/qexpected_p.h
+@@ -16,8 +16,8 @@
+ // <http://creativecommons.org/publicdomain/zero/1.0/>.
+ ///
+
+-#ifndef TL_EXPECTED_HPP
+-#define TL_EXPECTED_HPP
++#ifndef Q23_TL_EXPECTED_HPP
++#define Q23_TL_EXPECTED_HPP
+
+ //
+ // W A R N I N G
+@@ -30,9 +30,9 @@
+ // We mean it.
+ //
+
+-#define TL_EXPECTED_VERSION_MAJOR 1
+-#define TL_EXPECTED_VERSION_MINOR 1
+-#define TL_EXPECTED_VERSION_PATCH 0
++#define Q23_TL_EXPECTED_VERSION_MAJOR 1
++#define Q23_TL_EXPECTED_VERSION_MINOR 1
++#define Q23_TL_EXPECTED_VERSION_PATCH 0
+
+ #include <QtCore/private/qglobal_p.h>
+ #include <QtCore/qassert.h>
+@@ -44,45 +44,45 @@
+ #include <type_traits>
+ #include <utility>
+
+-#define TL_ASSERT Q_ASSERT
++#define Q23_TL_ASSERT Q_ASSERT
+
+ #if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
+-#define TL_EXPECTED_EXCEPTIONS_ENABLED
++#define Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ #endif
+
+-#if defined(TL_EXPECTED_EXCEPTIONS_ENABLED) && defined(QT_NO_EXCEPTIONS)
+-# undef TL_EXPECTED_EXCEPTIONS_ENABLED
++#if defined(Q23_TL_EXPECTED_EXCEPTIONS_ENABLED) && defined(QT_NO_EXCEPTIONS)
++# undef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ #endif
+
+ #if (defined(_MSC_VER) && _MSC_VER == 1900)
+-#define TL_EXPECTED_MSVC2015
+-#define TL_EXPECTED_MSVC2015_CONSTEXPR
++#define Q23_TL_EXPECTED_MSVC2015
++#define Q23_TL_EXPECTED_MSVC2015_CONSTEXPR
+ #else
+-#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
++#define Q23_TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
+ #endif
+
+ #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
+ !defined(__clang__))
+-#define TL_EXPECTED_GCC49
++#define Q23_TL_EXPECTED_GCC49
+ #endif
+
+ #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
+ !defined(__clang__))
+-#define TL_EXPECTED_GCC54
++#define Q23_TL_EXPECTED_GCC54
+ #endif
+
+ #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
+ !defined(__clang__))
+-#define TL_EXPECTED_GCC55
++#define Q23_TL_EXPECTED_GCC55
+ #endif
+
+-#if !defined(TL_ASSERT)
++#if !defined(Q23_TL_ASSERT)
+ //can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
+-#if (TL_CPLUSPLUS > 201103L) && !defined(TL_EXPECTED_GCC49)
++#if (Q23_TL_CPLUSPLUS > 201103L) && !defined(Q23_TL_EXPECTED_GCC49)
+ #include <cassert>
+-#define TL_ASSERT(x) assert(x)
++#define Q23_TL_ASSERT(x) assert(x)
+ #else
+-#define TL_ASSERT(x)
++#define Q23_TL_ASSERT(x)
+ #endif
+ #endif
+
+@@ -90,22 +90,22 @@
+ !defined(__clang__))
+ // GCC < 5 doesn't support overloading on const&& for member functions
+
+-#define TL_EXPECTED_NO_CONSTRR
++#define Q23_TL_EXPECTED_NO_CONSTRR
+ // GCC < 5 doesn't support some standard C++11 type traits
+-#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ std::has_trivial_copy_constructor<T>
+-#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+ std::has_trivial_copy_assign<T>
+
+ // This one will be different for GCC 5.7 if it's ever supported
+-#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
+ std::is_trivially_destructible<T>
+
+ // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
+ // std::vector for non-copyable types
+ #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
+-#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+-#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
++#ifndef Q23_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
++#define Q23_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+ QT_BEGIN_NAMESPACE
+ namespace q23 {
+ namespace detail {
+@@ -121,50 +121,50 @@ struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
+ QT_END_NAMESPACE
+ #endif
+
+-#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ q23::detail::is_trivially_copy_constructible<T>
+-#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+ std::is_trivially_copy_assignable<T>
+-#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
+ std::is_trivially_destructible<T>
+ #else
+-#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ std::is_trivially_copy_constructible<T>
+-#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+ std::is_trivially_copy_assignable<T>
+-#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
++#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
+ std::is_trivially_destructible<T>
+ #endif
+
+ #ifdef _MSVC_LANG
+-#define TL_CPLUSPLUS _MSVC_LANG
++#define Q23_TL_CPLUSPLUS _MSVC_LANG
+ #else
+-#define TL_CPLUSPLUS __cplusplus
++#define Q23_TL_CPLUSPLUS __cplusplus
+ #endif
+
+-#if TL_CPLUSPLUS > 201103L
+-#define TL_EXPECTED_CXX14
++#if Q23_TL_CPLUSPLUS > 201103L
++#define Q23_TL_EXPECTED_CXX14
+ #endif
+
+-#ifdef TL_EXPECTED_GCC49
+-#define TL_EXPECTED_GCC49_CONSTEXPR
++#ifdef Q23_TL_EXPECTED_GCC49
++#define Q23_TL_EXPECTED_GCC49_CONSTEXPR
+ #else
+-#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
++#define Q23_TL_EXPECTED_GCC49_CONSTEXPR constexpr
+ #endif
+
+-#if (TL_CPLUSPLUS == 201103L || defined(TL_EXPECTED_MSVC2015) || \
+- defined(TL_EXPECTED_GCC49))
+-#define TL_EXPECTED_11_CONSTEXPR
++#if (Q23_TL_CPLUSPLUS == 201103L || defined(Q23_TL_EXPECTED_MSVC2015) || \
++ defined(Q23_TL_EXPECTED_GCC49))
++#define Q23_TL_EXPECTED_11_CONSTEXPR
+ #else
+-#define TL_EXPECTED_11_CONSTEXPR constexpr
++#define Q23_TL_EXPECTED_11_CONSTEXPR constexpr
+ #endif
+
+ QT_BEGIN_NAMESPACE
+ namespace q23 {
+ template <class T, class E> class expected;
+
+-#ifndef TL_MONOSTATE_INPLACE_MUTEX
+-#define TL_MONOSTATE_INPLACE_MUTEX
++#ifndef Q23_TL_MONOSTATE_INPLACE_MUTEX
++#define Q23_TL_MONOSTATE_INPLACE_MUTEX
+ class monostate {};
+
+ struct in_place_t {
+@@ -196,8 +196,8 @@ public:
+ : m_val(l, std::forward<Args>(args)...) {}
+
+ constexpr const E &error() const & { return m_val; }
+- TL_EXPECTED_11_CONSTEXPR E &error() & { return m_val; }
+- TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(m_val); }
++ Q23_TL_EXPECTED_11_CONSTEXPR E &error() & { return m_val; }
++ Q23_TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(m_val); }
+ constexpr const E &&error() const && { return std::move(m_val); }
+
+ private:
+@@ -245,8 +245,8 @@ static constexpr unexpect_t unexpect{};
+
+ namespace detail {
+ template <typename E>
+-[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++[[noreturn]] Q23_TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ throw std::forward<E>(e);
+ #else
+ (void)e;
+@@ -258,8 +258,8 @@ template <typename E>
+ #endif
+ }
+
+-#ifndef TL_TRAITS_MUTEX
+-#define TL_TRAITS_MUTEX
++#ifndef Q23_TL_TRAITS_MUTEX
++#define Q23_TL_TRAITS_MUTEX
+ // C++14-style aliases for brevity
+ template <class T> using remove_const_t = typename std::remove_const<T>::type;
+ template <class T>
+@@ -278,13 +278,13 @@ struct conjunction<B, Bs...>
+ : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
+
+ #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
+-#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
++#define Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+ #endif
+
+ // In C++11 mode, there's an issue in libc++'s std::mem_fn
+ // which results in a hard-error when using it in a noexcept expression
+ // in some cases. This is a check to workaround the common failing case.
+-#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
++#ifdef Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+ template <class T>
+ struct is_pointer_to_non_const_member_func : std::false_type {};
+ template <class T, class Ret, class... Args>
+@@ -315,7 +315,7 @@ template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
+ // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
+ template <
+ typename Fn, typename... Args,
+-#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
++#ifdef Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+ typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
+ is_const_or_const_ref<Args...>::value)>,
+ #endif
+@@ -574,7 +574,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
+ // T is trivial, E is not.
+ template <class T, class E> struct expected_storage_base<T, E, true, false> {
+ constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
+- TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
++ Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
+ : m_no_init(), m_has_val(false) {}
+
+ template <class... Args,
+@@ -675,7 +675,7 @@ template <class E> struct expected_storage_base<void, E, false, true> {
+ #if __GNUC__ <= 5
+ //no constexpr for GCC 4/5 bug
+ #else
+- TL_EXPECTED_MSVC2015_CONSTEXPR
++ Q23_TL_EXPECTED_MSVC2015_CONSTEXPR
+ #endif
+ expected_storage_base() : m_has_val(true) {}
+
+@@ -770,7 +770,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
+ this->m_has_val = false;
+ }
+
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+
+ // These assign overloads ensure that the most efficient assignment
+ // implementation is used while maintaining the strong exception guarantee.
+@@ -820,7 +820,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
+ auto tmp = std::move(geterr());
+ geterr().~unexpected<E>();
+
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ construct(rhs.get());
+ } catch (...) {
+@@ -855,7 +855,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
+ if (!this->m_has_val && rhs.m_has_val) {
+ auto tmp = std::move(geterr());
+ geterr().~unexpected<E>();
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ construct(std::move(rhs).get());
+ } catch (...) {
+@@ -911,27 +911,27 @@ struct expected_operations_base : expected_storage_base<T, E> {
+
+ bool has_value() const { return this->m_has_val; }
+
+- TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
++ Q23_TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
+ constexpr const T &get() const & { return this->m_val; }
+- TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
+-#ifndef TL_EXPECTED_NO_CONSTRR
++ Q23_TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ constexpr const T &&get() const && { return std::move(this->m_val); }
+ #endif
+
+- TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
++ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
+ return this->m_unexpect;
+ }
+ constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
+- TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
++ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
+ return std::move(this->m_unexpect);
+ }
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ constexpr const unexpected<E> &&geterr() const && {
+ return std::move(this->m_unexpect);
+ }
+ #endif
+
+- TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
++ Q23_TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
+ };
+
+ // This base class provides some handy member functions which can be used in
+@@ -971,20 +971,20 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
+
+ bool has_value() const { return this->m_has_val; }
+
+- TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
++ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
+ return this->m_unexpect;
+ }
+ constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
+- TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
++ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
+ return std::move(this->m_unexpect);
+ }
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ constexpr const unexpected<E> &&geterr() const && {
+ return std::move(this->m_unexpect);
+ }
+ #endif
+
+- TL_EXPECTED_11_CONSTEXPR void destroy_val() {
++ Q23_TL_EXPECTED_11_CONSTEXPR void destroy_val() {
+ // no-op
+ }
+ };
+@@ -992,8 +992,8 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
+ // This class manages conditionally having a trivial copy constructor
+ // This specialization is for when T and E are trivially copy constructible
+ template <class T, class E,
+- bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
+- value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value,
++ bool = is_void_or<T, Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
++ value &&Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value,
+ bool = (is_copy_constructible_or_void<T>::value &&
+ std::is_copy_constructible<E>::value)>
+ struct expected_copy_base : expected_operations_base<T, E> {
+@@ -1025,7 +1025,7 @@ struct expected_copy_base<T, E, false, true> : expected_operations_base<T, E> {
+ // doesn't implement an analogue to std::is_trivially_move_constructible. We
+ // have to make do with a non-trivial move constructor even if T is trivially
+ // move constructible
+-#ifndef TL_EXPECTED_GCC49
++#ifndef Q23_TL_EXPECTED_GCC49
+ template <class T, class E,
+ bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value
+ &&std::is_trivially_move_constructible<E>::value>
+@@ -1058,12 +1058,12 @@ struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
+ // This class manages conditionally having a trivial copy assignment operator
+ template <class T, class E,
+ bool = is_void_or<
+- T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
+- TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
+- TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
+- &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
+- &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
+- &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value,
++ T, conjunction<Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
++ Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
++ Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
++ &&Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
++ &&Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
++ &&Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value,
+ bool = (is_copy_constructible_or_void<T>::value &&
+ std::is_copy_constructible<E>::value &&
+ is_copy_assignable_or_void<T>::value &&
+@@ -1093,7 +1093,7 @@ struct expected_copy_assign_base<T, E, false, true> : expected_move_base<T, E> {
+ // doesn't implement an analogue to std::is_trivially_move_assignable. We have
+ // to make do with a non-trivial move assignment operator even if T is trivially
+ // move assignable
+-#ifndef TL_EXPECTED_GCC49
++#ifndef Q23_TL_EXPECTED_GCC49
+ template <class T, class E,
+ bool =
+ is_void_or<T, conjunction<std::is_trivially_destructible<T>,
+@@ -1330,10 +1330,10 @@ class expected : private detail::expected_move_assign_base<T, E>,
+
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR U &val() {
++ Q23_TL_EXPECTED_11_CONSTEXPR U &val() {
+ return this->m_val;
+ }
+- TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
++ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
+
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+@@ -1350,19 +1350,19 @@ public:
+ typedef E error_type;
+ typedef unexpected<E> unexpected_type;
+
+-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
++#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
++ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
+ return and_then_impl(*this, std::forward<F>(f));
+ }
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
+ return and_then_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F> constexpr auto and_then(F &&f) const & {
+ return and_then_impl(*this, std::forward<F>(f));
+ }
+
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ template <class F> constexpr auto and_then(F &&f) const && {
+ return and_then_impl(std::move(*this), std::forward<F>(f));
+ }
+@@ -1370,13 +1370,13 @@ public:
+
+ #else
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR auto
++ Q23_TL_EXPECTED_11_CONSTEXPR auto
+ and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
+ std::forward<F>(f))) {
+ return and_then_impl(*this, std::forward<F>(f));
+ }
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR auto
++ Q23_TL_EXPECTED_11_CONSTEXPR auto
+ and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
+ std::forward<F>(f))) {
+ return and_then_impl(std::move(*this), std::forward<F>(f));
+@@ -1387,7 +1387,7 @@ public:
+ return and_then_impl(*this, std::forward<F>(f));
+ }
+
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ template <class F>
+ constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
+ std::declval<expected const &&>(), std::forward<F>(f))) {
+@@ -1396,12 +1396,12 @@ public:
+ #endif
+ #endif
+
+-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
++#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
++ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F> constexpr auto map(F &&f) const & {
+@@ -1412,13 +1412,13 @@ public:
+ }
+ #else
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
+ std::declval<expected &>(), std::declval<F &&>()))
+ map(F &&f) & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
+ std::declval<F &&>()))
+ map(F &&f) && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+@@ -1430,7 +1430,7 @@ public:
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ template <class F>
+ constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
+ std::declval<F &&>()))
+@@ -1440,12 +1440,12 @@ public:
+ #endif
+ #endif
+
+-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
++#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
++ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F> constexpr auto transform(F &&f) const & {
+@@ -1456,13 +1456,13 @@ public:
+ }
+ #else
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
+ std::declval<expected &>(), std::declval<F &&>()))
+ transform(F &&f) & {
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
+ std::declval<F &&>()))
+ transform(F &&f) && {
+ return expected_map_impl(std::move(*this), std::forward<F>(f));
+@@ -1474,7 +1474,7 @@ public:
+ return expected_map_impl(*this, std::forward<F>(f));
+ }
+
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ template <class F>
+ constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
+ std::declval<F &&>()))
+@@ -1484,12 +1484,12 @@ public:
+ #endif
+ #endif
+
+-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
++#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
++ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F> constexpr auto map_error(F &&f) const & {
+@@ -1500,13 +1500,13 @@ public:
+ }
+ #else
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
+ std::declval<F &&>()))
+ map_error(F &&f) & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
+ std::declval<F &&>()))
+ map_error(F &&f) && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+@@ -1518,7 +1518,7 @@ public:
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ template <class F>
+ constexpr decltype(map_error_impl(std::declval<const expected &&>(),
+ std::declval<F &&>()))
+@@ -1527,12 +1527,12 @@ public:
+ }
+ #endif
+ #endif
+-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
++#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
++ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
++ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+ }
+ template <class F> constexpr auto transform_error(F &&f) const & {
+@@ -1543,13 +1543,13 @@ public:
+ }
+ #else
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
+ std::declval<F &&>()))
+ transform_error(F &&f) & {
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+ template <class F>
+- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
++ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
+ std::declval<F &&>()))
+ transform_error(F &&f) && {
+ return map_error_impl(std::move(*this), std::forward<F>(f));
+@@ -1561,7 +1561,7 @@ public:
+ return map_error_impl(*this, std::forward<F>(f));
+ }
+
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ template <class F>
+ constexpr decltype(map_error_impl(std::declval<const expected &&>(),
+ std::declval<F &&>()))
+@@ -1570,11 +1570,11 @@ public:
+ }
+ #endif
+ #endif
+- template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
++ template <class F> expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
+ return or_else_impl(*this, std::forward<F>(f));
+ }
+
+- template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
++ template <class F> expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
+ return or_else_impl(std::move(*this), std::forward<F>(f));
+ }
+
+@@ -1582,7 +1582,7 @@ public:
+ return or_else_impl(*this, std::forward<F>(f));
+ }
+
+-#ifndef TL_EXPECTED_NO_CONSTRR
++#ifndef Q23_TL_EXPECTED_NO_CONSTRR
+ template <class F> expected constexpr or_else(F &&f) const && {
+ return or_else_impl(std::move(*this), std::forward<F>(f));
+ }
+@@ -1664,7 +1664,7 @@ public:
+ nullptr,
+ detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
+ * = nullptr>
+- explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
++ explicit Q23_TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
+ : ctor_base(detail::default_constructor_tag{}) {
+ if (rhs.has_value()) {
+ this->construct(*rhs);
+@@ -1679,7 +1679,7 @@ public:
+ nullptr,
+ detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
+ * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
++ Q23_TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
+ : ctor_base(detail::default_constructor_tag{}) {
+ if (rhs.has_value()) {
+ this->construct(*rhs);
+@@ -1693,7 +1693,7 @@ public:
+ detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
+ std::is_convertible<G &&, E>::value)> * = nullptr,
+ detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
+- explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
++ explicit Q23_TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
+ : ctor_base(detail::default_constructor_tag{}) {
+ if (rhs.has_value()) {
+ this->construct(std::move(*rhs));
+@@ -1707,7 +1707,7 @@ public:
+ detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
+ std::is_convertible<G &&, E>::value)> * = nullptr,
+ detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
++ Q23_TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
+ : ctor_base(detail::default_constructor_tag{}) {
+ if (rhs.has_value()) {
+ this->construct(std::move(*rhs));
+@@ -1720,14 +1720,14 @@ public:
+ class U = T,
+ detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
+ detail::expected_enable_forward_value<T, E, U> * = nullptr>
+- explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
++ explicit Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
+ : expected(in_place, std::forward<U>(v)) {}
+
+ template <
+ class U = T,
+ detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
+ detail::expected_enable_forward_value<T, E, U> * = nullptr>
+- TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
++ Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
+ : expected(in_place, std::forward<U>(v)) {}
+
+ template <
+@@ -1773,7 +1773,7 @@ public:
+ auto tmp = std::move(err());
+ err().~unexpected<E>();
+
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ ::new (valptr()) T(std::forward<U>(v));
+ this->m_has_val = true;
+@@ -1842,7 +1842,7 @@ public:
+ auto tmp = std::move(err());
+ err().~unexpected<E>();
+
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ ::new (valptr()) T(std::forward<Args>(args)...);
+ this->m_has_val = true;
+@@ -1882,7 +1882,7 @@ public:
+ auto tmp = std::move(err());
+ err().~unexpected<E>();
+
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ ::new (valptr()) T(il, std::forward<Args>(args)...);
+ this->m_has_val = true;
+@@ -1943,7 +1943,7 @@ private:
+ move_constructing_e_can_throw) {
+ auto temp = std::move(val());
+ val().~T();
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ ::new (errptr()) unexpected_type(std::move(rhs.err()));
+ rhs.err().~unexpected_type();
+@@ -1966,7 +1966,7 @@ private:
+ e_is_nothrow_move_constructible) {
+ auto temp = std::move(rhs.err());
+ rhs.err().~unexpected_type();
+-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
++#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
+ try {
+ ::new (rhs.valptr()) T(std::move(val()));
+ val().~T();
+@@ -2008,36 +2008,36 @@ public:
+ }
+
+ constexpr const T *operator->() const {
+- TL_ASSERT(has_value());
++ Q23_TL_ASSERT(has_value());
+ return valptr();
+ }
+- TL_EXPECTED_11_CONSTEXPR T *operator->() {
+- TL_ASSERT(has_value());
++ Q23_TL_EXPECTED_11_CONSTEXPR T *operator->() {
++ Q23_TL_ASSERT(has_value());
+ return valptr();
+ }
+
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+ constexpr const U &operator*() const & {
+- TL_ASSERT(has_value());
++ Q23_TL_ASSERT(has_value());
+ return val();
+ }
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR U &operator*() & {
+- TL_ASSERT(has_value());
++ Q23_TL_EXPECTED_11_CONSTEXPR U &operator*() & {
++ Q23_TL_ASSERT(has_value());
+ return val();
+ }
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+ constexpr const U &&operator*() const && {
+- TL_ASSERT(has_value());
++ Q23_TL_ASSERT(has_value());
+ return std::move(val());
+ }
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
+- TL_ASSERT(has_value());
++ Q23_TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
++ Q23_TL_ASSERT(has_value());
+ return std::move(val());
+ }
+
+@@ -2046,47 +2046,47 @@ public:
+
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR const U &value() const & {
++ Q23_TL_EXPECTED_11_CONSTEXPR const U &value() const & {
+ if (!has_value())
+ detail::throw_exception(bad_expected_access<E>(err().error()));
+ return val();
+ }
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR U &value() & {
++ Q23_TL_EXPECTED_11_CONSTEXPR U &value() & {
+ if (!has_value())
+ detail::throw_exception(bad_expected_access<E>(err().error()));
+ return val();
+ }
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
++ Q23_TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
+ if (!has_value())
+ detail::throw_exception(bad_expected_access<E>(std::move(err()).error()));
+ return std::move(val());
+ }
+ template <class U = T,
+ detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
+- TL_EXPECTED_11_CONSTEXPR U &&value() && {
++ Q23_TL_EXPECTED_11_CONSTEXPR U &&value() && {
+ if (!has_value())
+ detail::throw_exception(bad_expected_access<E>(std::move(err()).error()));
+ return std::move(val());
+ }
+
+ constexpr const E &error() const & {
+- TL_ASSERT(!has_value());
++ Q23_TL_ASSERT(!has_value());
+ return err().error();
+ }
+- TL_EXPECTED_11_CONSTEXPR E &error() & {
+- TL_ASSERT(!has_value());
++ Q23_TL_EXPECTED_11_CONSTEXPR E &error() & {
++ Q23_TL_ASSERT(!has_value());
+ return err().error();
+ }
+ constexpr const E &&error() const && {
+- TL_ASSERT(!has_value());
++ Q23_TL_ASSERT(!has_value());
+ return std::move(err().error());
+ }
+- TL_EXPECTED_11_CONSTEXPR E &&error() && {
+- TL_ASSERT(!has_value());
++ Q23_TL_EXPECTED_11_CONSTEXPR E &&error() && {
++ Q23_TL_ASSERT(!has_value());
+ return std::move(err().error());
+ }
+
+@@ -2096,7 +2096,7 @@ public:
+ "T must be copy-constructible and convertible to from U&&");
+ return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
+ }
+- template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
++ template <class U> Q23_TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
+ static_assert(std::is_move_constructible<T>::value &&
+ std::is_convertible<U &&, T>::value,
+ "T must be move-constructible and convertible to from U&&");
+@@ -2109,7 +2109,7 @@ template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type;
+ template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
+ template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
+
+-#ifdef TL_EXPECTED_CXX14
++#ifdef Q23_TL_EXPECTED_CXX14
+ template <class Exp, class F,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ class Ret = decltype(detail::invoke(std::declval<F>(),
+@@ -2156,7 +2156,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
+ }
+ #endif
+
+-#ifdef TL_EXPECTED_CXX14
++#ifdef Q23_TL_EXPECTED_CXX14
+ template <class Exp, class F,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ class Ret = decltype(detail::invoke(std::declval<F>(),
+@@ -2266,8 +2266,8 @@ auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
+ }
+ #endif
+
+-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
+- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
++#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
++ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
+ template <class Exp, class F,
+ detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
+ class Ret = decltype(detail::invoke(std::declval<F>(),
+@@ -2382,7 +2382,7 @@ auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
+ }
+ #endif
+
+-#ifdef TL_EXPECTED_CXX14
++#ifdef Q23_TL_EXPECTED_CXX14
+ template <class Exp, class F,
+ class Ret = decltype(detail::invoke(std::declval<F>(),
+ std::declval<Exp>().error())),
+--
+2.25.1
+
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 0b42af7686c..b2d79cca603 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -1404,7 +1404,7 @@ static_assert(!std::is_convertible_v<std::nullptr_t, bool>,
#if defined(__cplusplus)
#ifdef __cpp_constinit
-# if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
+# if defined(Q_CC_MSVC) && _MSC_VER < 1940 && !defined(Q_CC_CLANG)
// https://developercommunity.visualstudio.com/t/C:-constinit-for-an-optional-fails-if-/1406069
# define Q_CONSTINIT
# else
diff --git a/src/corelib/global/qexpected_p.h b/src/corelib/global/qexpected_p.h
index 24ea5be1e5e..54bcae51102 100644
--- a/src/corelib/global/qexpected_p.h
+++ b/src/corelib/global/qexpected_p.h
@@ -16,8 +16,8 @@
// <http://creativecommons.org/publicdomain/zero/1.0/>.
///
-#ifndef TL_EXPECTED_HPP
-#define TL_EXPECTED_HPP
+#ifndef Q23_TL_EXPECTED_HPP
+#define Q23_TL_EXPECTED_HPP
//
// W A R N I N G
@@ -30,9 +30,9 @@
// We mean it.
//
-#define TL_EXPECTED_VERSION_MAJOR 1
-#define TL_EXPECTED_VERSION_MINOR 1
-#define TL_EXPECTED_VERSION_PATCH 0
+#define Q23_TL_EXPECTED_VERSION_MAJOR 1
+#define Q23_TL_EXPECTED_VERSION_MINOR 1
+#define Q23_TL_EXPECTED_VERSION_PATCH 0
#include <QtCore/private/qglobal_p.h>
#include <QtCore/qassert.h>
@@ -44,45 +44,45 @@
#include <type_traits>
#include <utility>
-#define TL_ASSERT Q_ASSERT
+#define Q23_TL_ASSERT Q_ASSERT
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
-#define TL_EXPECTED_EXCEPTIONS_ENABLED
+#define Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
#endif
-#if defined(TL_EXPECTED_EXCEPTIONS_ENABLED) && defined(QT_NO_EXCEPTIONS)
-# undef TL_EXPECTED_EXCEPTIONS_ENABLED
+#if defined(Q23_TL_EXPECTED_EXCEPTIONS_ENABLED) && defined(QT_NO_EXCEPTIONS)
+# undef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
#endif
#if (defined(_MSC_VER) && _MSC_VER == 1900)
-#define TL_EXPECTED_MSVC2015
-#define TL_EXPECTED_MSVC2015_CONSTEXPR
+#define Q23_TL_EXPECTED_MSVC2015
+#define Q23_TL_EXPECTED_MSVC2015_CONSTEXPR
#else
-#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
+#define Q23_TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
#endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
-#define TL_EXPECTED_GCC49
+#define Q23_TL_EXPECTED_GCC49
#endif
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
!defined(__clang__))
-#define TL_EXPECTED_GCC54
+#define Q23_TL_EXPECTED_GCC54
#endif
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
!defined(__clang__))
-#define TL_EXPECTED_GCC55
+#define Q23_TL_EXPECTED_GCC55
#endif
-#if !defined(TL_ASSERT)
+#if !defined(Q23_TL_ASSERT)
//can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
-#if (TL_CPLUSPLUS > 201103L) && !defined(TL_EXPECTED_GCC49)
+#if (Q23_TL_CPLUSPLUS > 201103L) && !defined(Q23_TL_EXPECTED_GCC49)
#include <cassert>
-#define TL_ASSERT(x) assert(x)
+#define Q23_TL_ASSERT(x) assert(x)
#else
-#define TL_ASSERT(x)
+#define Q23_TL_ASSERT(x)
#endif
#endif
@@ -90,22 +90,22 @@
!defined(__clang__))
// GCC < 5 doesn't support overloading on const&& for member functions
-#define TL_EXPECTED_NO_CONSTRR
+#define Q23_TL_EXPECTED_NO_CONSTRR
// GCC < 5 doesn't support some standard C++11 type traits
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
std::has_trivial_copy_constructor<T>
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
std::has_trivial_copy_assign<T>
// This one will be different for GCC 5.7 if it's ever supported
-#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
std::is_trivially_destructible<T>
// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
// std::vector for non-copyable types
#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
-#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
-#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+#ifndef Q23_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+#define Q23_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
QT_BEGIN_NAMESPACE
namespace q23 {
namespace detail {
@@ -121,50 +121,50 @@ struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
QT_END_NAMESPACE
#endif
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
q23::detail::is_trivially_copy_constructible<T>
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
std::is_trivially_copy_assignable<T>
-#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
std::is_trivially_destructible<T>
#else
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
std::is_trivially_copy_constructible<T>
-#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
std::is_trivially_copy_assignable<T>
-#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
+#define Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
std::is_trivially_destructible<T>
#endif
#ifdef _MSVC_LANG
-#define TL_CPLUSPLUS _MSVC_LANG
+#define Q23_TL_CPLUSPLUS _MSVC_LANG
#else
-#define TL_CPLUSPLUS __cplusplus
+#define Q23_TL_CPLUSPLUS __cplusplus
#endif
-#if TL_CPLUSPLUS > 201103L
-#define TL_EXPECTED_CXX14
+#if Q23_TL_CPLUSPLUS > 201103L
+#define Q23_TL_EXPECTED_CXX14
#endif
-#ifdef TL_EXPECTED_GCC49
-#define TL_EXPECTED_GCC49_CONSTEXPR
+#ifdef Q23_TL_EXPECTED_GCC49
+#define Q23_TL_EXPECTED_GCC49_CONSTEXPR
#else
-#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
+#define Q23_TL_EXPECTED_GCC49_CONSTEXPR constexpr
#endif
-#if (TL_CPLUSPLUS == 201103L || defined(TL_EXPECTED_MSVC2015) || \
- defined(TL_EXPECTED_GCC49))
-#define TL_EXPECTED_11_CONSTEXPR
+#if (Q23_TL_CPLUSPLUS == 201103L || defined(Q23_TL_EXPECTED_MSVC2015) || \
+ defined(Q23_TL_EXPECTED_GCC49))
+#define Q23_TL_EXPECTED_11_CONSTEXPR
#else
-#define TL_EXPECTED_11_CONSTEXPR constexpr
+#define Q23_TL_EXPECTED_11_CONSTEXPR constexpr
#endif
QT_BEGIN_NAMESPACE
namespace q23 {
template <class T, class E> class expected;
-#ifndef TL_MONOSTATE_INPLACE_MUTEX
-#define TL_MONOSTATE_INPLACE_MUTEX
+#ifndef Q23_TL_MONOSTATE_INPLACE_MUTEX
+#define Q23_TL_MONOSTATE_INPLACE_MUTEX
class monostate {};
struct in_place_t {
@@ -196,8 +196,8 @@ public:
: m_val(l, std::forward<Args>(args)...) {}
constexpr const E &error() const & { return m_val; }
- TL_EXPECTED_11_CONSTEXPR E &error() & { return m_val; }
- TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(m_val); }
+ Q23_TL_EXPECTED_11_CONSTEXPR E &error() & { return m_val; }
+ Q23_TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(m_val); }
constexpr const E &&error() const && { return std::move(m_val); }
private:
@@ -245,8 +245,8 @@ static constexpr unexpect_t unexpect{};
namespace detail {
template <typename E>
-[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+[[noreturn]] Q23_TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
throw std::forward<E>(e);
#else
(void)e;
@@ -258,8 +258,8 @@ template <typename E>
#endif
}
-#ifndef TL_TRAITS_MUTEX
-#define TL_TRAITS_MUTEX
+#ifndef Q23_TL_TRAITS_MUTEX
+#define Q23_TL_TRAITS_MUTEX
// C++14-style aliases for brevity
template <class T> using remove_const_t = typename std::remove_const<T>::type;
template <class T>
@@ -278,13 +278,13 @@ struct conjunction<B, Bs...>
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
-#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+#define Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
#endif
// In C++11 mode, there's an issue in libc++'s std::mem_fn
// which results in a hard-error when using it in a noexcept expression
// in some cases. This is a check to workaround the common failing case.
-#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+#ifdef Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
template <class T>
struct is_pointer_to_non_const_member_func : std::false_type {};
template <class T, class Ret, class... Args>
@@ -315,7 +315,7 @@ template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
template <
typename Fn, typename... Args,
-#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+#ifdef Q23_TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
is_const_or_const_ref<Args...>::value)>,
#endif
@@ -574,7 +574,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
// T is trivial, E is not.
template <class T, class E> struct expected_storage_base<T, E, true, false> {
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
- TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
+ Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
: m_no_init(), m_has_val(false) {}
template <class... Args,
@@ -675,7 +675,7 @@ template <class E> struct expected_storage_base<void, E, false, true> {
#if __GNUC__ <= 5
//no constexpr for GCC 4/5 bug
#else
- TL_EXPECTED_MSVC2015_CONSTEXPR
+ Q23_TL_EXPECTED_MSVC2015_CONSTEXPR
#endif
expected_storage_base() : m_has_val(true) {}
@@ -770,7 +770,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
this->m_has_val = false;
}
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
// These assign overloads ensure that the most efficient assignment
// implementation is used while maintaining the strong exception guarantee.
@@ -820,7 +820,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
auto tmp = std::move(geterr());
geterr().~unexpected<E>();
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
try {
construct(rhs.get());
} catch (...) {
@@ -855,7 +855,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
if (!this->m_has_val && rhs.m_has_val) {
auto tmp = std::move(geterr());
geterr().~unexpected<E>();
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
try {
construct(std::move(rhs).get());
} catch (...) {
@@ -911,27 +911,27 @@ struct expected_operations_base : expected_storage_base<T, E> {
bool has_value() const { return this->m_has_val; }
- TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
+ Q23_TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
constexpr const T &get() const & { return this->m_val; }
- TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
-#ifndef TL_EXPECTED_NO_CONSTRR
+ Q23_TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
constexpr const T &&get() const && { return std::move(this->m_val); }
#endif
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
+ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
return this->m_unexpect;
}
constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
+ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
return std::move(this->m_unexpect);
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
constexpr const unexpected<E> &&geterr() const && {
return std::move(this->m_unexpect);
}
#endif
- TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
+ Q23_TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
};
// This base class provides some handy member functions which can be used in
@@ -971,20 +971,20 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
bool has_value() const { return this->m_has_val; }
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
+ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
return this->m_unexpect;
}
constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
+ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
return std::move(this->m_unexpect);
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
constexpr const unexpected<E> &&geterr() const && {
return std::move(this->m_unexpect);
}
#endif
- TL_EXPECTED_11_CONSTEXPR void destroy_val() {
+ Q23_TL_EXPECTED_11_CONSTEXPR void destroy_val() {
// no-op
}
};
@@ -992,8 +992,8 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
// This class manages conditionally having a trivial copy constructor
// This specialization is for when T and E are trivially copy constructible
template <class T, class E,
- bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
- value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value,
+ bool = is_void_or<T, Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
+ value &&Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value,
bool = (is_copy_constructible_or_void<T>::value &&
std::is_copy_constructible<E>::value)>
struct expected_copy_base : expected_operations_base<T, E> {
@@ -1025,7 +1025,7 @@ struct expected_copy_base<T, E, false, true> : expected_operations_base<T, E> {
// doesn't implement an analogue to std::is_trivially_move_constructible. We
// have to make do with a non-trivial move constructor even if T is trivially
// move constructible
-#ifndef TL_EXPECTED_GCC49
+#ifndef Q23_TL_EXPECTED_GCC49
template <class T, class E,
bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value
&&std::is_trivially_move_constructible<E>::value>
@@ -1058,12 +1058,12 @@ struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
// This class manages conditionally having a trivial copy assignment operator
template <class T, class E,
bool = is_void_or<
- T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
- TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
- TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
- &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
- &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
- &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value,
+ T, conjunction<Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
+ Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
+ Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
+ &&Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
+ &&Q23_TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
+ &&Q23_TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value,
bool = (is_copy_constructible_or_void<T>::value &&
std::is_copy_constructible<E>::value &&
is_copy_assignable_or_void<T>::value &&
@@ -1093,7 +1093,7 @@ struct expected_copy_assign_base<T, E, false, true> : expected_move_base<T, E> {
// doesn't implement an analogue to std::is_trivially_move_assignable. We have
// to make do with a non-trivial move assignment operator even if T is trivially
// move assignable
-#ifndef TL_EXPECTED_GCC49
+#ifndef Q23_TL_EXPECTED_GCC49
template <class T, class E,
bool =
is_void_or<T, conjunction<std::is_trivially_destructible<T>,
@@ -1330,10 +1330,10 @@ class expected : private detail::expected_move_assign_base<T, E>,
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &val() {
+ Q23_TL_EXPECTED_11_CONSTEXPR U &val() {
return this->m_val;
}
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
+ Q23_TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
@@ -1350,19 +1350,19 @@ public:
typedef E error_type;
typedef unexpected<E> unexpected_type;
-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
+#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
+ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
return and_then_impl(*this, std::forward<F>(f));
}
- template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
return and_then_impl(std::move(*this), std::forward<F>(f));
}
template <class F> constexpr auto and_then(F &&f) const & {
return and_then_impl(*this, std::forward<F>(f));
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
template <class F> constexpr auto and_then(F &&f) const && {
return and_then_impl(std::move(*this), std::forward<F>(f));
}
@@ -1370,13 +1370,13 @@ public:
#else
template <class F>
- TL_EXPECTED_11_CONSTEXPR auto
+ Q23_TL_EXPECTED_11_CONSTEXPR auto
and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
std::forward<F>(f))) {
return and_then_impl(*this, std::forward<F>(f));
}
template <class F>
- TL_EXPECTED_11_CONSTEXPR auto
+ Q23_TL_EXPECTED_11_CONSTEXPR auto
and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
std::forward<F>(f))) {
return and_then_impl(std::move(*this), std::forward<F>(f));
@@ -1387,7 +1387,7 @@ public:
return and_then_impl(*this, std::forward<F>(f));
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
template <class F>
constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
std::declval<expected const &&>(), std::forward<F>(f))) {
@@ -1396,12 +1396,12 @@ public:
#endif
#endif
-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
+#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
+ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
return expected_map_impl(*this, std::forward<F>(f));
}
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
return expected_map_impl(std::move(*this), std::forward<F>(f));
}
template <class F> constexpr auto map(F &&f) const & {
@@ -1412,13 +1412,13 @@ public:
}
#else
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
std::declval<expected &>(), std::declval<F &&>()))
map(F &&f) & {
return expected_map_impl(*this, std::forward<F>(f));
}
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
std::declval<F &&>()))
map(F &&f) && {
return expected_map_impl(std::move(*this), std::forward<F>(f));
@@ -1430,7 +1430,7 @@ public:
return expected_map_impl(*this, std::forward<F>(f));
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
template <class F>
constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
std::declval<F &&>()))
@@ -1440,12 +1440,12 @@ public:
#endif
#endif
-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
+#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
+ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
return expected_map_impl(*this, std::forward<F>(f));
}
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
return expected_map_impl(std::move(*this), std::forward<F>(f));
}
template <class F> constexpr auto transform(F &&f) const & {
@@ -1456,13 +1456,13 @@ public:
}
#else
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
std::declval<expected &>(), std::declval<F &&>()))
transform(F &&f) & {
return expected_map_impl(*this, std::forward<F>(f));
}
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
std::declval<F &&>()))
transform(F &&f) && {
return expected_map_impl(std::move(*this), std::forward<F>(f));
@@ -1474,7 +1474,7 @@ public:
return expected_map_impl(*this, std::forward<F>(f));
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
template <class F>
constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
std::declval<F &&>()))
@@ -1484,12 +1484,12 @@ public:
#endif
#endif
-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
+#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
+ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
return map_error_impl(*this, std::forward<F>(f));
}
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
return map_error_impl(std::move(*this), std::forward<F>(f));
}
template <class F> constexpr auto map_error(F &&f) const & {
@@ -1500,13 +1500,13 @@ public:
}
#else
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
std::declval<F &&>()))
map_error(F &&f) & {
return map_error_impl(*this, std::forward<F>(f));
}
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
std::declval<F &&>()))
map_error(F &&f) && {
return map_error_impl(std::move(*this), std::forward<F>(f));
@@ -1518,7 +1518,7 @@ public:
return map_error_impl(*this, std::forward<F>(f));
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
template <class F>
constexpr decltype(map_error_impl(std::declval<const expected &&>(),
std::declval<F &&>()))
@@ -1527,12 +1527,12 @@ public:
}
#endif
#endif
-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
+#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
+ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
return map_error_impl(*this, std::forward<F>(f));
}
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
+ template <class F> Q23_TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
return map_error_impl(std::move(*this), std::forward<F>(f));
}
template <class F> constexpr auto transform_error(F &&f) const & {
@@ -1543,13 +1543,13 @@ public:
}
#else
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
std::declval<F &&>()))
transform_error(F &&f) & {
return map_error_impl(*this, std::forward<F>(f));
}
template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
+ Q23_TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
std::declval<F &&>()))
transform_error(F &&f) && {
return map_error_impl(std::move(*this), std::forward<F>(f));
@@ -1561,7 +1561,7 @@ public:
return map_error_impl(*this, std::forward<F>(f));
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
template <class F>
constexpr decltype(map_error_impl(std::declval<const expected &&>(),
std::declval<F &&>()))
@@ -1570,11 +1570,11 @@ public:
}
#endif
#endif
- template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
+ template <class F> expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
return or_else_impl(*this, std::forward<F>(f));
}
- template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
+ template <class F> expected Q23_TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
return or_else_impl(std::move(*this), std::forward<F>(f));
}
@@ -1582,7 +1582,7 @@ public:
return or_else_impl(*this, std::forward<F>(f));
}
-#ifndef TL_EXPECTED_NO_CONSTRR
+#ifndef Q23_TL_EXPECTED_NO_CONSTRR
template <class F> expected constexpr or_else(F &&f) const && {
return or_else_impl(std::move(*this), std::forward<F>(f));
}
@@ -1664,7 +1664,7 @@ public:
nullptr,
detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
* = nullptr>
- explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
+ explicit Q23_TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
: ctor_base(detail::default_constructor_tag{}) {
if (rhs.has_value()) {
this->construct(*rhs);
@@ -1679,7 +1679,7 @@ public:
nullptr,
detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
* = nullptr>
- TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
+ Q23_TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
: ctor_base(detail::default_constructor_tag{}) {
if (rhs.has_value()) {
this->construct(*rhs);
@@ -1693,7 +1693,7 @@ public:
detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
std::is_convertible<G &&, E>::value)> * = nullptr,
detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
- explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
+ explicit Q23_TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
: ctor_base(detail::default_constructor_tag{}) {
if (rhs.has_value()) {
this->construct(std::move(*rhs));
@@ -1707,7 +1707,7 @@ public:
detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
std::is_convertible<G &&, E>::value)> * = nullptr,
detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
+ Q23_TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
: ctor_base(detail::default_constructor_tag{}) {
if (rhs.has_value()) {
this->construct(std::move(*rhs));
@@ -1720,14 +1720,14 @@ public:
class U = T,
detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
detail::expected_enable_forward_value<T, E, U> * = nullptr>
- explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
+ explicit Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
: expected(in_place, std::forward<U>(v)) {}
template <
class U = T,
detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
detail::expected_enable_forward_value<T, E, U> * = nullptr>
- TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
+ Q23_TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
: expected(in_place, std::forward<U>(v)) {}
template <
@@ -1773,7 +1773,7 @@ public:
auto tmp = std::move(err());
err().~unexpected<E>();
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
try {
::new (valptr()) T(std::forward<U>(v));
this->m_has_val = true;
@@ -1842,7 +1842,7 @@ public:
auto tmp = std::move(err());
err().~unexpected<E>();
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
try {
::new (valptr()) T(std::forward<Args>(args)...);
this->m_has_val = true;
@@ -1882,7 +1882,7 @@ public:
auto tmp = std::move(err());
err().~unexpected<E>();
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
try {
::new (valptr()) T(il, std::forward<Args>(args)...);
this->m_has_val = true;
@@ -1943,7 +1943,7 @@ private:
move_constructing_e_can_throw) {
auto temp = std::move(val());
val().~T();
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
try {
::new (errptr()) unexpected_type(std::move(rhs.err()));
rhs.err().~unexpected_type();
@@ -1966,7 +1966,7 @@ private:
e_is_nothrow_move_constructible) {
auto temp = std::move(rhs.err());
rhs.err().~unexpected_type();
-#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
+#ifdef Q23_TL_EXPECTED_EXCEPTIONS_ENABLED
try {
::new (rhs.valptr()) T(std::move(val()));
val().~T();
@@ -2008,36 +2008,36 @@ public:
}
constexpr const T *operator->() const {
- TL_ASSERT(has_value());
+ Q23_TL_ASSERT(has_value());
return valptr();
}
- TL_EXPECTED_11_CONSTEXPR T *operator->() {
- TL_ASSERT(has_value());
+ Q23_TL_EXPECTED_11_CONSTEXPR T *operator->() {
+ Q23_TL_ASSERT(has_value());
return valptr();
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
constexpr const U &operator*() const & {
- TL_ASSERT(has_value());
+ Q23_TL_ASSERT(has_value());
return val();
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &operator*() & {
- TL_ASSERT(has_value());
+ Q23_TL_EXPECTED_11_CONSTEXPR U &operator*() & {
+ Q23_TL_ASSERT(has_value());
return val();
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
constexpr const U &&operator*() const && {
- TL_ASSERT(has_value());
+ Q23_TL_ASSERT(has_value());
return std::move(val());
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
- TL_ASSERT(has_value());
+ Q23_TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
+ Q23_TL_ASSERT(has_value());
return std::move(val());
}
@@ -2046,47 +2046,47 @@ public:
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR const U &value() const & {
+ Q23_TL_EXPECTED_11_CONSTEXPR const U &value() const & {
if (!has_value())
detail::throw_exception(bad_expected_access<E>(err().error()));
return val();
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &value() & {
+ Q23_TL_EXPECTED_11_CONSTEXPR U &value() & {
if (!has_value())
detail::throw_exception(bad_expected_access<E>(err().error()));
return val();
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
+ Q23_TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
if (!has_value())
detail::throw_exception(bad_expected_access<E>(std::move(err()).error()));
return std::move(val());
}
template <class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &&value() && {
+ Q23_TL_EXPECTED_11_CONSTEXPR U &&value() && {
if (!has_value())
detail::throw_exception(bad_expected_access<E>(std::move(err()).error()));
return std::move(val());
}
constexpr const E &error() const & {
- TL_ASSERT(!has_value());
+ Q23_TL_ASSERT(!has_value());
return err().error();
}
- TL_EXPECTED_11_CONSTEXPR E &error() & {
- TL_ASSERT(!has_value());
+ Q23_TL_EXPECTED_11_CONSTEXPR E &error() & {
+ Q23_TL_ASSERT(!has_value());
return err().error();
}
constexpr const E &&error() const && {
- TL_ASSERT(!has_value());
+ Q23_TL_ASSERT(!has_value());
return std::move(err().error());
}
- TL_EXPECTED_11_CONSTEXPR E &&error() && {
- TL_ASSERT(!has_value());
+ Q23_TL_EXPECTED_11_CONSTEXPR E &&error() && {
+ Q23_TL_ASSERT(!has_value());
return std::move(err().error());
}
@@ -2096,7 +2096,7 @@ public:
"T must be copy-constructible and convertible to from U&&");
return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
}
- template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
+ template <class U> Q23_TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
static_assert(std::is_move_constructible<T>::value &&
std::is_convertible<U &&, T>::value,
"T must be move-constructible and convertible to from U&&");
@@ -2109,7 +2109,7 @@ template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type;
template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
-#ifdef TL_EXPECTED_CXX14
+#ifdef Q23_TL_EXPECTED_CXX14
template <class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
@@ -2156,7 +2156,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
}
#endif
-#ifdef TL_EXPECTED_CXX14
+#ifdef Q23_TL_EXPECTED_CXX14
template <class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
@@ -2266,8 +2266,8 @@ auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
}
#endif
-#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
+#if defined(Q23_TL_EXPECTED_CXX14) && !defined(Q23_TL_EXPECTED_GCC49) && \
+ !defined(Q23_TL_EXPECTED_GCC54) && !defined(Q23_TL_EXPECTED_GCC55)
template <class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(),
@@ -2382,7 +2382,7 @@ auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
}
#endif
-#ifdef TL_EXPECTED_CXX14
+#ifdef Q23_TL_EXPECTED_CXX14
template <class Exp, class F,
class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())),
diff --git a/src/corelib/global/qnumeric.h b/src/corelib/global/qnumeric.h
index 48e736ff124..db32ae73556 100644
--- a/src/corelib/global/qnumeric.h
+++ b/src/corelib/global/qnumeric.h
@@ -627,6 +627,27 @@ QT_WARNING_DISABLE_FLOAT_COMPARE
QT_WARNING_POP
+namespace QtPrivate {
+/*
+ A version of qFuzzyCompare that works for all values (qFuzzyCompare()
+ requires that neither argument is numerically 0).
+
+ It's private because we need a fix for the many qFuzzyCompare() uses that
+ ignore the precondition, even for older branches.
+
+ See QTBUG-142020 for discussion of a longer-term solution.
+*/
+template <typename T, typename S>
+[[nodiscard]] constexpr bool fuzzyCompare(const T &lhs, const S &rhs) noexcept
+{
+ static_assert(noexcept(qIsNull(lhs) && qIsNull(rhs) && qFuzzyIsNull(lhs - rhs) && qFuzzyCompare(lhs, rhs)),
+ "The operations qIsNull(), qFuzzyIsNull() and qFuzzyCompare() must be noexcept "
+ "for both argument types!");
+ return qIsNull(lhs) || qIsNull(rhs) ? qFuzzyIsNull(lhs - rhs) : qFuzzyCompare(lhs, rhs);
+}
+} // namespace QtPrivate
+
+
inline int qIntCast(double f) { return int(f); }
inline int qIntCast(float f) { return int(f); }
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index d27a71526d8..32364fa8eb4 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -486,6 +486,12 @@ const QOperatingSystemVersionBase QOperatingSystemVersion::Windows11_22H2;
*/
/*!
+ \variable QOperatingSystemVersion::Windows11_25H2
+ \brief a version corresponding to Windows 11 Version 25H2 (version 10.0.26200).
+ \since 6.11
+ */
+
+/*!
\variable QOperatingSystemVersion::OSXMavericks
\brief a version corresponding to OS X Mavericks (version 10.9).
\since 5.9
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
index 75801a7ddcf..99866692f8c 100644
--- a/src/corelib/global/qoperatingsystemversion.h
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -148,6 +148,7 @@ public:
static constexpr QOperatingSystemVersionBase Android14 { QOperatingSystemVersionBase::Android, 14, 0 };
static constexpr QOperatingSystemVersionBase Windows11_23H2 { QOperatingSystemVersionBase::Windows, 10, 0, 22631 };
static constexpr QOperatingSystemVersionBase Windows11_24H2 { QOperatingSystemVersionBase::Windows, 10, 0, 26100 };
+ static constexpr QOperatingSystemVersionBase Windows11_25H2 { QOperatingSystemVersionBase::Windows, 10, 0, 26200 };
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) && !defined(Q_QDOC)
};
diff --git a/src/corelib/global/qttranslation.qdoc b/src/corelib/global/qttranslation.qdoc
index 191b3777db6..c8b3764614e 100644
--- a/src/corelib/global/qttranslation.qdoc
+++ b/src/corelib/global/qttranslation.qdoc
@@ -179,7 +179,7 @@
\fn QString qTrId(const char *id, int n = -1)
\relates <QtTranslation>
\reentrant
- \since 6.9
+ \since 6.11
\brief The qTrId function is an alias for qtTrId.
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 0771c15584b..d3c398f0860 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -249,6 +249,12 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHand
}
/*!
+ \class QFSFileEnginePrivate
+ \inmodule QtCore
+ \internal
+*/
+
+/*!
Opens the file handle \a fh using the open mode \a flags.
*/
bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
diff --git a/src/corelib/io/qiooperation_p.h b/src/corelib/io/qiooperation_p.h
index 56845167ede..1486719a7e8 100644
--- a/src/corelib/io/qiooperation_p.h
+++ b/src/corelib/io/qiooperation_p.h
@@ -72,6 +72,9 @@ protected:
Q_DECLARE_PRIVATE(QIOOperation)
friend class QRandomAccessAsyncFilePrivate;
+ friend class QRandomAccessAsyncFileBackend;
+ friend class QRandomAccessAsyncFileNativeBackend;
+ friend class QRandomAccessAsyncFileThreadPoolBackend;
};
class Q_CORE_EXPORT QIOReadWriteOperationBase : public QIOOperation
@@ -86,6 +89,11 @@ protected:
QIOReadWriteOperationBase() = delete;
Q_DISABLE_COPY_MOVE(QIOReadWriteOperationBase)
explicit QIOReadWriteOperationBase(QIOOperationPrivate &dd, QObject *parent = nullptr);
+
+ friend class QRandomAccessAsyncFilePrivate;
+ friend class QRandomAccessAsyncFileBackend;
+ friend class QRandomAccessAsyncFileNativeBackend;
+ friend class QRandomAccessAsyncFileThreadPoolBackend;
};
class Q_CORE_EXPORT QIOReadOperation : public QIOReadWriteOperationBase
@@ -101,6 +109,9 @@ protected:
explicit QIOReadOperation(QIOOperationPrivate &dd, QObject *parent = nullptr);
friend class QRandomAccessAsyncFilePrivate;
+ friend class QRandomAccessAsyncFileBackend;
+ friend class QRandomAccessAsyncFileNativeBackend;
+ friend class QRandomAccessAsyncFileThreadPoolBackend;
};
class Q_CORE_EXPORT QIOWriteOperation : public QIOReadWriteOperationBase
@@ -116,6 +127,9 @@ protected:
explicit QIOWriteOperation(QIOOperationPrivate &dd, QObject *parent = nullptr);
friend class QRandomAccessAsyncFilePrivate;
+ friend class QRandomAccessAsyncFileBackend;
+ friend class QRandomAccessAsyncFileNativeBackend;
+ friend class QRandomAccessAsyncFileThreadPoolBackend;
};
class Q_CORE_EXPORT QIOVectoredReadOperation : public QIOReadWriteOperationBase
@@ -131,6 +145,9 @@ protected:
explicit QIOVectoredReadOperation(QIOOperationPrivate &dd, QObject *parent = nullptr);
friend class QRandomAccessAsyncFilePrivate;
+ friend class QRandomAccessAsyncFileBackend;
+ friend class QRandomAccessAsyncFileNativeBackend;
+ friend class QRandomAccessAsyncFileThreadPoolBackend;
};
class Q_CORE_EXPORT QIOVectoredWriteOperation : public QIOReadWriteOperationBase
@@ -146,6 +163,9 @@ protected:
explicit QIOVectoredWriteOperation(QIOOperationPrivate &dd, QObject *parent = nullptr);
friend class QRandomAccessAsyncFilePrivate;
+ friend class QRandomAccessAsyncFileBackend;
+ friend class QRandomAccessAsyncFileNativeBackend;
+ friend class QRandomAccessAsyncFileThreadPoolBackend;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qioring.cpp b/src/corelib/io/qioring.cpp
index 28849b49b04..2eb013e24fc 100644
--- a/src/corelib/io/qioring.cpp
+++ b/src/corelib/io/qioring.cpp
@@ -8,6 +8,20 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQIORing, "qt.core.ioring", QtCriticalMsg)
+QIORing *QIORing::sharedInstance()
+{
+ thread_local QIORing instance;
+ if (!instance.initializeIORing())
+ return nullptr;
+ return &instance;
+}
+
+QIORing::QIORing(quint32 submissionQueueSize, quint32 completionQueueSize)
+ : sqEntries(submissionQueueSize), cqEntries(completionQueueSize)
+{
+ // Destructor in respective _<platform>.cpp
+}
+
auto QIORing::queueRequestInternal(GenericRequestType &request) -> QueuedRequestStatus
{
if (!ensureInitialized() || preparingRequests) { // preparingRequests protects against recursing
@@ -65,12 +79,20 @@ template <typename T>
constexpr bool HasResultMember = qxp::is_detected_v<DetectResult, T>;
}
+void QIORing::setFileErrorResult(QIORing::GenericRequestType &req, QFileDevice::FileError error)
+{
+ invokeOnOp(req, [error](auto *concreteRequest) {
+ if constexpr (QtPrivate::HasResultMember<decltype(*concreteRequest)>)
+ setFileErrorResult(*concreteRequest, error);
+ });
+}
+
void QIORing::finishRequestWithError(QIORing::GenericRequestType &req, QFileDevice::FileError error)
{
- invokeOnOp(req, [error](auto *req) {
- if constexpr (QtPrivate::HasResultMember<decltype(*req)>)
- req->result.template emplace<QFileDevice::FileError>(error);
- invokeCallback(*req);
+ invokeOnOp(req, [error](auto *concreteRequest) {
+ if constexpr (QtPrivate::HasResultMember<decltype(*concreteRequest)>)
+ setFileErrorResult(*concreteRequest, error);
+ invokeCallback(*concreteRequest);
});
}
diff --git a/src/corelib/io/qioring_linux.cpp b/src/corelib/io/qioring_linux.cpp
index b296b916c81..2b5865f3c2d 100644
--- a/src/corelib/io/qioring_linux.cpp
+++ b/src/corelib/io/qioring_linux.cpp
@@ -35,19 +35,6 @@ static io_uring_op toUringOp(QIORing::Operation op);
static void prepareFileReadWrite(io_uring_sqe *sqe, const QIORingRequestOffsetFdBase &request,
const void *address, qsizetype size);
-
-QIORing *QIORing::sharedInstance()
-{
- thread_local QIORing instance;
- if (!instance.initializeIORing())
- return nullptr;
- return &instance;
-}
-
-QIORing::QIORing(quint32 submissionQueueSize, quint32 completionQueueSize)
- : sqEntries(submissionQueueSize), cqEntries(completionQueueSize)
-{
-}
QIORing::~QIORing()
{
if (eventDescriptor != -1)
diff --git a/src/corelib/io/qioring_p.h b/src/corelib/io/qioring_p.h
index d4c4308122e..8fdaf48f8f6 100644
--- a/src/corelib/io/qioring_p.h
+++ b/src/corelib/io/qioring_p.h
@@ -22,7 +22,6 @@
#include <QtCore/qspan.h>
#include <QtCore/qhash.h>
#include <QtCore/qfiledevice.h>
-#include <QtCore/qwineventnotifier.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qdeadlinetimer.h>
@@ -30,10 +29,15 @@
# include <QtCore/qsocketnotifier.h>
struct io_uring_sqe;
struct io_uring_cqe;
+#elif defined(Q_OS_WIN)
+# include <QtCore/qwineventnotifier.h>
+# include <qt_windows.h>
+# include <ioringapi.h>
#endif
#include <algorithm>
#include <filesystem>
+#include <QtCore/qxpfunctional.h>
#include <variant>
#include <optional>
#include <type_traits>
@@ -87,6 +91,10 @@ enum class Operation : quint8 {
// clang-format on
Q_ENUM_NS(Operation);
#undef DEFINE_ENTRY
+
+#ifdef Q_OS_WIN
+struct IORingApiTable;
+#endif
}; // namespace QtPrivate
template <QtPrivate::Operation Op>
@@ -162,6 +170,12 @@ private:
template <typename Fun>
static auto invokeOnOp(GenericRequestType &req, Fun fn);
+ template <Operation Op>
+ static void setFileErrorResult(QIORingRequest<Op> &req, QFileDevice::FileError error)
+ {
+ req.result.template emplace<QFileDevice::FileError>(error);
+ }
+ static void setFileErrorResult(GenericRequestType &req, QFileDevice::FileError error);
static void finishRequestWithError(GenericRequestType &req, QFileDevice::FileError error);
static bool verifyFd(GenericRequestType &req);
@@ -205,6 +219,30 @@ private:
ReadWriteStatus handleReadCompletion(const io_uring_cqe *cqe, GenericRequestType *request);
template <Operation Op>
ReadWriteStatus handleWriteCompletion(const io_uring_cqe *cqe, GenericRequestType *request);
+#elif defined(Q_OS_WIN)
+ // We use UINT32 because that's the type used for size parameters in their API.
+ static constexpr qsizetype MaxReadWriteLen = std::numeric_limits<UINT32>::max();
+ std::optional<QWinEventNotifier> notifier;
+ HIORING ioRingHandle = nullptr;
+ HANDLE eventHandle = INVALID_HANDLE_VALUE;
+ const QtPrivate::IORingApiTable *apiTable;
+
+ bool initialized = false;
+ bool queueWasFull = false;
+
+ [[nodiscard]]
+ RequestPrepResult prepareRequest(GenericRequestType &request);
+ QIORing::ReadWriteStatus handleReadCompletion(
+ HRESULT result, quintptr information, QSpan<std::byte> *destinations, void *voidExtra,
+ qxp::function_ref<qint64(std::variant<QFileDevice::FileError, qint64>)> setResult);
+ template <Operation Op>
+ ReadWriteStatus handleReadCompletion(const IORING_CQE *cqe, GenericRequestType *request);
+ ReadWriteStatus handleWriteCompletion(
+ HRESULT result, quintptr information, const QSpan<const std::byte> *sources,
+ void *voidExtra,
+ qxp::function_ref<qint64(std::variant<QFileDevice::FileError, qint64>)> setResult);
+ template <Operation Op>
+ ReadWriteStatus handleWriteCompletion(const IORING_CQE *cqe, GenericRequestType *request);
#endif
};
@@ -243,6 +281,7 @@ struct QIORingRequestBase : Base
template <>
struct QIORingResult<QtPrivate::Operation::Open>
{
+ // On Windows this is a HANDLE
qintptr fd;
};
template <>
@@ -260,6 +299,7 @@ template <>
struct QIORingRequest<QtPrivate::Operation::Close> final
: QIORingRequestBase<QtPrivate::Operation::Close, QIORingRequestEmptyBase>
{
+ // On Windows this is a HANDLE
qintptr fd;
};
@@ -318,6 +358,7 @@ struct QIORingResult<QtPrivate::Operation::Flush> final
template <>
struct QIORingRequest<QtPrivate::Operation::Flush> final : QIORingRequestBase<QtPrivate::Operation::Flush, QIORingRequestEmptyBase>
{
+ // On Windows this is a HANDLE
qintptr fd;
};
@@ -330,6 +371,7 @@ template <>
struct QIORingRequest<QtPrivate::Operation::Stat> final
: QIORingRequestBase<QtPrivate::Operation::Stat, QIORingRequestEmptyBase>
{
+ // On Windows this is a HANDLE
qintptr fd;
};
@@ -473,6 +515,7 @@ namespace QtPrivate {
// The 'extra' struct for Read/Write operations that must be split up
struct ReadWriteExtra
{
+ qint64 totalProcessed = 0;
qsizetype spanIndex = 0;
qsizetype spanOffset = 0;
qsizetype numSpans = 1;
diff --git a/src/corelib/io/qioring_win.cpp b/src/corelib/io/qioring_win.cpp
new file mode 100644
index 00000000000..b2f188486d0
--- /dev/null
+++ b/src/corelib/io/qioring_win.cpp
@@ -0,0 +1,818 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#include "qioring_p.h"
+
+QT_REQUIRE_CONFIG(windows_ioring);
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qscopedvaluerollback.h>
+
+#include <qt_windows.h>
+#include <ioringapi.h>
+
+#include <QtCore/q26numeric.h>
+
+QT_BEGIN_NAMESPACE
+
+// We don't really build for 32-bit windows anymore, but this code is definitely wrong if someone
+// does.
+static_assert(sizeof(qsizetype) > sizeof(UINT32),
+ "This code is written with assuming 64-bit Windows.");
+
+using namespace Qt::StringLiterals;
+
+namespace QtPrivate {
+#define FOREACH_WIN_IORING_FUNCTION(Fn) \
+ Fn(BuildIoRingReadFile) \
+ Fn(BuildIoRingWriteFile) \
+ Fn(BuildIoRingFlushFile) \
+ Fn(BuildIoRingCancelRequest) \
+ Fn(QueryIoRingCapabilities) \
+ Fn(CreateIoRing) \
+ Fn(GetIoRingInfo) \
+ Fn(SubmitIoRing) \
+ Fn(CloseIoRing) \
+ Fn(PopIoRingCompletion) \
+ Fn(SetIoRingCompletionEvent) \
+ /**/
+struct IORingApiTable
+{
+#define DefineIORingFunction(Name) \
+ using Name##Fn = decltype(&::Name); \
+ Name##Fn Name = nullptr;
+
+ FOREACH_WIN_IORING_FUNCTION(DefineIORingFunction)
+
+#undef DefineIORingFunction
+};
+
+static const IORingApiTable *getApiTable()
+{
+ static const IORingApiTable apiTable = []() {
+ IORingApiTable apiTable;
+ const HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
+ if (Q_UNLIKELY(!kernel32)) // how would this happen
+ return apiTable;
+
+#define ResolveFunction(Name) \
+ apiTable.Name = IORingApiTable::Name##Fn(QFunctionPointer(GetProcAddress(kernel32, #Name)));
+
+ FOREACH_WIN_IORING_FUNCTION(ResolveFunction)
+
+#undef ResolveFunction
+ return apiTable;
+ }();
+
+#define TEST_TABLE_OK(X) \
+ apiTable.X && /* chain */
+#define BOOL_CHAIN(...) (__VA_ARGS__ true)
+ const bool success = BOOL_CHAIN(FOREACH_WIN_IORING_FUNCTION(TEST_TABLE_OK));
+#undef BOOL_CHAIN
+#undef TEST_TABLE_OK
+
+ return success ? std::addressof(apiTable) : nullptr;
+}
+} // namespace QtPrivate
+
+static HRESULT buildReadOperation(HIORING ioRingHandle, qintptr fd, QSpan<std::byte> destination,
+ quint64 offset, quintptr userData)
+{
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ const IORING_HANDLE_REF fileRef((HANDLE(fd)));
+ const IORING_BUFFER_REF bufferRef(destination.data());
+ const auto maxSize = q26::saturate_cast<UINT32>(destination.size());
+ Q_ASSERT(maxSize == destination.size());
+ const auto *apiTable = QtPrivate::getApiTable();
+ Q_ASSERT(apiTable); // If we got this far it needs to be here
+ return apiTable->BuildIoRingReadFile(ioRingHandle, fileRef, bufferRef, maxSize, offset,
+ userData, IOSQE_FLAGS_NONE);
+}
+
+static HRESULT buildWriteOperation(HIORING ioRingHandle, qintptr fd, QSpan<const std::byte> source,
+ quint64 offset, quintptr userData)
+{
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ const IORING_HANDLE_REF fileRef((HANDLE(fd)));
+ const IORING_BUFFER_REF bufferRef(const_cast<std::byte *>(source.data()));
+ const auto maxSize = q26::saturate_cast<UINT32>(source.size());
+ Q_ASSERT(maxSize == source.size());
+ const auto *apiTable = QtPrivate::getApiTable();
+ Q_ASSERT(apiTable); // If we got this far it needs to be here
+ // @todo: FILE_WRITE_FLAGS can be set to write-through, could be used for Unbuffered mode.
+ return apiTable->BuildIoRingWriteFile(ioRingHandle, fileRef, bufferRef, maxSize, offset,
+ FILE_WRITE_FLAGS_NONE, userData, IOSQE_FLAGS_NONE);
+}
+
+QIORing::~QIORing()
+{
+ if (initialized) {
+ CloseHandle(eventHandle);
+ apiTable->CloseIoRing(ioRingHandle);
+ }
+}
+
+bool QIORing::initializeIORing()
+{
+ if (initialized)
+ return true;
+
+ if (apiTable = QtPrivate::getApiTable(); !apiTable) {
+ qCWarning(lcQIORing, "Failed to retrieve API table");
+ return false;
+ }
+
+ IORING_CAPABILITIES capabilities;
+ apiTable->QueryIoRingCapabilities(&capabilities);
+ if (capabilities.MaxVersion < IORING_VERSION_3) // 3 adds write, flush and drain
+ return false;
+ if ((capabilities.FeatureFlags & IORING_FEATURE_SET_COMPLETION_EVENT) == 0)
+ return false; // We currently require the SET_COMPLETION_EVENT feature
+
+ qCDebug(lcQIORing) << "Creating QIORing, requesting space for" << sqEntries
+ << "submission queue entries, and" << cqEntries
+ << "completion queue entries";
+
+ IORING_CREATE_FLAGS flags;
+ memset(&flags, 0, sizeof(flags));
+ HRESULT hr = apiTable->CreateIoRing(IORING_VERSION_3, flags, sqEntries, cqEntries,
+ &ioRingHandle);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "failed to initialize QIORing");
+ return false;
+ }
+ auto earlyExitCleanup = qScopeGuard([this]() {
+ if (eventHandle != INVALID_HANDLE_VALUE)
+ CloseHandle(eventHandle);
+ apiTable->CloseIoRing(ioRingHandle);
+ });
+ eventHandle = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ if (eventHandle == INVALID_HANDLE_VALUE) {
+ qErrnoWarning("Failed to create event handle");
+ return false;
+ }
+ notifier.emplace(eventHandle);
+ hr = apiTable->SetIoRingCompletionEvent(ioRingHandle, eventHandle);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Failed to assign the event handle to QIORing");
+ return false;
+ }
+ IORING_INFO info;
+ if (SUCCEEDED(apiTable->GetIoRingInfo(ioRingHandle, &info))) {
+ sqEntries = info.SubmissionQueueSize;
+ cqEntries = info.CompletionQueueSize;
+ qCDebug(lcQIORing) << "QIORing configured with capacity for" << sqEntries
+ << "submissions, and" << cqEntries << "completions.";
+ }
+ QObject::connect(std::addressof(*notifier), &QWinEventNotifier::activated,
+ std::addressof(*notifier), [this]() { completionReady(); });
+ initialized = true;
+ earlyExitCleanup.dismiss();
+ return true;
+}
+
+QIORing::ReadWriteStatus QIORing::handleReadCompletion(
+ HRESULT result, quintptr information, QSpan<std::byte> *destinations, void *voidExtra,
+ qxp::function_ref<qint64(std::variant<QFileDevice::FileError, qint64>)> setResultFn)
+{
+ if (FAILED(result)) {
+ if (result == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
+ return ReadWriteStatus::Finished;
+
+ if (result == E_ABORT)
+ setResultFn(QFileDevice::AbortError);
+ else
+ setResultFn(QFileDevice::ReadError);
+ } else if (auto *extra = static_cast<QtPrivate::ReadWriteExtra *>(voidExtra)) {
+ const qsizetype bytesRead = q26::saturate_cast<decltype(MaxReadWriteLen)>(information);
+ qCDebug(lcQIORing) << "Partial read of" << bytesRead << "bytes completed";
+ extra->totalProcessed = setResultFn(bytesRead);
+ extra->spanOffset += bytesRead;
+ qCDebug(lcQIORing) << "Read operation progress: span" << extra->spanIndex << "offset"
+ << extra->spanOffset << "of" << destinations[extra->spanIndex].size()
+ << "bytes. Total read:" << extra->totalProcessed << "bytes";
+ // The while loop is in case there is an empty span, we skip over it:
+ while (extra->spanOffset == destinations[extra->spanIndex].size()) {
+ // Move to next span
+ if (++extra->spanIndex == extra->numSpans)
+ return ReadWriteStatus::Finished;
+ extra->spanOffset = 0;
+ }
+ return ReadWriteStatus::MoreToDo;
+ } else {
+ setResultFn(q26::saturate_cast<decltype(MaxReadWriteLen)>(information));
+ }
+ return ReadWriteStatus::Finished;
+}
+
+template <QIORing::Operation Op>
+Q_ALWAYS_INLINE QIORing::ReadWriteStatus QIORing::handleReadCompletion(const IORING_CQE *cqe,
+ GenericRequestType *request)
+{
+ static_assert(Op == Operation::Read || Op == Operation::VectoredRead);
+ QIORingRequest<Op> *readRequest = request->requestData<Op>();
+ Q_ASSERT(readRequest);
+ auto *destinations = [&readRequest]() {
+ if constexpr (Op == Operation::Read)
+ return &readRequest->destination;
+ else
+ return &readRequest->destinations[0];
+ }();
+ auto setResult = [readRequest](const std::variant<QFileDevice::FileError, qint64> &result) {
+ if (result.index() == 0) { // error
+ QIORing::setFileErrorResult(*readRequest, *std::get_if<QFileDevice::FileError>(&result));
+ return 0ll;
+ }
+ // else: success
+ auto &readResult = [&readRequest]() -> QIORingResult<Op> & {
+ if (auto *result = std::get_if<QIORingResult<Op>>(&readRequest->result))
+ return *result;
+ return readRequest->result.template emplace<QIORingResult<Op>>();
+ }();
+ qint64 bytesRead = *std::get_if<qint64>(&result);
+ readResult.bytesRead += bytesRead;
+ return readResult.bytesRead;
+ };
+ QIORing::ReadWriteStatus rwstatus = handleReadCompletion(
+ cqe->ResultCode, cqe->Information, destinations, request->getExtra<void>(), setResult);
+ switch (rwstatus) {
+ case ReadWriteStatus::Finished:
+ if (request->getExtra<void>())
+ --ongoingSplitOperations;
+ break;
+ case ReadWriteStatus::MoreToDo: {
+ // Move the request such that it is next in the list to be processed:
+ auto &it = addrItMap[request];
+ const auto where = lastUnqueuedIterator.value_or(pendingRequests.end());
+ pendingRequests.splice(where, pendingRequests, it);
+ it = std::prev(where);
+ lastUnqueuedIterator = it;
+ break;
+ }
+ }
+ return rwstatus;
+}
+
+QIORing::ReadWriteStatus QIORing::handleWriteCompletion(
+ HRESULT result, quintptr information, const QSpan<const std::byte> *sources, void *voidExtra,
+ qxp::function_ref<qint64(std::variant<QFileDevice::FileError, qint64>)> setResultFn)
+{
+ if (FAILED(result)) {
+ if (result == E_ABORT)
+ setResultFn(QFileDevice::AbortError);
+ else
+ setResultFn(QFileDevice::WriteError);
+ } else if (auto *extra = static_cast<QtPrivate::ReadWriteExtra *>(voidExtra)) {
+ const qsizetype bytesWritten = q26::saturate_cast<decltype(MaxReadWriteLen)>(information);
+ qCDebug(lcQIORing) << "Partial write of" << bytesWritten << "bytes completed";
+ extra->totalProcessed = setResultFn(bytesWritten);
+ extra->spanOffset += bytesWritten;
+ qCDebug(lcQIORing) << "Write operation progress: span" << extra->spanIndex << "offset"
+ << extra->spanOffset << "of" << sources[extra->spanIndex].size()
+ << "bytes. Total written:" << extra->totalProcessed << "bytes";
+ // The while loop is in case there is an empty span, we skip over it:
+ while (extra->spanOffset == sources[extra->spanIndex].size()) {
+ // Move to next span
+ if (++extra->spanIndex == extra->numSpans)
+ return ReadWriteStatus::Finished;
+ extra->spanOffset = 0;
+ }
+ return ReadWriteStatus::MoreToDo;
+ } else {
+ setResultFn(q26::saturate_cast<decltype(MaxReadWriteLen)>(information));
+ }
+ return ReadWriteStatus::Finished;
+}
+
+template <QIORing::Operation Op>
+Q_ALWAYS_INLINE QIORing::ReadWriteStatus QIORing::handleWriteCompletion(const IORING_CQE *cqe,
+ GenericRequestType *request)
+{
+ static_assert(Op == Operation::Write || Op == Operation::VectoredWrite);
+ QIORingRequest<Op> *writeRequest = request->requestData<Op>();
+ auto *sources = [&writeRequest]() {
+ if constexpr (Op == Operation::Write)
+ return &writeRequest->source;
+ else
+ return &writeRequest->sources[0];
+ }();
+ auto setResult = [writeRequest](const std::variant<QFileDevice::FileError, qint64> &result) {
+ if (result.index() == 0) { // error
+ QIORing::setFileErrorResult(*writeRequest, *std::get_if<QFileDevice::FileError>(&result));
+ return 0ll;
+ }
+ // else: success
+ auto &writeResult = [&writeRequest]() -> QIORingResult<Op> & {
+ if (auto *result = std::get_if<QIORingResult<Op>>(&writeRequest->result))
+ return *result;
+ return writeRequest->result.template emplace<QIORingResult<Op>>();
+ }();
+ qint64 bytesWritten = *std::get_if<qint64>(&result);
+ writeResult.bytesWritten += bytesWritten;
+ return writeResult.bytesWritten;
+ };
+ QIORing::ReadWriteStatus rwstatus = handleWriteCompletion(
+ cqe->ResultCode, cqe->Information, sources, request->getExtra<void>(), setResult);
+ switch (rwstatus) {
+ case ReadWriteStatus::Finished:
+ if (request->getExtra<void>())
+ --ongoingSplitOperations;
+ break;
+ case ReadWriteStatus::MoreToDo: {
+ // Move the request such that it is next in the list to be processed:
+ auto &it = addrItMap[request];
+ const auto where = lastUnqueuedIterator.value_or(pendingRequests.end());
+ pendingRequests.splice(where, pendingRequests, it);
+ it = std::prev(where);
+ lastUnqueuedIterator = it;
+ break;
+ }
+ }
+ return rwstatus;
+}
+
+void QIORing::completionReady()
+{
+ ResetEvent(eventHandle);
+ IORING_CQE entry;
+ while (apiTable->PopIoRingCompletion(ioRingHandle, &entry) == S_OK) {
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ auto *request = reinterpret_cast<GenericRequestType *>(entry.UserData);
+ if (!addrItMap.contains(request)) {
+ qCDebug(lcQIORing) << "Got completed entry, but cannot find it in the map. Likely "
+ "deleted, ignoring. UserData pointer:"
+ << request;
+ continue;
+ }
+ qCDebug(lcQIORing) << "Got completed entry. Operation:" << request->operation()
+ << "- UserData pointer:" << request
+ << "- Result:" << qt_error_string(entry.ResultCode) << '('
+ << QByteArray("0x"_ba + QByteArray::number(entry.ResultCode, 16)).data()
+ << ')';
+ switch (request->operation()) {
+ case Operation::Open: // Synchronously finishes
+ Q_UNREACHABLE_RETURN();
+ case Operation::Close: {
+ auto closeRequest = request->takeRequestData<Operation::Close>();
+ // We ignore the result of the flush, we are closing the handle anyway.
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ if (CloseHandle(HANDLE(closeRequest.fd)))
+ closeRequest.result.emplace<QIORingResult<Operation::Close>>();
+ else
+ closeRequest.result.emplace<QFileDevice::FileError>(QFileDevice::OpenError);
+ invokeCallback(closeRequest);
+ break;
+ }
+ case Operation::Read: {
+ const ReadWriteStatus status = handleReadCompletion<Operation::Read>(&entry, request);
+ if (status == ReadWriteStatus::MoreToDo)
+ continue;
+ auto readRequest = request->takeRequestData<Operation::Read>();
+ invokeCallback(readRequest);
+ break;
+ }
+ case Operation::Write: {
+ const ReadWriteStatus status = handleWriteCompletion<Operation::Write>(&entry, request);
+ if (status == ReadWriteStatus::MoreToDo)
+ continue;
+ auto writeRequest = request->takeRequestData<Operation::Write>();
+ invokeCallback(writeRequest);
+ break;
+ }
+ case Operation::VectoredRead: {
+ const ReadWriteStatus status = handleReadCompletion<Operation::VectoredRead>(&entry,
+ request);
+ if (status == ReadWriteStatus::MoreToDo)
+ continue;
+ auto vectoredReadRequest = request->takeRequestData<Operation::VectoredRead>();
+ invokeCallback(vectoredReadRequest);
+ break;
+ }
+ case Operation::VectoredWrite: {
+ const ReadWriteStatus status = handleWriteCompletion<Operation::VectoredWrite>(&entry,
+ request);
+ if (status == ReadWriteStatus::MoreToDo)
+ continue;
+ auto vectoredWriteRequest = request->takeRequestData<Operation::VectoredWrite>();
+ invokeCallback(vectoredWriteRequest);
+ break;
+ }
+ case Operation::Flush: {
+ auto flushRequest = request->takeRequestData<Operation::Flush>();
+ if (FAILED(entry.ResultCode)) {
+ qErrnoWarning(entry.ResultCode, "Flush operation failed");
+ // @todo any FlushError?
+ flushRequest.result.emplace<QFileDevice::FileError>(
+ QFileDevice::FileError::WriteError);
+ } else {
+ flushRequest.result.emplace<QIORingResult<Operation::Flush>>();
+ }
+ invokeCallback(flushRequest);
+ break;
+ }
+ case QtPrivate::Operation::Cancel: {
+ auto cancelRequest = request->takeRequestData<Operation::Cancel>();
+ invokeCallback(cancelRequest);
+ break;
+ }
+ case QtPrivate::Operation::Stat:
+ Q_UNREACHABLE_RETURN(); // Completes synchronously
+ break;
+ case Operation::NumOperations:
+ Q_UNREACHABLE_RETURN();
+ break;
+ }
+ auto it = addrItMap.take(request);
+ pendingRequests.erase(it);
+ --inFlightRequests;
+ queueWasFull = false;
+ }
+ prepareRequests();
+ if (unstagedRequests > 0)
+ submitRequests();
+}
+
+bool QIORing::waitForCompletions(QDeadlineTimer deadline)
+{
+ notifier->setEnabled(false);
+ auto reactivateNotifier = qScopeGuard([this]() {
+ notifier->setEnabled(true);
+ });
+
+ while (!deadline.hasExpired()) {
+ DWORD timeout = 0;
+ if (deadline.isForever()) {
+ timeout = INFINITE;
+ } else {
+ timeout = q26::saturate_cast<DWORD>(deadline.remainingTime());
+ if (timeout == INFINITE)
+ --timeout;
+ }
+ if (WaitForSingleObject(eventHandle, timeout) == WAIT_OBJECT_0)
+ return true;
+ }
+ return false;
+}
+
+static HANDLE openFile(const QIORingRequest<QIORing::Operation::Open> &openRequest)
+{
+ DWORD access = 0;
+ if (openRequest.flags.testFlag(QIODevice::ReadOnly))
+ access |= GENERIC_READ;
+ if (openRequest.flags.testFlag(QIODevice::WriteOnly))
+ access |= GENERIC_WRITE;
+
+ DWORD disposition = 0;
+ if (openRequest.flags.testFlag(QIODevice::Append)) {
+ qCWarning(lcQIORing, "Opening file with Append not supported for random access file");
+ return INVALID_HANDLE_VALUE;
+ }
+ if (openRequest.flags.testFlag(QIODevice::NewOnly)) {
+ disposition = CREATE_NEW;
+ } else {
+ // If Write is specified we _may_ create a file.
+ // See qfsfileengine_p.h openModeCanCreate.
+ disposition = openRequest.flags.testFlag(QIODeviceBase::WriteOnly)
+ && !openRequest.flags.testFlags(QIODeviceBase::ExistingOnly)
+ ? OPEN_ALWAYS
+ : OPEN_EXISTING;
+ }
+ const DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ const DWORD flagsAndAttribs = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
+ HANDLE h = CreateFile(openRequest.path.native().c_str(), access, shareMode, nullptr,
+ disposition, flagsAndAttribs, nullptr);
+ if (h != INVALID_HANDLE_VALUE && openRequest.flags.testFlag(QIODeviceBase::Truncate)) {
+ FILE_END_OF_FILE_INFO info;
+ memset(&info, 0, sizeof(info));
+ SetFileInformationByHandle(h, FileEndOfFileInfo, &info, sizeof(info));
+ }
+ return h;
+}
+
+bool QIORing::supportsOperation(Operation op)
+{
+ switch (op) {
+ case QtPrivate::Operation::Open:
+ case QtPrivate::Operation::Close:
+ case QtPrivate::Operation::Read:
+ case QtPrivate::Operation::Write:
+ case QtPrivate::Operation::Flush:
+ case QtPrivate::Operation::Cancel:
+ case QtPrivate::Operation::Stat:
+ case QtPrivate::Operation::VectoredRead:
+ case QtPrivate::Operation::VectoredWrite:
+ return true;
+ case QtPrivate::Operation::NumOperations:
+ return false;
+ }
+ return false; // Not unreachable, we could allow more for io_uring
+}
+
+void QIORing::submitRequests()
+{
+ stagePending = false;
+ if (unstagedRequests == 0)
+ return;
+
+ // We perform a miniscule wait - to see if anything already in the queue is already completed -
+ // if we have been told the queue is full. Then we can try queuing more things right away
+ const bool shouldTryWait = std::exchange(queueWasFull, false);
+ const auto submitToRing = [this, &shouldTryWait] {
+ quint32 submittedEntries = 0;
+ HRESULT hr = apiTable->SubmitIoRing(ioRingHandle, shouldTryWait ? 1 : 0, 1,
+ &submittedEntries);
+ qCDebug(lcQIORing) << "Submitted" << submittedEntries << "requests";
+ unstagedRequests -= submittedEntries;
+ if (FAILED(hr)) {
+ // Too noisy, not a real problem
+ // qErrnoWarning(hr, "Failed to submit QIORing request: %u", submittedEntries);
+ return false;
+ }
+ return submittedEntries > 0;
+ };
+ if (submitToRing() && shouldTryWait) {
+ // We try to prepare some more request and submit more if able
+ prepareRequests();
+ if (unstagedRequests > 0)
+ submitToRing();
+ }
+}
+
+void QIORing::prepareRequests()
+{
+ if (!lastUnqueuedIterator)
+ return;
+ Q_ASSERT(!preparingRequests);
+ QScopedValueRollback<bool> prepareGuard(preparingRequests, true);
+
+ auto it = *lastUnqueuedIterator;
+ lastUnqueuedIterator.reset();
+ const auto end = pendingRequests.end();
+ while (!queueWasFull && it != end) {
+ auto &request = *it;
+ switch (prepareRequest(request)) {
+ case RequestPrepResult::Ok:
+ ++unstagedRequests;
+ ++inFlightRequests;
+ break;
+ case RequestPrepResult::QueueFull:
+ qCDebug(lcQIORing) << "Queue was reported as full, in flight requests:"
+ << inFlightRequests << "submission queue size:" << sqEntries
+ << "completion queue size:" << cqEntries;
+ queueWasFull = true;
+ lastUnqueuedIterator = it;
+ return;
+ case RequestPrepResult::Defer:
+ qCDebug(lcQIORing) << "Request for" << request.operation()
+ << "had to be deferred, will not queue any more requests at the "
+ "moment.";
+ lastUnqueuedIterator = it;
+ return; //
+ case RequestPrepResult::RequestCompleted:
+ // Used for requests that immediately finish. So we erase it:
+ qCDebug(lcQIORing) << "Request for" << request.operation()
+ << "completed synchronously.";
+ addrItMap.remove(&request);
+ it = pendingRequests.erase(it);
+ continue; // Don't increment iterator again
+ }
+ ++it;
+ }
+}
+
+namespace QtPrivate {
+template <typename T>
+using DetectHasFd = decltype(std::declval<const T &>().fd);
+
+template <typename T>
+constexpr bool OperationHasFd_v = qxp::is_detected_v<DetectHasFd, T>;
+} // namespace QtPrivate
+
+auto QIORing::prepareRequest(GenericRequestType &request) -> RequestPrepResult
+{
+ qCDebug(lcQIORing) << "Preparing a request with operation" << request.operation();
+ HRESULT hr = -1;
+
+ if (!verifyFd(request)) {
+ finishRequestWithError(request, QFileDevice::OpenError);
+ return RequestPrepResult::RequestCompleted;
+ }
+
+ switch (request.operation()) {
+ case Operation::Open: {
+ QIORingRequest<Operation::Open> openRequest = request.takeRequestData<Operation::Open>();
+ HANDLE fileDescriptor = openFile(openRequest);
+ if (fileDescriptor == INVALID_HANDLE_VALUE) {
+ openRequest.result.emplace<QFileDevice::FileError>(QFileDevice::FileError::OpenError);
+ } else {
+ auto &result = openRequest.result.emplace<QIORingResult<Operation::Open>>();
+ result.fd = qintptr(fileDescriptor);
+ }
+ invokeCallback(openRequest);
+ return RequestPrepResult::RequestCompleted;
+ }
+ case Operation::Close: {
+ if (ongoingSplitOperations > 0)
+ return RequestPrepResult::Defer;
+
+ // We need to wait until all previous OPS are done before we close the request.
+ // There is no no-op request in the Windows QIORing, so we issue a flush.
+ auto *closeRequest = request.requestData<Operation::Close>();
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ const IORING_HANDLE_REF fileRef(HANDLE(closeRequest->fd));
+ hr = apiTable->BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_MIN_METADATA,
+ quintptr(std::addressof(request)),
+ IOSQE_FLAGS_DRAIN_PRECEDING_OPS);
+ break;
+ }
+ case Operation::Read: {
+ auto *readRequest = request.requestData<Operation::Read>();
+ auto span = readRequest->destination;
+ auto offset = readRequest->offset;
+ if (span.size() > MaxReadWriteLen) {
+ qCDebug(lcQIORing) << "Requested Read of size" << span.size() << "has to be split";
+ auto *extra = request.getOrInitializeExtra<QtPrivate::ReadWriteExtra>();
+ if (extra->spanOffset == 0)
+ ++ongoingSplitOperations;
+ const qsizetype remaining = span.size() - extra->spanOffset;
+ span.slice(extra->spanOffset, std::min(remaining, MaxReadWriteLen));
+ offset += extra->totalProcessed;
+ }
+ hr = buildReadOperation(ioRingHandle, readRequest->fd, span, offset,
+ quintptr(std::addressof(request)));
+ break;
+ }
+ case Operation::VectoredRead: {
+ auto *vectoredReadRequest = request.requestData<Operation::VectoredRead>();
+ auto span = vectoredReadRequest->destinations.front();
+ auto offset = vectoredReadRequest->offset;
+ if (Q_LIKELY(vectoredReadRequest->destinations.size() > 1
+ || span.size() > MaxReadWriteLen)) {
+ auto *extra = request.getOrInitializeExtra<QtPrivate::ReadWriteExtra>();
+ if (extra->spanOffset == 0 && extra->spanIndex == 0)
+ ++ongoingSplitOperations;
+ extra->numSpans = vectoredReadRequest->destinations.size();
+
+ span = vectoredReadRequest->destinations[extra->spanIndex];
+
+ const qsizetype remaining = span.size() - extra->spanOffset;
+ span.slice(extra->spanOffset, std::min(remaining, MaxReadWriteLen));
+ offset += extra->totalProcessed;
+ }
+ hr = buildReadOperation(ioRingHandle, vectoredReadRequest->fd, span,
+ offset, quintptr(std::addressof(request)));
+ break;
+ }
+ case Operation::Write: {
+ auto *writeRequest = request.requestData<Operation::Write>();
+ auto span = writeRequest->source;
+ auto offset = writeRequest->offset;
+ if (span.size() > MaxReadWriteLen) {
+ qCDebug(lcQIORing) << "Requested Write of size" << span.size() << "has to be split";
+ auto *extra = request.getOrInitializeExtra<QtPrivate::ReadWriteExtra>();
+ if (extra->spanOffset == 0)
+ ++ongoingSplitOperations;
+ const qsizetype remaining = span.size() - extra->spanOffset;
+ span.slice(extra->spanOffset, std::min(remaining, MaxReadWriteLen));
+ offset += extra->totalProcessed;
+ }
+ hr = buildWriteOperation(ioRingHandle, writeRequest->fd, span, offset,
+ quintptr(std::addressof(request)));
+ break;
+ }
+ case Operation::VectoredWrite: {
+ auto *vectoredWriteRequest = request.requestData<Operation::VectoredWrite>();
+ auto span = vectoredWriteRequest->sources.front();
+ auto offset = vectoredWriteRequest->offset;
+ if (Q_LIKELY(vectoredWriteRequest->sources.size() > 1
+ || span.size() > MaxReadWriteLen)) {
+ auto *extra = request.getOrInitializeExtra<QtPrivate::ReadWriteExtra>();
+ if (extra->spanOffset == 0 && extra->spanIndex == 0)
+ ++ongoingSplitOperations;
+ extra->numSpans = vectoredWriteRequest->sources.size();
+
+ span = vectoredWriteRequest->sources[extra->spanIndex];
+
+ const qsizetype remaining = span.size() - extra->spanOffset;
+ span.slice(extra->spanOffset, std::min(remaining, MaxReadWriteLen));
+ offset += extra->totalProcessed;
+ }
+ hr = buildWriteOperation(ioRingHandle, vectoredWriteRequest->fd, span,
+ offset, quintptr(std::addressof(request)));
+ break;
+ }
+ case Operation::Flush: {
+ if (ongoingSplitOperations > 0)
+ return RequestPrepResult::Defer;
+ auto *flushRequest = request.requestData<Operation::Flush>();
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ const IORING_HANDLE_REF fileRef(HANDLE(flushRequest->fd));
+ hr = apiTable->BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_DEFAULT,
+ quintptr(std::addressof(request)),
+ IOSQE_FLAGS_DRAIN_PRECEDING_OPS);
+ break;
+ }
+ case QtPrivate::Operation::Stat: {
+ auto statRequest = request.takeRequestData<Operation::Stat>();
+ FILE_STANDARD_INFO info;
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ if (!GetFileInformationByHandleEx(HANDLE(statRequest.fd), FileStandardInfo, &info,
+ sizeof(info))) {
+ DWORD winErr = GetLastError();
+ QFileDevice::FileError error = QFileDevice::UnspecifiedError;
+ if (winErr == ERROR_FILE_NOT_FOUND || winErr == ERROR_INVALID_HANDLE)
+ error = QFileDevice::OpenError;
+ else if (winErr == ERROR_ACCESS_DENIED)
+ error = QFileDevice::PermissionsError;
+ statRequest.result.emplace<QFileDevice::FileError>(error);
+ } else {
+ auto &result = statRequest.result.emplace<QIORingResult<Operation::Stat>>();
+ result.size = info.EndOfFile.QuadPart;
+ }
+ invokeCallback(statRequest);
+ return RequestPrepResult::RequestCompleted;
+ }
+ case Operation::Cancel: {
+ auto *cancelRequest = request.requestData<Operation::Cancel>();
+ auto *otherOperation = reinterpret_cast<GenericRequestType *>(cancelRequest->handle);
+ if (!otherOperation || !addrItMap.contains(otherOperation)) {
+ qCDebug(lcQIORing, "Invalid cancel for non-existant operation");
+ invokeCallback(*cancelRequest);
+ return RequestPrepResult::RequestCompleted;
+ }
+ qCDebug(lcQIORing) << "Cancelling operation of type" << otherOperation->operation()
+ << "which was"
+ << (otherOperation->wasQueued() ? "queued" : "not queued");
+ Q_ASSERT(&request != otherOperation);
+ if (!otherOperation->wasQueued()) {
+ // The request hasn't been queued yet, so we can just drop it from
+ // the pending requests and call the callback.
+ auto it = addrItMap.take(otherOperation);
+ finishRequestWithError(*otherOperation, QFileDevice::AbortError);
+ pendingRequests.erase(it); // otherOperation is deleted
+ invokeCallback(*cancelRequest);
+ return RequestPrepResult::RequestCompleted;
+ }
+ qintptr fd = -1;
+ invokeOnOp(*otherOperation, [&fd](auto *request) {
+ if constexpr (QtPrivate::OperationHasFd_v<decltype(*request)>)
+ fd = request->fd;
+ });
+ if (fd == -1) {
+ qCDebug(lcQIORing, "Invalid cancel for non-existant fd");
+ invokeCallback(*cancelRequest);
+ return RequestPrepResult::RequestCompleted;
+ }
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ const IORING_HANDLE_REF fileRef((HANDLE(fd)));
+ hr = apiTable->BuildIoRingCancelRequest(ioRingHandle, fileRef, quintptr(otherOperation),
+ quintptr(std::addressof(request)));
+ break;
+ }
+ case Operation::NumOperations:
+ Q_UNREACHABLE_RETURN(RequestPrepResult::RequestCompleted);
+ break;
+ }
+ if (hr == IORING_E_SUBMISSION_QUEUE_FULL)
+ return RequestPrepResult::QueueFull;
+ if (FAILED(hr)) {
+ finishRequestWithError(request, QFileDevice::UnspecifiedError);
+ return RequestPrepResult::RequestCompleted;
+ }
+ request.setQueued(true);
+ return RequestPrepResult::Ok;
+}
+
+bool QIORing::verifyFd(GenericRequestType &req)
+{
+ bool result = true;
+ invokeOnOp(req, [&](auto *request) {
+ if constexpr (QtPrivate::OperationHasFd_v<decltype(*request)>) {
+ result = quintptr(request->fd) > 0 && quintptr(request->fd) != quintptr(INVALID_HANDLE_VALUE);
+ }
+ });
+ return result;
+}
+
+void QIORing::GenericRequestType::cleanupExtra(Operation op, void *extra)
+{
+ switch (op) {
+ case QtPrivate::Operation::Read:
+ case QtPrivate::Operation::VectoredRead:
+ case QtPrivate::Operation::Write:
+ case QtPrivate::Operation::VectoredWrite:
+ delete static_cast<QtPrivate::ReadWriteExtra *>(extra);
+ break;
+ case QtPrivate::Operation::Open:
+ case QtPrivate::Operation::Close:
+ case QtPrivate::Operation::Flush:
+ case QtPrivate::Operation::Stat:
+ case QtPrivate::Operation::Cancel:
+ case QtPrivate::Operation::NumOperations:
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qrandomaccessasyncfile.cpp b/src/corelib/io/qrandomaccessasyncfile.cpp
index c544585de9d..34e216efe27 100644
--- a/src/corelib/io/qrandomaccessasyncfile.cpp
+++ b/src/corelib/io/qrandomaccessasyncfile.cpp
@@ -7,6 +7,31 @@
QT_BEGIN_NAMESPACE
+QRandomAccessAsyncFileBackend::QRandomAccessAsyncFileBackend(QRandomAccessAsyncFile *owner)
+ : m_owner(owner)
+{
+}
+QRandomAccessAsyncFileBackend::~QRandomAccessAsyncFileBackend() = default;
+QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() = default;
+QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() = default;
+
+void QRandomAccessAsyncFilePrivate::init()
+{
+ Q_Q(QRandomAccessAsyncFile);
+
+#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) || defined(Q_OS_DARWIN)
+ m_backend = std::make_unique<QRandomAccessAsyncFileNativeBackend>(q);
+#endif
+ if (!m_backend || !m_backend->init()) {
+#if QT_CONFIG(thread) && QT_CONFIG(future)
+ m_backend = std::make_unique<QRandomAccessAsyncFileThreadPoolBackend>(q);
+ [[maybe_unused]]
+ bool result = m_backend->init();
+ Q_ASSERT(result); // it always succeeds
+#endif
+ }
+}
+
QRandomAccessAsyncFile::QRandomAccessAsyncFile(QObject *parent)
: QObject{*new QRandomAccessAsyncFilePrivate, parent}
{
diff --git a/src/corelib/io/qrandomaccessasyncfile_darwin.mm b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
index 7231d12fe7d..80c1affa642 100644
--- a/src/corelib/io/qrandomaccessasyncfile_darwin.mm
+++ b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
@@ -27,14 +27,14 @@ static bool isBarrierOperation(QIOOperation::Type type)
// only!
template <typename Operation, typename ...Args>
Operation *
-QRandomAccessAsyncFilePrivate::addOperation(QIOOperation::Type type, qint64 offset, Args &&...args)
+QRandomAccessAsyncFileNativeBackend::addOperation(QIOOperation::Type type, qint64 offset, Args &&...args)
{
auto dataStorage = new QtPrivate::QIOOperationDataStorage(std::forward<Args>(args)...);
auto *priv = new QIOOperationPrivate(dataStorage);
priv->offset = offset;
priv->type = type;
- Operation *op = new Operation(*priv, q_ptr);
+ Operation *op = new Operation(*priv, m_owner);
auto opId = getNextId();
m_operations.push_back(OperationInfo(opId, op));
startOperationsUntilBarrier();
@@ -42,19 +42,20 @@ QRandomAccessAsyncFilePrivate::addOperation(QIOOperation::Type type, qint64 offs
return op;
}
-QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate()
- : QObjectPrivate()
+QRandomAccessAsyncFileNativeBackend::QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner)
+ : QRandomAccessAsyncFileBackend(owner)
{
}
-QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate()
+QRandomAccessAsyncFileNativeBackend::~QRandomAccessAsyncFileNativeBackend()
= default;
-void QRandomAccessAsyncFilePrivate::init()
+bool QRandomAccessAsyncFileNativeBackend::init()
{
+ return true;
}
-void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op)
+void QRandomAccessAsyncFileNativeBackend::cancelAndWait(QIOOperation *op)
{
auto it = std::find_if(m_operations.cbegin(), m_operations.cend(),
[op](const auto &opInfo) {
@@ -87,7 +88,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op)
startOperationsUntilBarrier();
}
-void QRandomAccessAsyncFilePrivate::close()
+void QRandomAccessAsyncFileNativeBackend::close()
{
if (m_fileState == FileState::Closed)
return;
@@ -95,10 +96,8 @@ void QRandomAccessAsyncFilePrivate::close()
// cancel all operations
m_mutex.lock();
m_opToCancel = kAllOperationIds;
- m_numChannelsToClose = m_ioChannel ? 1 : 0;
for (const auto &op : m_operations) {
if (op.channel) {
- ++m_numChannelsToClose;
closeIoChannel(op.channel);
}
}
@@ -127,7 +126,7 @@ void QRandomAccessAsyncFilePrivate::close()
m_fileState = FileState::Closed;
}
-qint64 QRandomAccessAsyncFilePrivate::size() const
+qint64 QRandomAccessAsyncFileNativeBackend::size() const
{
if (m_fileState != FileState::Opened)
return -1;
@@ -140,7 +139,7 @@ qint64 QRandomAccessAsyncFilePrivate::size() const
}
QIOOperation *
-QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode)
+QRandomAccessAsyncFileNativeBackend::open(const QString &path, QIODeviceBase::OpenMode mode)
{
if (m_fileState == FileState::Closed) {
m_filePath = path;
@@ -153,44 +152,44 @@ QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode
return addOperation<QIOOperation>(QIOOperation::Type::Open, 0);
}
-QIOOperation *QRandomAccessAsyncFilePrivate::flush()
+QIOOperation *QRandomAccessAsyncFileNativeBackend::flush()
{
return addOperation<QIOOperation>(QIOOperation::Type::Flush, 0);
}
-QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize)
+QIOReadOperation *QRandomAccessAsyncFileNativeBackend::read(qint64 offset, qint64 maxSize)
{
QByteArray array(maxSize, Qt::Uninitialized);
return addOperation<QIOReadOperation>(QIOOperation::Type::Read, offset, std::move(array));
}
-QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data)
+QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, const QByteArray &data)
{
QByteArray copy = data;
return write(offset, std::move(copy));
}
-QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data)
+QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, QByteArray &&data)
{
return addOperation<QIOWriteOperation>(QIOOperation::Type::Write, offset, std::move(data));
}
QIOVectoredReadOperation *
-QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer)
+QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<std::byte> buffer)
{
return addOperation<QIOVectoredReadOperation>(QIOOperation::Type::Read, offset,
QSpan<const QSpan<std::byte>>{buffer});
}
QIOVectoredWriteOperation *
-QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> buffer)
+QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer)
{
return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset,
QSpan<const QSpan<const std::byte>>{buffer});
}
QIOVectoredReadOperation *
-QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers)
+QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers)
{
// GCD implementation does not have vectored read. Spawning several read
// operations (each with an updated offset), is not ideal, because some
@@ -204,32 +203,40 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by
}
QIOVectoredWriteOperation *
-QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers)
+QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers)
{
return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset, buffers);
}
-void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted()
+void QRandomAccessAsyncFileNativeBackend::notifyIfOperationsAreCompleted()
{
QMutexLocker locker(&m_mutex);
+ --m_numChannelsToClose;
if (m_opToCancel == kAllOperationIds) {
- --m_numChannelsToClose;
if (m_numChannelsToClose == 0 && m_runningOps.isEmpty())
m_cancellationCondition.wakeOne();
}
}
-dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd)
+dispatch_io_t QRandomAccessAsyncFileNativeBackend::createMainChannel(int fd)
{
auto sharedThis = this;
- return dispatch_io_create(DISPATCH_IO_RANDOM, fd,
- dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
- ^(int /*error*/) {
- sharedThis->notifyIfOperationsAreCompleted();
- });
+ auto channel =
+ dispatch_io_create(DISPATCH_IO_RANDOM, fd,
+ dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
+ ^(int /*error*/) {
+ // main I/O channel uses kInvalidOperationId
+ // as its identifier
+ sharedThis->notifyIfOperationsAreCompleted();
+ });
+ if (channel) {
+ QMutexLocker locker(&m_mutex);
+ ++m_numChannelsToClose;
+ }
+ return channel;
}
-dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId)
+dispatch_io_t QRandomAccessAsyncFileNativeBackend::duplicateIoChannel(OperationId opId)
{
if (!m_ioChannel)
return nullptr;
@@ -247,17 +254,18 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId
if (channel) {
QMutexLocker locker(&m_mutex);
m_runningOps.insert(opId);
+ ++m_numChannelsToClose;
}
return channel;
}
-void QRandomAccessAsyncFilePrivate::closeIoChannel(dispatch_io_t channel)
+void QRandomAccessAsyncFileNativeBackend::closeIoChannel(dispatch_io_t channel)
{
if (channel)
dispatch_io_close(channel, DISPATCH_IO_STOP);
}
-void QRandomAccessAsyncFilePrivate::releaseIoChannel(dispatch_io_t channel)
+void QRandomAccessAsyncFileNativeBackend::releaseIoChannel(dispatch_io_t channel)
{
if (channel) {
dispatch_release(channel);
@@ -265,7 +273,7 @@ void QRandomAccessAsyncFilePrivate::releaseIoChannel(dispatch_io_t channel)
}
}
-void QRandomAccessAsyncFilePrivate::handleOperationComplete(const OperationResult &opResult)
+void QRandomAccessAsyncFileNativeBackend::handleOperationComplete(const OperationResult &opResult)
{
// try to start next operations on return
auto onReturn = qScopeGuard([this] {
@@ -372,15 +380,15 @@ void QRandomAccessAsyncFilePrivate::handleOperationComplete(const OperationResul
}
}
-void QRandomAccessAsyncFilePrivate::queueCompletion(OperationId opId, int error)
+void QRandomAccessAsyncFileNativeBackend::queueCompletion(OperationId opId, int error)
{
const OperationResult res = { opId, 0LL, error };
- QMetaObject::invokeMethod(q_ptr, [this, res] {
+ QMetaObject::invokeMethod(m_owner, [this, res] {
handleOperationComplete(res);
}, Qt::QueuedConnection);
}
-void QRandomAccessAsyncFilePrivate::startOperationsUntilBarrier()
+void QRandomAccessAsyncFileNativeBackend::startOperationsUntilBarrier()
{
// starts all operations until barrier, or a barrier operation if it's the
// first one
@@ -414,7 +422,7 @@ void QRandomAccessAsyncFilePrivate::startOperationsUntilBarrier()
}
}
-void QRandomAccessAsyncFilePrivate::executeRead(OperationInfo &opInfo)
+void QRandomAccessAsyncFileNativeBackend::executeRead(OperationInfo &opInfo)
{
opInfo.channel = duplicateIoChannel(opInfo.opId);
if (!opInfo.channel) {
@@ -445,7 +453,7 @@ void QRandomAccessAsyncFilePrivate::executeRead(OperationInfo &opInfo)
}
}
-void QRandomAccessAsyncFilePrivate::executeWrite(OperationInfo &opInfo)
+void QRandomAccessAsyncFileNativeBackend::executeWrite(OperationInfo &opInfo)
{
opInfo.channel = duplicateIoChannel(opInfo.opId);
if (!opInfo.channel) {
@@ -494,7 +502,7 @@ void QRandomAccessAsyncFilePrivate::executeWrite(OperationInfo &opInfo)
}
}
-void QRandomAccessAsyncFilePrivate::executeFlush(OperationInfo &opInfo)
+void QRandomAccessAsyncFileNativeBackend::executeFlush(OperationInfo &opInfo)
{
opInfo.channel = duplicateIoChannel(opInfo.opId);
if (!opInfo.channel) {
@@ -523,7 +531,7 @@ void QRandomAccessAsyncFilePrivate::executeFlush(OperationInfo &opInfo)
}
}
} else {
- auto context = sharedThis->q_ptr;
+ auto context = sharedThis->m_owner;
const OperationResult res = { opId, 0LL, err };
QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) {
sharedThis->handleOperationComplete(r);
@@ -555,7 +563,7 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
return oflags;
}
-void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo)
+void QRandomAccessAsyncFileNativeBackend::executeOpen(OperationInfo &opInfo)
{
if (m_fileState != FileState::OpenPending) {
queueCompletion(opInfo.opId, EINVAL);
@@ -593,9 +601,10 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo)
// So we need to notify the condition variable in
// both cases.
Q_ASSERT(sharedThis->m_runningOps.isEmpty());
+ Q_ASSERT(sharedThis->m_numChannelsToClose == 0);
sharedThis->m_cancellationCondition.wakeOne();
} else {
- auto context = sharedThis->q_ptr;
+ auto context = sharedThis->m_owner;
const OperationResult res = { opId, qint64(fd), err };
QMetaObject::invokeMethod(context,
[sharedThis](const OperationResult &r) {
@@ -605,7 +614,7 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo)
});
}
-void QRandomAccessAsyncFilePrivate::readOneBuffer(OperationId opId, qsizetype bufferIdx,
+void QRandomAccessAsyncFileNativeBackend::readOneBuffer(OperationId opId, qsizetype bufferIdx,
qint64 alreadyRead)
{
// we need to lookup the operation again, because it could have beed removed
@@ -642,7 +651,7 @@ void QRandomAccessAsyncFilePrivate::readOneBuffer(OperationId opId, qsizetype bu
readBuffers.size(), alreadyRead);
}
-void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispatch_io_t channel,
+void QRandomAccessAsyncFileNativeBackend::readOneBufferHelper(OperationId opId, dispatch_io_t channel,
qint64 offset, void *bytesPtr,
qint64 maxSize, qsizetype currentBufferIdx,
qsizetype totalBuffers, qint64 alreadyRead)
@@ -690,7 +699,7 @@ void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispat
}
} else {
sharedThis->m_runningOps.remove(opId);
- auto context = sharedThis->q_ptr;
+ auto context = sharedThis->m_owner;
// if error, or last buffer, or read less than expected,
// report operation completion
qint64 totalRead = qint64(readFromBuffer) + alreadyRead;
@@ -713,7 +722,7 @@ void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispat
});
}
-void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t channel,
+void QRandomAccessAsyncFileNativeBackend::writeHelper(OperationId opId, dispatch_io_t channel,
qint64 offset, dispatch_data_t dataToWrite,
qint64 dataSize)
{
@@ -752,7 +761,7 @@ void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t
const size_t written = dataSize - toBeWritten;
[dataToWrite release];
- auto context = sharedThis->q_ptr;
+ auto context = sharedThis->m_owner;
const OperationResult res = { opId, qint64(written), error };
QMetaObject::invokeMethod(context,
[sharedThis](const OperationResult &r) {
@@ -762,7 +771,7 @@ void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t
});
}
-QRandomAccessAsyncFilePrivate::OperationId QRandomAccessAsyncFilePrivate::getNextId()
+QRandomAccessAsyncFileNativeBackend::OperationId QRandomAccessAsyncFileNativeBackend::getNextId()
{
// never return reserved values
static OperationId opId = kInvalidOperationId;
diff --git a/src/corelib/io/qrandomaccessasyncfile_p_p.h b/src/corelib/io/qrandomaccessasyncfile_p_p.h
index 11ad788c884..2eb53058780 100644
--- a/src/corelib/io/qrandomaccessasyncfile_p_p.h
+++ b/src/corelib/io/qrandomaccessasyncfile_p_p.h
@@ -22,7 +22,7 @@
#include <QtCore/qstring.h>
-#ifdef QT_RANDOMACCESSASYNCFILE_THREAD
+#if QT_CONFIG(future) && QT_CONFIG(thread)
#include <QtCore/private/qfsfileengine_p.h>
@@ -30,7 +30,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/qqueue.h>
-#endif // QT_RANDOMACCESSASYNCFILE_THREAD
+#endif // future && thread
#ifdef Q_OS_DARWIN
@@ -50,41 +50,36 @@
QT_BEGIN_NAMESPACE
-class QRandomAccessAsyncFilePrivate : public QObjectPrivate
+class QRandomAccessAsyncFileBackend
{
- Q_DECLARE_PUBLIC(QRandomAccessAsyncFile)
- Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFilePrivate)
+ Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileBackend)
public:
- QRandomAccessAsyncFilePrivate();
- ~QRandomAccessAsyncFilePrivate() override;
-
- static QRandomAccessAsyncFilePrivate *get(QRandomAccessAsyncFile *file)
- { return file->d_func(); }
+ explicit QRandomAccessAsyncFileBackend(QRandomAccessAsyncFile *owner);
+ virtual ~QRandomAccessAsyncFileBackend();
- void init();
- void cancelAndWait(QIOOperation *op);
+ virtual bool init() = 0;
+ virtual void cancelAndWait(QIOOperation *op) = 0;
- void close();
- qint64 size() const;
+ virtual void close() = 0;
+ virtual qint64 size() const = 0;
- [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode);
- [[nodiscard]] QIOOperation *flush();
+ [[nodiscard]] virtual QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) = 0;
+ [[nodiscard]] virtual QIOOperation *flush() = 0;
- [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize);
- [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data);
- [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data);
+ [[nodiscard]] virtual QIOReadOperation *read(qint64 offset, qint64 maxSize) = 0;
+ [[nodiscard]] virtual QIOWriteOperation *write(qint64 offset, const QByteArray &data) = 0;
+ [[nodiscard]] virtual QIOWriteOperation *write(qint64 offset, QByteArray &&data) = 0;
- [[nodiscard]] QIOVectoredReadOperation *
- readInto(qint64 offset, QSpan<std::byte> buffer);
- [[nodiscard]] QIOVectoredWriteOperation *
- writeFrom(qint64 offset, QSpan<const std::byte> buffer);
-
- [[nodiscard]] QIOVectoredReadOperation *
- readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers);
- [[nodiscard]] QIOVectoredWriteOperation *
- writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers);
+ [[nodiscard]] virtual QIOVectoredReadOperation *
+ readInto(qint64 offset, QSpan<std::byte> buffer) = 0;
+ [[nodiscard]] virtual QIOVectoredWriteOperation *
+ writeFrom(qint64 offset, QSpan<const std::byte> buffer) = 0;
-private:
+ [[nodiscard]] virtual QIOVectoredReadOperation *
+ readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) = 0;
+ [[nodiscard]] virtual QIOVectoredWriteOperation *
+ writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) = 0;
+protected:
// common for all backends
enum class FileState : quint8
{
@@ -94,32 +89,131 @@ private:
};
QString m_filePath;
+ QRandomAccessAsyncFile *m_owner = nullptr;
QIODeviceBase::OpenMode m_openMode;
FileState m_fileState = FileState::Closed;
+};
-#ifdef QT_RANDOMACCESSASYNCFILE_THREAD
+class QRandomAccessAsyncFilePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QRandomAccessAsyncFile)
+ Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFilePrivate)
public:
- struct OperationResult
+ QRandomAccessAsyncFilePrivate();
+ ~QRandomAccessAsyncFilePrivate() override;
+
+ static QRandomAccessAsyncFilePrivate *get(QRandomAccessAsyncFile *file)
+ { return file->d_func(); }
+
+ void init();
+ void cancelAndWait(QIOOperation *op)
{
- qint64 bytesProcessed; // either read or written
- QIOOperation::Error error;
- };
+ checkValid();
+ m_backend->cancelAndWait(op);
+ }
+
+ void close()
+ {
+ checkValid();
+ m_backend->close();
+ }
+ qint64 size() const
+ {
+ checkValid();
+ return m_backend->size();
+ }
+
+ [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode)
+ {
+ checkValid();
+ return m_backend->open(path, mode);
+ }
+ [[nodiscard]] QIOOperation *flush()
+ {
+ checkValid();
+ return m_backend->flush();
+ }
+
+ [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize)
+ {
+ checkValid();
+ return m_backend->read(offset, maxSize);
+ }
+ [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data)
+ {
+ checkValid();
+ return m_backend->write(offset, data);
+ }
+ [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data)
+ {
+ checkValid();
+ return m_backend->write(offset, std::move(data));
+ }
+
+ [[nodiscard]] QIOVectoredReadOperation *readInto(qint64 offset, QSpan<std::byte> buffer)
+ {
+ checkValid();
+ return m_backend->readInto(offset, buffer);
+ }
+ [[nodiscard]] QIOVectoredWriteOperation *writeFrom(qint64 offset, QSpan<const std::byte> buffer)
+ {
+ checkValid();
+ return m_backend->writeFrom(offset, buffer);
+ }
+
+ [[nodiscard]] QIOVectoredReadOperation *readInto(qint64 offset,
+ QSpan<const QSpan<std::byte>> buffers)
+ {
+ checkValid();
+ return m_backend->readInto(offset, buffers);
+ }
+ [[nodiscard]] QIOVectoredWriteOperation *writeFrom(qint64 offset,
+ QSpan<const QSpan<const std::byte>> buffers)
+ {
+ checkValid();
+ return m_backend->writeFrom(offset, buffers);
+ }
private:
- mutable QBasicMutex m_engineMutex;
- std::unique_ptr<QFSFileEngine> m_engine;
- QFutureWatcher<OperationResult> m_watcher;
+ void checkValid() const { Q_ASSERT(m_backend); }
+ std::unique_ptr<QRandomAccessAsyncFileBackend> m_backend;
- QQueue<QPointer<QIOOperation>> m_operations;
- QPointer<QIOOperation> m_currentOperation;
- qsizetype numProcessedBuffers = 0;
+};
- void executeNextOperation();
- void processBufferAt(qsizetype idx);
- void processFlush();
- void processOpen();
- void operationComplete();
-#elif defined(QT_RANDOMACCESSASYNCFILE_QIORING)
+
+#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) || defined(Q_OS_DARWIN)
+class QRandomAccessAsyncFileNativeBackend final : public QRandomAccessAsyncFileBackend
+{
+ Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileNativeBackend)
+public:
+ explicit QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner);
+ ~QRandomAccessAsyncFileNativeBackend();
+
+ bool init() override;
+ void cancelAndWait(QIOOperation *op) override;
+
+ void close() override;
+ qint64 size() const override;
+
+ [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) override;
+ [[nodiscard]] QIOOperation *flush() override;
+
+ [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override;
+ [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) override;
+ [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override;
+
+ [[nodiscard]] QIOVectoredReadOperation *
+ readInto(qint64 offset, QSpan<std::byte> buffer) override;
+ [[nodiscard]] QIOVectoredWriteOperation *
+ writeFrom(qint64 offset, QSpan<const std::byte> buffer) override;
+
+ [[nodiscard]] QIOVectoredReadOperation *
+ readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) override;
+ [[nodiscard]] QIOVectoredWriteOperation *
+ writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) override;
+
+private:
+#if defined(QT_RANDOMACCESSASYNCFILE_QIORING)
void queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error);
void startReadIntoSingle(QIOOperation *op, const QSpan<std::byte> &to);
void startWriteFromSingle(QIOOperation *op, const QSpan<const std::byte> &from);
@@ -210,6 +304,61 @@ private:
dispatch_data_t dataToWrite, qint64 dataSize);
#endif
};
+#endif // QIORing || macOS
+
+#if QT_CONFIG(future) && QT_CONFIG(thread)
+class QRandomAccessAsyncFileThreadPoolBackend : public QRandomAccessAsyncFileBackend
+{
+ Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileThreadPoolBackend)
+public:
+ explicit QRandomAccessAsyncFileThreadPoolBackend(QRandomAccessAsyncFile *owner);
+ ~QRandomAccessAsyncFileThreadPoolBackend();
+
+ bool init() override;
+ void cancelAndWait(QIOOperation *op) override;
+
+ void close() override;
+ qint64 size() const override;
+
+ [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) override;
+ [[nodiscard]] QIOOperation *flush() override;
+
+ [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override;
+ [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) override;
+ [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override;
+
+ [[nodiscard]] QIOVectoredReadOperation *
+ readInto(qint64 offset, QSpan<std::byte> buffer) override;
+ [[nodiscard]] QIOVectoredWriteOperation *
+ writeFrom(qint64 offset, QSpan<const std::byte> buffer) override;
+
+ [[nodiscard]] QIOVectoredReadOperation *
+ readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) override;
+ [[nodiscard]] QIOVectoredWriteOperation *
+ writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) override;
+
+ struct OperationResult
+ {
+ qint64 bytesProcessed; // either read or written
+ QIOOperation::Error error;
+ };
+private:
+
+ mutable QBasicMutex m_engineMutex;
+ std::unique_ptr<QFSFileEngine> m_engine;
+ QFutureWatcher<OperationResult> m_watcher;
+
+ QQueue<QPointer<QIOOperation>> m_operations;
+ QPointer<QIOOperation> m_currentOperation;
+ qsizetype numProcessedBuffers = 0;
+
+ void executeNextOperation();
+ void processBufferAt(qsizetype idx);
+ void processFlush();
+ void processOpen();
+ void operationComplete();
+};
+#endif // future && thread
QT_END_NAMESPACE
diff --git a/src/corelib/io/qrandomaccessasyncfile_qioring.cpp b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp
index c9783ea2856..8e1145325d8 100644
--- a/src/corelib/io/qrandomaccessasyncfile_qioring.cpp
+++ b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp
@@ -18,18 +18,21 @@ QT_BEGIN_NAMESPACE
Q_STATIC_LOGGING_CATEGORY(lcQRandomAccessIORing, "qt.core.qrandomaccessasyncfile.ioring",
QtCriticalMsg);
-QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() = default;
+QRandomAccessAsyncFileNativeBackend::QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner)
+ : QRandomAccessAsyncFileBackend(owner)
+{}
-QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() = default;
+QRandomAccessAsyncFileNativeBackend::~QRandomAccessAsyncFileNativeBackend() = default;
-void QRandomAccessAsyncFilePrivate::init()
+bool QRandomAccessAsyncFileNativeBackend::init()
{
m_ioring = QIORing::sharedInstance();
if (!m_ioring)
- qCCritical(lcQRandomAccessIORing, "QRandomAccessAsyncFile: ioring failed to initialize");
+ qCWarning(lcQRandomAccessIORing, "QRandomAccessAsyncFile: ioring failed to initialize");
+ return m_ioring != nullptr;
}
-QIORing::RequestHandle QRandomAccessAsyncFilePrivate::cancel(QIORing::RequestHandle handle)
+QIORing::RequestHandle QRandomAccessAsyncFileNativeBackend::cancel(QIORing::RequestHandle handle)
{
if (handle) {
QIORingRequest<QIORing::Operation::Cancel> cancelRequest;
@@ -39,7 +42,7 @@ QIORing::RequestHandle QRandomAccessAsyncFilePrivate::cancel(QIORing::RequestHan
return nullptr;
}
-void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op)
+void QRandomAccessAsyncFileNativeBackend::cancelAndWait(QIOOperation *op)
{
auto *opHandle = m_opHandleMap.value(op);
if (auto *handle = cancel(opHandle)) {
@@ -48,7 +51,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op)
}
}
-void QRandomAccessAsyncFilePrivate::queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error)
+void QRandomAccessAsyncFileNativeBackend::queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error)
{
// Remove the handle now in case the user cancels or deletes the io-operation
// before operationComplete is called - the null-handle will protect from
@@ -61,14 +64,14 @@ void QRandomAccessAsyncFilePrivate::queueCompletion(QIOOperationPrivate *priv, Q
}, Qt::QueuedConnection);
}
-QIOOperation *QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode)
+QIOOperation *QRandomAccessAsyncFileNativeBackend::open(const QString &path, QIODeviceBase::OpenMode mode)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage();
auto *priv = new QIOOperationPrivate(dataStorage);
priv->type = QIOOperation::Type::Open;
- auto *op = new QIOOperation(*priv, q_ptr);
+ auto *op = new QIOOperation(*priv, m_owner);
if (m_fileState != FileState::Closed) {
queueCompletion(priv, QIOOperation::Error::Open);
return op;
@@ -115,7 +118,7 @@ QIOOperation *QRandomAccessAsyncFilePrivate::open(const QString &path, QIODevice
return op;
}
-void QRandomAccessAsyncFilePrivate::close()
+void QRandomAccessAsyncFileNativeBackend::close()
{
// all the operations should be aborted
const auto ops = std::exchange(m_operations, {});
@@ -123,7 +126,7 @@ void QRandomAccessAsyncFilePrivate::close()
// Request to cancel all of the in-flight operations:
for (const auto &op : ops) {
if (op) {
- op->d_func()->error = QIOOperation::Error::Aborted;
+ QIOOperationPrivate::get(op)->error = QIOOperation::Error::Aborted;
if (auto *opHandle = m_opHandleMap.value(op)) {
tasksToAwait.append(cancel(opHandle));
tasksToAwait.append(opHandle);
@@ -142,7 +145,7 @@ void QRandomAccessAsyncFilePrivate::close()
m_fd = -1;
}
-qint64 QRandomAccessAsyncFilePrivate::size() const
+qint64 QRandomAccessAsyncFileNativeBackend::size() const
{
QIORingRequest<QIORing::Operation::Stat> statRequest;
statRequest.fd = m_fd;
@@ -161,14 +164,14 @@ qint64 QRandomAccessAsyncFilePrivate::size() const
return finalSize;
}
-QIOOperation *QRandomAccessAsyncFilePrivate::flush()
+QIOOperation *QRandomAccessAsyncFileNativeBackend::flush()
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage();
auto *priv = new QIOOperationPrivate(dataStorage);
priv->type = QIOOperation::Type::Flush;
- auto *op = new QIOOperation(*priv, q_ptr);
+ auto *op = new QIOOperation(*priv, m_owner);
m_operations.append(op);
QIORingRequest<QIORing::Operation::Flush> flushRequest;
@@ -192,7 +195,7 @@ QIOOperation *QRandomAccessAsyncFilePrivate::flush()
return op;
}
-void QRandomAccessAsyncFilePrivate::startReadIntoSingle(QIOOperation *op,
+void QRandomAccessAsyncFileNativeBackend::startReadIntoSingle(QIOOperation *op,
const QSpan<std::byte> &to)
{
QIORingRequest<QIORing::Operation::Read> readRequest;
@@ -231,7 +234,7 @@ void QRandomAccessAsyncFilePrivate::startReadIntoSingle(QIOOperation *op,
m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(readRequest)));
}
-QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize)
+QIOReadOperation *QRandomAccessAsyncFileNativeBackend::read(qint64 offset, qint64 maxSize)
{
QByteArray array;
array.resizeForOverwrite(maxSize);
@@ -241,7 +244,7 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS
priv->offset = offset;
priv->type = QIOOperation::Type::Read;
- auto *op = new QIOReadOperation(*priv, q_ptr);
+ auto *op = new QIOReadOperation(*priv, m_owner);
m_operations.append(op);
startReadIntoSingle(op, as_writable_bytes(QSpan(dataStorage->getByteArray())));
@@ -249,12 +252,12 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS
return op;
}
-QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data)
+QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, const QByteArray &data)
{
return write(offset, QByteArray(data));
}
-void QRandomAccessAsyncFilePrivate::startWriteFromSingle(QIOOperation *op,
+void QRandomAccessAsyncFileNativeBackend::startWriteFromSingle(QIOOperation *op,
const QSpan<const std::byte> &from)
{
QIORingRequest<QIORing::Operation::Write> writeRequest;
@@ -288,7 +291,7 @@ void QRandomAccessAsyncFilePrivate::startWriteFromSingle(QIOOperation *op,
m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(writeRequest)));
}
-QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data)
+QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, QByteArray &&data)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(data));
@@ -296,7 +299,7 @@ QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArra
priv->offset = offset;
priv->type = QIOOperation::Type::Write;
- auto *op = new QIOWriteOperation(*priv, q_ptr);
+ auto *op = new QIOWriteOperation(*priv, m_owner);
m_operations.append(op);
startWriteFromSingle(op, as_bytes(QSpan(dataStorage->getByteArray())));
@@ -304,7 +307,7 @@ QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArra
return op;
}
-QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset,
+QIOVectoredReadOperation *QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset,
QSpan<std::byte> buffer)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage(
@@ -314,7 +317,7 @@ QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset,
priv->offset = offset;
priv->type = QIOOperation::Type::Read;
- auto *op = new QIOVectoredReadOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredReadOperation(*priv, m_owner);
m_operations.append(op);
startReadIntoSingle(op, dataStorage->getReadSpans().first());
@@ -322,7 +325,7 @@ QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset,
return op;
}
-QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset,
+QIOVectoredWriteOperation *QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset,
QSpan<const std::byte> buffer)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage(
@@ -332,7 +335,7 @@ QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offse
priv->offset = offset;
priv->type = QIOOperation::Type::Write;
- auto *op = new QIOVectoredWriteOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredWriteOperation(*priv, m_owner);
m_operations.append(op);
startWriteFromSingle(op, dataStorage->getWriteSpans().first());
@@ -341,7 +344,7 @@ QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offse
}
QIOVectoredReadOperation *
-QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers)
+QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers)
{
if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredRead))
return nullptr;
@@ -351,7 +354,7 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by
priv->offset = offset;
priv->type = QIOOperation::Type::Read;
- auto *op = new QIOVectoredReadOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredReadOperation(*priv, m_owner);
if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now
queueCompletion(priv, QIOOperation::Error::IncorrectOffset);
return op;
@@ -393,7 +396,7 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by
}
QIOVectoredWriteOperation *
-QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers)
+QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers)
{
if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredWrite))
return nullptr;
@@ -403,7 +406,7 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const
priv->offset = offset;
priv->type = QIOOperation::Type::Write;
- auto *op = new QIOVectoredWriteOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredWriteOperation(*priv, m_owner);
if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now
queueCompletion(priv, QIOOperation::Error::IncorrectOffset);
return op;
diff --git a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp
index 4ebcf554655..774fbadc5ad 100644
--- a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp
+++ b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp
@@ -64,28 +64,29 @@ static SharedThreadPool asyncFileThreadPool;
} // anonymous namespace
-QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() :
- QObjectPrivate()
+QRandomAccessAsyncFileThreadPoolBackend::QRandomAccessAsyncFileThreadPoolBackend(QRandomAccessAsyncFile *owner) :
+ QRandomAccessAsyncFileBackend(owner)
{
asyncFileThreadPool.ref();
}
-QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate()
+QRandomAccessAsyncFileThreadPoolBackend::~QRandomAccessAsyncFileThreadPoolBackend()
{
asyncFileThreadPool.deref();
}
-void QRandomAccessAsyncFilePrivate::init()
+bool QRandomAccessAsyncFileThreadPoolBackend::init()
{
- QObject::connect(&m_watcher, &QFutureWatcherBase::finished, q_ptr, [this]{
+ QObject::connect(&m_watcher, &QFutureWatcherBase::finished, m_owner, [this]{
operationComplete();
});
- QObject::connect(&m_watcher, &QFutureWatcherBase::canceled, q_ptr, [this]{
+ QObject::connect(&m_watcher, &QFutureWatcherBase::canceled, m_owner, [this]{
operationComplete();
});
+ return true;
}
-void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op)
+void QRandomAccessAsyncFileThreadPoolBackend::cancelAndWait(QIOOperation *op)
{
if (op == m_currentOperation) {
m_currentOperation = nullptr; // to discard the result
@@ -97,7 +98,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op)
}
QIOOperation *
-QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode)
+QRandomAccessAsyncFileThreadPoolBackend::open(const QString &path, QIODeviceBase::OpenMode mode)
{
// We generate the command in any case. But if the file is already opened,
// it will finish with an error
@@ -112,14 +113,14 @@ QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode
auto *priv = new QIOOperationPrivate(dataStorage);
priv->type = QIOOperation::Type::Open;
- auto *op = new QIOOperation(*priv, q_ptr);
+ auto *op = new QIOOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
-void QRandomAccessAsyncFilePrivate::close()
+void QRandomAccessAsyncFileThreadPoolBackend::close()
{
// all the operations should be aborted
for (const auto &op : std::as_const(m_operations)) {
@@ -148,7 +149,7 @@ void QRandomAccessAsyncFilePrivate::close()
m_fileState = FileState::Closed;
}
-qint64 QRandomAccessAsyncFilePrivate::size() const
+qint64 QRandomAccessAsyncFileThreadPoolBackend::size() const
{
QMutexLocker locker(&m_engineMutex);
if (m_engine)
@@ -156,20 +157,20 @@ qint64 QRandomAccessAsyncFilePrivate::size() const
return -1;
}
-QIOOperation *QRandomAccessAsyncFilePrivate::flush()
+QIOOperation *QRandomAccessAsyncFileThreadPoolBackend::flush()
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage();
auto *priv = new QIOOperationPrivate(dataStorage);
priv->type = QIOOperation::Type::Flush;
- auto *op = new QIOOperation(*priv, q_ptr);
+ auto *op = new QIOOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
-QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize)
+QIOReadOperation *QRandomAccessAsyncFileThreadPoolBackend::read(qint64 offset, qint64 maxSize)
{
QByteArray array;
array.resizeForOverwrite(maxSize);
@@ -179,14 +180,14 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS
priv->offset = offset;
priv->type = QIOOperation::Type::Read;
- auto *op = new QIOReadOperation(*priv, q_ptr);
+ auto *op = new QIOReadOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
QIOWriteOperation *
-QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data)
+QRandomAccessAsyncFileThreadPoolBackend::write(qint64 offset, const QByteArray &data)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage(data);
@@ -194,14 +195,14 @@ QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data)
priv->offset = offset;
priv->type = QIOOperation::Type::Write;
- auto *op = new QIOWriteOperation(*priv, q_ptr);
+ auto *op = new QIOWriteOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
QIOWriteOperation *
-QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data)
+QRandomAccessAsyncFileThreadPoolBackend::write(qint64 offset, QByteArray &&data)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(data));
@@ -209,14 +210,14 @@ QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data)
priv->offset = offset;
priv->type = QIOOperation::Type::Write;
- auto *op = new QIOWriteOperation(*priv, q_ptr);
+ auto *op = new QIOWriteOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
QIOVectoredReadOperation *
-QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer)
+QRandomAccessAsyncFileThreadPoolBackend::readInto(qint64 offset, QSpan<std::byte> buffer)
{
auto *dataStorage =
new QtPrivate::QIOOperationDataStorage(QSpan<const QSpan<std::byte>>{buffer});
@@ -225,14 +226,14 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer)
priv->offset = offset;
priv->type = QIOOperation::Type::Read;
- auto *op = new QIOVectoredReadOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredReadOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
QIOVectoredWriteOperation *
-QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> buffer)
+QRandomAccessAsyncFileThreadPoolBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer)
{
auto *dataStorage =
new QtPrivate::QIOOperationDataStorage(QSpan<const QSpan<const std::byte>>{buffer});
@@ -241,14 +242,14 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> b
priv->offset = offset;
priv->type = QIOOperation::Type::Write;
- auto *op = new QIOVectoredWriteOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredWriteOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
QIOVectoredReadOperation *
-QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers)
+QRandomAccessAsyncFileThreadPoolBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers);
@@ -256,14 +257,14 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by
priv->offset = offset;
priv->type = QIOOperation::Type::Read;
- auto *op = new QIOVectoredReadOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredReadOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
QIOVectoredWriteOperation *
-QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers)
+QRandomAccessAsyncFileThreadPoolBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers)
{
auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers);
@@ -271,16 +272,16 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const
priv->offset = offset;
priv->type = QIOOperation::Type::Write;
- auto *op = new QIOVectoredWriteOperation(*priv, q_ptr);
+ auto *op = new QIOVectoredWriteOperation(*priv, m_owner);
m_operations.append(op);
executeNextOperation();
return op;
}
-static QRandomAccessAsyncFilePrivate::OperationResult
+static QRandomAccessAsyncFileThreadPoolBackend::OperationResult
executeRead(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, char *buffer, qint64 maxSize)
{
- QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None};
+ QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None};
QMutexLocker locker(mutex);
if (engine) {
@@ -299,11 +300,11 @@ executeRead(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, char *buff
return result;
}
-static QRandomAccessAsyncFilePrivate::OperationResult
+static QRandomAccessAsyncFileThreadPoolBackend::OperationResult
executeWrite(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset,
const char *buffer, qint64 size)
{
- QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None};
+ QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None};
QMutexLocker locker(mutex);
if (engine) {
@@ -322,7 +323,7 @@ executeWrite(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset,
return result;
}
-void QRandomAccessAsyncFilePrivate::executeNextOperation()
+void QRandomAccessAsyncFileThreadPoolBackend::executeNextOperation()
{
if (m_currentOperation.isNull()) {
// start next
@@ -351,7 +352,7 @@ void QRandomAccessAsyncFilePrivate::executeNextOperation()
}
}
-void QRandomAccessAsyncFilePrivate::processBufferAt(qsizetype idx)
+void QRandomAccessAsyncFileThreadPoolBackend::processBufferAt(qsizetype idx)
{
Q_ASSERT(!m_currentOperation.isNull());
auto *priv = QIOOperationPrivate::get(m_currentOperation.get());
@@ -417,7 +418,7 @@ void QRandomAccessAsyncFilePrivate::processBufferAt(qsizetype idx)
}
}
-void QRandomAccessAsyncFilePrivate::processFlush()
+void QRandomAccessAsyncFileThreadPoolBackend::processFlush()
{
Q_ASSERT(!m_currentOperation.isNull());
auto *priv = QIOOperationPrivate::get(m_currentOperation.get());
@@ -427,7 +428,7 @@ void QRandomAccessAsyncFilePrivate::processFlush()
QBasicMutex *mutexPtr = &m_engineMutex;
auto op = [engine = m_engine.get(), mutexPtr] {
QMutexLocker locker(mutexPtr);
- QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None};
+ QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None};
if (engine) {
if (!engine->flush())
result.error = QIOOperation::Error::Flush;
@@ -442,7 +443,7 @@ void QRandomAccessAsyncFilePrivate::processFlush()
m_watcher.setFuture(f);
}
-void QRandomAccessAsyncFilePrivate::processOpen()
+void QRandomAccessAsyncFileThreadPoolBackend::processOpen()
{
Q_ASSERT(!m_currentOperation.isNull());
auto *priv = QIOOperationPrivate::get(m_currentOperation.get());
@@ -457,7 +458,7 @@ void QRandomAccessAsyncFilePrivate::processOpen()
m_engineMutex.unlock();
QBasicMutex *mutexPtr = &m_engineMutex;
auto op = [engine = m_engine.get(), mutexPtr, mode = m_openMode] {
- QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None};
+ QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None};
QMutexLocker locker(mutexPtr);
const bool res =
engine && engine->open(mode | QIODeviceBase::Unbuffered, std::nullopt);
@@ -468,13 +469,13 @@ void QRandomAccessAsyncFilePrivate::processOpen()
f = QtFuture::makeReadyVoidFuture().then(asyncFileThreadPool(), op);
} else {
f = QtFuture::makeReadyVoidFuture().then(asyncFileThreadPool(), [] {
- return QRandomAccessAsyncFilePrivate::OperationResult{0, QIOOperation::Error::Open};
+ return QRandomAccessAsyncFileThreadPoolBackend::OperationResult{0, QIOOperation::Error::Open};
});
}
m_watcher.setFuture(f);
}
-void QRandomAccessAsyncFilePrivate::operationComplete()
+void QRandomAccessAsyncFileThreadPoolBackend::operationComplete()
{
// TODO: if one of the buffers was read/written with an error,
// stop processing immediately
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index 456a209af37..6edf4395887 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -14,6 +14,11 @@ using namespace Qt::StringLiterals;
static const DWORD minReadBufferSize = 4096;
+/*!
+ \class QWindowsPipeReader
+ \inmodule QtCore
+ \internal
+*/
QWindowsPipeReader::QWindowsPipeReader(QObject *parent)
: QObject(parent),
handle(INVALID_HANDLE_VALUE),
diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h
index 0233727f848..7eca3094a66 100644
--- a/src/corelib/itemmodels/qrangemodel_impl.h
+++ b/src/corelib/itemmodels/qrangemodel_impl.h
@@ -239,17 +239,15 @@ namespace QRangeModelDetails
: std::true_type
{};
- // we use std::rotate in moveRows/Columns, which requires std::swap and the
- // iterators to be at least a forward iterator
- template <typename It, typename = void>
- struct test_rotate : std::false_type {};
-
+ // we use std::rotate in moveRows/Columns, which requires the values (which
+ // might be const if we only get a const iterator) to be swappable, and the
+ // iterator type to be at least a forward iterator
template <typename It>
- struct test_rotate<It, std::void_t<decltype(std::swap(*std::declval<It>(),
- *std::declval<It>()))>>
- : std::is_base_of<std::forward_iterator_tag,
- typename std::iterator_traits<It>::iterator_category>
- {};
+ using test_rotate = std::conjunction<
+ std::is_swappable<decltype(*std::declval<It>())>,
+ std::is_base_of<std::forward_iterator_tag,
+ typename std::iterator_traits<It>::iterator_category>
+ >;
template <typename C, typename = void>
struct test_splice : std::false_type {};
@@ -1373,25 +1371,34 @@ public:
using multi_role = QRangeModelDetails::is_multi_role<value_type>;
auto setRangeModelDataRole = [&target, &data]{
- auto &targetRef = QRangeModelDetails::refTo(target);
constexpr auto targetMetaType = QMetaType::fromType<value_type>();
const auto dataMetaType = data.metaType();
constexpr bool isWrapped = QRangeModelDetails::is_wrapped<value_type>();
if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
// we don't support replacing objects that are stored as raw pointers,
// as this makes object ownership very messy. But we can replace objects
- // stored in smart pointers.
- if constexpr (isWrapped && !std::is_pointer_v<value_type>
- && std::is_copy_assignable_v<value_type>) {
- if (data.canConvert(targetMetaType)) {
- target = data.value<value_type>();
- return true;
+ // stored in smart pointers, and we can initialize raw nullptr objects.
+ if constexpr (isWrapped) {
+ constexpr bool is_raw_pointer = std::is_pointer_v<value_type>;
+ if constexpr (!is_raw_pointer && std::is_copy_assignable_v<value_type>) {
+ if (data.canConvert(targetMetaType)) {
+ target = data.value<value_type>();
+ return true;
+ }
+ } else if constexpr (is_raw_pointer) {
+ if (!QRangeModelDetails::isValid(target) && data.canConvert(targetMetaType)) {
+ target = data.value<value_type>();
+ return true;
+ }
+ } else {
+ Q_UNUSED(target);
}
}
// Otherwise we have a move-only or polymorph type. fall through to
// error handling.
} else if constexpr (isWrapped) {
if (QRangeModelDetails::isValid(target)) {
+ auto &targetRef = QRangeModelDetails::refTo(target);
// we need to get a wrapped value type out of the QVariant, which
// might carry a pointer. We have to try all alternatives.
if (const auto mt = QMetaType::fromType<wrapped_value_type>();
@@ -1405,10 +1412,10 @@ public:
}
}
} else if (targetMetaType == dataMetaType) {
- targetRef = data.value<value_type>();
+ QRangeModelDetails::refTo(target) = data.value<value_type>();
return true;
} else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
- targetRef = *data.value<value_type *>();
+ QRangeModelDetails::refTo(target) = *data.value<value_type *>();
return true;
}
#ifndef QT_NO_DEBUG
@@ -1463,6 +1470,13 @@ public:
};
success = writeAt(index, writeData);
+
+ if constexpr (itemsAreQObjects) {
+ if (success && isRangeModelRole(role) && this->autoConnectPolicy() == AutoConnectPolicy::Full) {
+ if (QObject *item = data.value<QObject *>())
+ Self::connectProperties(index, item, m_data.context, m_data.properties);
+ }
+ }
}
return success;
}
diff --git a/src/corelib/itemmodels/qrangemodeladapter.h b/src/corelib/itemmodels/qrangemodeladapter.h
index bd3342e6185..0234c402248 100644
--- a/src/corelib/itemmodels/qrangemodeladapter.h
+++ b/src/corelib/itemmodels/qrangemodeladapter.h
@@ -19,13 +19,11 @@ class QT_TECH_PREVIEW_API QRangeModelAdapter
#ifdef Q_QDOC
using range_type = Range;
- using const_row_reference = typename std::iterator_traits<Range>::const_reference;
- using row_reference = typename std::iterator_traits<Range>::reference;
#else
using range_type = QRangeModelDetails::wrapped_t<Range>;
+#endif
using const_row_reference = typename Impl::const_row_reference;
using row_reference = typename Impl::row_reference;
-#endif
using range_features = typename QRangeModelDetails::range_traits<range_type>;
using row_type = std::remove_reference_t<row_reference>;
using row_features = QRangeModelDetails::range_traits<typename Impl::wrapped_row_type>;
@@ -78,16 +76,22 @@ class QT_TECH_PREVIEW_API QRangeModelAdapter
template <typename C>
using if_compatible_row_range = std::enable_if_t<is_compatible_row_range<C>, bool>;
template <typename Data>
- static constexpr bool is_compatible_data = true;
- // std::is_convertible_v<Data, decltype(*std::begin(std::declval<const_row_reference>()))>;
+ static constexpr bool is_compatible_data = std::is_convertible_v<Data, data_type>;
template <typename Data>
using if_compatible_data = std::enable_if_t<is_compatible_data<Data>, bool>;
template <typename C>
static constexpr bool is_compatible_data_range = is_compatible_data<
+ typename QRangeModelDetails::data_type<
+ typename QRangeModelDetails::row_traits<
decltype(*std::begin(std::declval<C&>()))
- >;
+ >::item_type
+ >::type
+ >;
template <typename C>
- using if_compatible_data_range = std::enable_if_t<is_compatible_data_range<C>, bool>;
+ using if_compatible_column_data = std::enable_if_t<is_compatible_data<C>
+ || is_compatible_data_range<C>, bool>;
+ template <typename C>
+ using if_compatible_column_range = std::enable_if_t<is_compatible_data_range<C>, bool>;
template <typename R>
using if_assignable_range = std::enable_if_t<std::is_assignable_v<range_type, R>, bool>;
@@ -141,6 +145,7 @@ public:
}
DataReference(const DataReference &other) = default;
+ DataReference(DataReference &&other) = default;
// reference (not std::reference_wrapper) semantics
DataReference &operator=(const DataReference &other)
@@ -149,29 +154,23 @@ public:
return *this;
}
+ DataReference &operator=(DataReference &&other)
+ {
+ *this = other.get();
+ return *this;
+ }
+
~DataReference() = default;
DataReference &operator=(const value_type &value)
{
- constexpr Qt::ItemDataRole dataRole = Qt::RangeModelAdapterRole;
+ assign(value);
+ return *this;
+ }
- if (m_index.isValid()) {
- auto model = const_cast<QAbstractItemModel *>(m_index.model());
- [[maybe_unused]] bool couldWrite = false;
- if constexpr (std::is_same_v<q20::remove_cvref_t<value_type>, QVariant>)
- couldWrite = model->setData(m_index, value, dataRole);
- else
- couldWrite = model->setData(m_index, QVariant::fromValue(value), dataRole);
-#ifndef QT_NO_DEBUG
- if (!couldWrite) {
- qWarning() << "Writing value of type" << QMetaType::fromType<value_type>().name()
- << "to role" << dataRole << "at index" << m_index
- << "of the model failed";
- }
- } else {
- qCritical("Data reference for invalid index, can't write to model");
-#endif
- }
+ DataReference &operator=(value_type &&value)
+ {
+ assign(std::move(value));
return *this;
}
@@ -196,6 +195,33 @@ public:
private:
QModelIndex m_index;
+ template <typename Value>
+ void assign(Value &&value)
+ {
+ constexpr Qt::ItemDataRole dataRole = Qt::RangeModelAdapterRole;
+
+ if (m_index.isValid()) {
+ auto model = const_cast<QAbstractItemModel *>(m_index.model());
+ [[maybe_unused]] bool couldWrite = false;
+ if constexpr (std::is_same_v<q20::remove_cvref_t<Value>, QVariant>) {
+ couldWrite = model->setData(m_index, value, dataRole);
+ } else {
+ couldWrite = model->setData(m_index,
+ QVariant::fromValue(std::forward<Value>(value)),
+ dataRole);
+ }
+#ifndef QT_NO_DEBUG
+ if (!couldWrite) {
+ qWarning() << "Writing value of type"
+ << QMetaType::fromType<q20::remove_cvref_t<Value>>().name()
+ << "to role" << dataRole << "at index" << m_index << "failed";
+ }
+ } else {
+ qCritical("Data reference for invalid index, can't write to model");
+#endif
+ }
+ }
+
friend inline bool comparesEqual(const DataReference &lhs, const DataReference &rhs)
{
return lhs.m_index == rhs.m_index
@@ -1020,60 +1046,55 @@ public:
template <typename NewRange = range_type, if_assignable_range<NewRange> = true>
void setRange(NewRange &&newRange)
{
- using namespace QRangeModelDetails;
-
- auto *impl = storage.implementation();
- const QModelIndex root = storage.root();
- const qsizetype newLastRow = qsizetype(Impl::size(refTo(newRange))) - 1;
- auto *oldRange = impl->childRange(root);
- const qsizetype oldLastRow = qsizetype(Impl::size(oldRange)) - 1;
-
- if (!root.isValid()) {
- impl->beginResetModel();
- impl->deleteOwnedRows();
- } else if constexpr (is_tree<Impl>) {
- if (oldLastRow > 0) {
- impl->beginRemoveRows(root, 0, model()->rowCount(root) - 1);
- impl->deleteRemovedRows(refTo(oldRange));
- impl->endRemoveRows();
- }
- if (newLastRow > 0)
- impl->beginInsertRows(root, 0, newLastRow);
- } else {
- Q_ASSERT_X(false, "QRangeModelAdapter::setRange",
- "Internal error: The root index in a table or list must be invalid.");
- }
- refTo(oldRange) = std::forward<NewRange>(newRange);
- if (!root.isValid()) {
- impl->endResetModel();
- } else if constexpr (is_tree<Impl>) {
- if (newLastRow > 0) {
- Q_ASSERT(model()->hasChildren(root));
- // if it was moved, then newRange is now likely to be empty. Get
- // the inserted row.
- impl->setParentRow(refTo(impl->childRange(storage.root())),
- pointerTo(impl->rowData(root)));
- impl->endInsertRows();
- }
- }
- if constexpr (Impl::itemsAreQObjects) {
- if (model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
- const auto begin = QRangeModelDetails::begin(refTo(oldRange));
- const auto end = QRangeModelDetails::end(refTo(oldRange));
- int rowIndex = 0;
- for (auto it = begin; it != end; ++it, ++rowIndex)
- impl->autoConnectPropertiesInRow(*it, rowIndex, root);
- }
- }
+ setRangeImpl(qsizetype(Impl::size(QRangeModelDetails::refTo(newRange))) - 1,
+ [&newRange](auto &oldRange) {
+ oldRange = std::forward<NewRange>(newRange);
+ });
}
- template <typename NewRange = range_type, if_assignable_range<NewRange> = true>
+ template <typename NewRange = range_type, if_assignable_range<NewRange> = true,
+ unless_adapter<NewRange> = true>
QRangeModelAdapter &operator=(NewRange &&newRange)
{
setRange(std::forward<NewRange>(newRange));
return *this;
}
+ template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
+ void setRange(std::initializer_list<Row> newRange)
+ {
+ setRangeImpl(qsizetype(newRange.size() - 1), [&newRange](auto &oldRange) {
+ oldRange = newRange;
+ });
+ }
+
+ template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
+ QRangeModelAdapter &operator=(std::initializer_list<Row> newRange)
+ {
+ setRange(newRange);
+ return *this;
+ }
+
+ template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
+ void assign(std::initializer_list<Row> newRange)
+ {
+ setRange(newRange);
+ }
+
+ template <typename InputIterator, typename Sentinel, typename I = Impl, if_writable<I> = true>
+ void setRange(InputIterator first, Sentinel last)
+ {
+ setRangeImpl(qsizetype(std::distance(first, last) - 1), [first, last](auto &oldRange) {
+ oldRange.assign(first, last);
+ });
+ }
+
+ template <typename InputIterator, typename Sentinel, typename I = Impl, if_writable<I> = true>
+ void assign(InputIterator first, Sentinel last)
+ {
+ setRange(first, last);
+ }
+
// iterator API
ConstRowIterator cbegin() const
{
@@ -1245,12 +1266,12 @@ public:
decltype(auto) operator[](int row) const { return at(row); }
template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
- decltype(auto) at(int row)
+ auto at(int row)
{
return RowReference{index(row, 0), this};
}
template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
- decltype(auto) operator[](int row) { return at(row); }
+ auto operator[](int row) { return at(row); }
// at/operator[int, int] for table: returns value at row/column
template <typename I = Impl, unless_list<I> = true>
@@ -1428,15 +1449,15 @@ public:
return storage.m_model->insertColumn(before);
}
- template <typename D = row_type, typename I = Impl,
- if_canInsertColumns<I> = true, if_compatible_data<D> = true>
+ template <typename D, typename I = Impl,
+ if_canInsertColumns<I> = true, if_compatible_column_data<D> = true>
bool insertColumn(int before, D &&data)
{
return insertColumnImpl(before, storage.root(), std::forward<D>(data));
}
template <typename C, typename I = Impl,
- if_canInsertColumns<I> = true, if_compatible_data_range<C> = true>
+ if_canInsertColumns<I> = true, if_compatible_column_range<C> = true>
bool insertColumns(int before, C &&data)
{
return insertColumnsImpl(before, storage.root(), std::forward<C>(data));
@@ -1503,6 +1524,65 @@ private:
Q_EMIT storage.implementation()->dataChanged(topLeft, bottomRight, {});
}
+ void beginSetRangeImpl(Impl *impl, range_type *oldRange, qsizetype newLastRow)
+ {
+ const QModelIndex root = storage.root();
+ const qsizetype oldLastRow = qsizetype(Impl::size(oldRange)) - 1;
+
+ if (!root.isValid()) {
+ impl->beginResetModel();
+ impl->deleteOwnedRows();
+ } else if constexpr (is_tree<Impl>) {
+ if (oldLastRow > 0) {
+ impl->beginRemoveRows(root, 0, model()->rowCount(root) - 1);
+ impl->deleteRemovedRows(QRangeModelDetails::refTo(oldRange));
+ impl->endRemoveRows();
+ }
+ if (newLastRow > 0)
+ impl->beginInsertRows(root, 0, newLastRow);
+ } else {
+ Q_ASSERT_X(false, "QRangeModelAdapter::setRange",
+ "Internal error: The root index in a table or list must be invalid.");
+ }
+ }
+
+ void endSetRangeImpl(Impl *impl, qsizetype newLastRow)
+ {
+ const QModelIndex root = storage.root();
+ if (!root.isValid()) {
+ impl->endResetModel();
+ } else if constexpr (is_tree<Impl>) {
+ if (newLastRow > 0) {
+ Q_ASSERT(model()->hasChildren(root));
+ // if it was moved, then newRange is now likely to be empty. Get
+ // the inserted row.
+ impl->setParentRow(QRangeModelDetails::refTo(impl->childRange(root)),
+ QRangeModelDetails::pointerTo(impl->rowData(root)));
+ impl->endInsertRows();
+ }
+ }
+ }
+
+ template <typename Assigner>
+ void setRangeImpl(qsizetype newLastRow, Assigner &&assigner)
+ {
+ auto *impl = storage.implementation();
+ auto *oldRange = impl->childRange(storage.root());
+ beginSetRangeImpl(impl, oldRange, newLastRow);
+ assigner(QRangeModelDetails::refTo(oldRange));
+ endSetRangeImpl(impl, newLastRow);
+
+ if constexpr (Impl::itemsAreQObjects) {
+ if (model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
+ const auto begin = QRangeModelDetails::begin(QRangeModelDetails::refTo(oldRange));
+ const auto end = QRangeModelDetails::end(QRangeModelDetails::refTo(oldRange));
+ int rowIndex = 0;
+ for (auto it = begin; it != end; ++it, ++rowIndex)
+ impl->autoConnectPropertiesInRow(*it, rowIndex, storage.root());
+ }
+ }
+ }
+
template <typename P>
static auto setParentRow(P protocol, row_type &newRow, row_ptr parentRow)
-> decltype(protocol.setParentRow(std::declval<row_type&>(), std::declval<row_ptr>()))
diff --git a/src/corelib/itemmodels/qrangemodeladapter.qdoc b/src/corelib/itemmodels/qrangemodeladapter.qdoc
index 263bff0dd0c..88872589299 100644
--- a/src/corelib/itemmodels/qrangemodeladapter.qdoc
+++ b/src/corelib/itemmodels/qrangemodeladapter.qdoc
@@ -277,14 +277,6 @@
*/
/*!
- \typedef QRangeModelAdapter::const_row_reference
-*/
-
-/*!
- \typedef QRangeModelAdapter::row_reference
-*/
-
-/*!
\typedef QRangeModelAdapter::range_type
*/
@@ -329,16 +321,39 @@
/*!
\fn template <typename Range, typename Protocol, typename Model> template <typename NewRange, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<NewRange>> void QRangeModelAdapter<Range, Protocol, Model>::setRange(NewRange &&newRange)
- \fn template <typename Range, typename Protocol, typename Model> template <typename NewRange, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<NewRange>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::operator=(NewRange &&newRange)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename NewRange, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<NewRange>, QRangeModelAdapter<Range, Protocol, Model>::unless_adapter<NewRange>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::operator=(NewRange &&newRange)
+
+ Replaces the contents of the model with the rows in \a newRange, possibly
+ using move semantics.
- Assigns \a newRange to the stored range, possibly using move semantics.
This function makes the model() emit the \l{QAbstractItemModel::}{modelAboutToBeReset()}
and \l{QAbstractItemModel::}{modelReset()} signals.
\constraints \c Range is mutable, and \a newRange is of a type that can be
- assigned to \c Range.
+ assigned to \c Range, but not a QRangeModelAdapter.
+
+ \sa range(), at(), model(), assign()
+*/
+
+/*!
+ \fn template <typename Range, typename Protocol, typename Model> template <typename Row, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<std::initializer_list<Row>>> void QRangeModelAdapter<Range, Protocol, Model>::setRange(std::initializer_list<Row> newRange)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename Row, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<std::initializer_list<Row>>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::assign(std::initializer_list<Row> newRange)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename Row, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<std::initializer_list<Row>>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::operator=(std::initializer_list<Row> newRange)
+
+ Replaces the contents of the model with the rows in \a newRange.
- \sa range(), at(), model()
+ \constraints \c Range is mutable, and \a newRange can be assigned to \c Range.
+
+ \sa range(), at, model()
+*/
+
+/*!
+ \fn template <typename Range, typename Protocol, typename Model> template <typename InputIterator, typename Sentinel, typename I = Impl, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> void QRangeModelAdapter<Range, Protocol, Model>::setRange(InputIterator first, Sentinel last)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename InputIterator, typename Sentinel, typename I = Impl, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> void QRangeModelAdapter<Range, Protocol, Model>::assign(InputIterator first, Sentinel last)
+
+ Replaces the contents of the models with the rows in the range [\a first, \a last).
+
+ \sa range(), at, model()
*/
/*!
@@ -508,8 +523,8 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> QRangeModelAdapter<Range, Protocol, Model>::const_row_reference QRangeModelAdapter<Range, Protocol, Model>::at(int row) const
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> QRangeModelAdapter<Range, Protocol, Model>::const_row_reference QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) const
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::at(int row) const
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) const
\return a constant reference to the row at \a row, as stored in \c Range.
@@ -517,8 +532,8 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> QRangeModelAdapter<Range, Protocol, Model>::row_reference QRangeModelAdapter<Range, Protocol, Model>::at(int row)
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> QRangeModelAdapter<Range, Protocol, Model>::row_reference QRangeModelAdapter<Range, Protocol, Model>::operator[](int row)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::at(int row)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::operator[](int row)
\return a mutable reference to the row at \a row, as stored in \c Range.
@@ -574,6 +589,16 @@
*/
/*!
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::at(QSpan<const int> path) const
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::operator[](QSpan<const int> path) const
+
+ \return a constant reference to the row specified by \a path, as stored in
+ \c Range.
+
+ \constraints \c Range is a tree.
+*/
+
+/*!
\fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::at(QSpan<const int> path)
\fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::operator[](QSpan<const int> path)
@@ -810,7 +835,7 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename D, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_data<D>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumn(int before, D &&data)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename D, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_column_data<D>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumn(int before, D &&data)
\overload
Inserts a single column constructed from \a data before the column specified
@@ -838,7 +863,7 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename C, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_data_range<C>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumns(int before, C &&data)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename C, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_column_range<C>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumns(int before, C &&data)
Inserts columns constructed from the elements in \a data before the column
specified by \a before into all rows, and returns whether the insertion was
diff --git a/src/corelib/kernel/qassociativeiterable.h b/src/corelib/kernel/qassociativeiterable.h
index 39f66d45fa0..4f9bbf67bfb 100644
--- a/src/corelib/kernel/qassociativeiterable.h
+++ b/src/corelib/kernel/qassociativeiterable.h
@@ -156,10 +156,12 @@ inline QVariantRef<QAssociativeIterator>::operator QVariant() const
if (!metaType.isValid())
return m_pointer->key();
+ return [&] {
QVariant v(metaType);
metaAssociation.mappedAtIterator(m_pointer->constIterator(),
metaType == QMetaType::fromType<QVariant>() ? &v : v.data());
return v;
+ }();
}
template<>
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index 687fc7e85fa..f5f1f4a8cb8 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -22,6 +22,10 @@
#include <spawn.h>
#include <qdebug.h>
+#include <qpoint.h>
+#include <qsize.h>
+#include <qrect.h>
+#include <qmargins.h>
#include "qendian.h"
#include "qhash.h"
@@ -222,6 +226,34 @@ QDebug operator<<(QDebug dbg, CFStringRef stringRef)
return dbg;
}
+QDebug operator<<(QDebug dbg, CGPoint point)
+{
+ dbg << QPointF::fromCGPoint(point);
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, CGSize size)
+{
+ dbg << QSizeF::fromCGSize(size);
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, CGRect rect)
+{
+ dbg << QRectF::fromCGRect(rect);
+ return dbg;
+}
+
+#if defined(Q_OS_MACOS)
+QDebug operator<<(QDebug dbg, NSEdgeInsets insets)
+#else
+QDebug operator<<(QDebug dbg, UIEdgeInsets insets)
+#endif
+{
+ dbg << QMargins(insets.left, insets.top, insets.right, insets.bottom);
+ return dbg;
+}
+
// Prevents breaking the ODR in case we introduce support for more types
// later on, and lets the user override our default QDebug operators.
#define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 2c4b4c02c55..1e57ee01e1d 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -78,6 +78,15 @@ kern_return_t IOObjectRelease(io_object_t object);
Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
+struct CGPoint;
+struct CGSize;
+struct CGRect;
+#if defined(Q_OS_MACOS)
+struct NSEdgeInsets;
+#else
+struct UIEdgeInsets;
+#endif
+
// @compatibility_alias doesn't work with categories or their methods
#define QtExtras QT_MANGLE_NAMESPACE(QtExtras)
@@ -225,6 +234,14 @@ Q_AUTOTEST_EXPORT void qt_mac_ensureResponsible();
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool);
Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string);
+Q_CORE_EXPORT QDebug operator<<(QDebug, CGPoint);
+Q_CORE_EXPORT QDebug operator<<(QDebug, CGSize);
+Q_CORE_EXPORT QDebug operator<<(QDebug, CGRect);
+#if defined(Q_OS_MACOS)
+Q_CORE_EXPORT QDebug operator<<(QDebug, NSEdgeInsets);
+#else
+Q_CORE_EXPORT QDebug operator<<(QDebug, UIEdgeInsets);
+#endif
#endif
Q_CORE_EXPORT bool qt_apple_isApplicationExtension();
diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm
index 2dddf147f85..d57c057a21a 100644
--- a/src/corelib/kernel/qeventdispatcher_cf.mm
+++ b/src/corelib/kernel/qeventdispatcher_cf.mm
@@ -207,6 +207,7 @@ QEventLoop *QEventDispatcherCoreFoundation::currentEventLoop() const
}
/*!
+ \internal
Processes all pending events that match \a flags until there are no
more events to process. Returns \c true if pending events were handled;
otherwise returns \c false.
diff --git a/src/corelib/kernel/qiterable.h b/src/corelib/kernel/qiterable.h
index baab2897967..494cec73a3f 100644
--- a/src/corelib/kernel/qiterable.h
+++ b/src/corelib/kernel/qiterable.h
@@ -502,7 +502,10 @@ public:
if (m_metaContainer.hasSize())
return m_metaContainer.size(container);
- // ### Qt7: Return -1 here. We shouldn't second-guess the underlying container
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ // We shouldn't second-guess the underlying container, so we're not synthesizing a size.
+ return -1;
+#else
QtPrivate::warnSynthesizedAccess(
"size() called on an iterable without native size accessor. This is slow");
@@ -515,6 +518,7 @@ public:
m_metaContainer.destroyConstIterator(begin);
m_metaContainer.destroyConstIterator(end);
return size;
+#endif
}
void clear()
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index abef9fdd663..21bfe5af448 100644
--- a/src/corelib/kernel/qjniobject.cpp
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -27,7 +27,8 @@ using namespace Qt::StringLiterals;
garbage-collected and providing access to most \c JNIEnv method calls
(member, static) and fields (setter, getter). It eliminates much
boiler-plate that would normally be needed, with direct JNI access, for
- every operation, including exception-handling.
+ every operation. Exceptions thrown by called Java methods are cleared by
+ default, but can since Qt 6.11 also be handled by the caller.
\note This API has been designed and tested for use with Android.
It has not been tested for other platforms.
@@ -129,12 +130,46 @@ using namespace Qt::StringLiterals;
Note that while the first template parameter specifies the return type of the Java
function, the method will still return a QJniObject.
- \section1 Handling Java Exception
+ \section1 Handling Java Exceptions
After calling Java functions that might throw exceptions, it is important
to check for, handle and clear out any exception before continuing. All
- QJniObject functions handle exceptions internally by reporting and clearing them,
- saving client code the need to handle exceptions.
+ QJniObject functions can handle exceptions internally by reporting and
+ clearing them. This includes JNI exceptions, for instance when trying to
+ call a method that doesn't exist, or with bad parameters; and exceptions
+ are thrown by the method as a way of reporting errors or returning failure
+ information.
+
+ From Qt 6.11 on, client code can opt in to handle exceptions explicitly in
+ each call. To do so, use \c{std::expected} from C++ 23 as the return type,
+ with the value type as the expected, and \c{jthrowable} as the error type.
+ For instance, trying to read a setting value via the
+ \c{android.provider.Settings.Secure} type might throw an exception if the
+ setting does not exist.
+
+ \code
+ Q_DECLARE_JNI_CLASS(SettingsSecure, "android/provider/Settings$Secure")
+ using namespace QtJniTypes;
+
+ QString enabledInputMethods()
+ {
+ ContentResolver resolver;
+ SettingsSecure settings;
+
+ auto defaultInputMethods = settings.callMethod<std::expected<QString, jthrowable>>(
+ "getString", resolver, u"enabled_input_methods"_s
+ );
+ if (defaultInputMethods)
+ return defaultInputMethods.value();
+ QStringList stackTrace = QJniEnvironment::stackTrace(defaultInputMethods.error());
+ }
+ \endcode
+
+ You can use any other type that behaves like \c{std::expected}, so handling
+ exceptions explicitly is possible without using C++23. The only
+ requirements are that the type declares three nested types \c{value_type},
+ \c{error_type}, and \c{unexpected_type}, can be constructed from the value
+ type, and from its \c{unexpected_type} holding a \c{jthrowable}.
\note The user must handle exceptions manually when doing JNI calls using \c JNIEnv directly.
It is unsafe to make other JNI calls when exceptions are pending. For more information, see
@@ -921,7 +956,10 @@ QByteArray QJniObject::className() const
jint size = myJavaString.callMethod<jint>("length");
\endcode
- The method signature is deduced at compile time from \c Ret and the types of \a args.
+ The method signature is deduced at compile time from \c Ret and the types
+ of \a args. \c Ret can be a \c{std::expected}-compatible type that returns
+ a value, or \l{Handling Java Exceptions}{any Java exception thrown} by the
+ called method.
*/
/*!
@@ -952,7 +990,10 @@ QByteArray QJniObject::className() const
jint value = QJniObject::callStaticMethod<jint>("MyClass", "staticMethod");
\endcode
- The method signature is deduced at compile time from \c Ret and the types of \a args.
+ The method signature is deduced at compile time from \c Ret and the types
+ of \a args. \c Ret can be a \c{std::expected}-compatible type that returns
+ a value, or \l{Handling Java Exceptions}{any Java exception thrown} by the
+ called method.
*/
/*!
@@ -1009,7 +1050,10 @@ QByteArray QJniObject::className() const
jdouble randNr = QJniObject::callStaticMethod<jdouble>(javaMathClass, "random");
\endcode
- The method signature is deduced at compile time from \c Ret and the types of \a args.
+ The method signature is deduced at compile time from \c Ret and the types
+ of \a args. \c Ret can be a \c{std::expected}-compatible type that returns
+ a value, or \l{Handling Java Exceptions}{any Java exception thrown} by the
+ called method.
*/
/*!
@@ -1020,8 +1064,12 @@ QByteArray QJniObject::className() const
\c Ret (unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
be a QJniObject.
- The method signature is deduced at compile time from \c Ret and the types of \a args.
- \c Klass needs to be a C++ type with a registered type mapping to a Java type.
+ The method signature is deduced at compile time from \c Ret and the types
+ of \a args. \c Klass needs to be a C++ type with a registered type mapping
+ to a Java type. \c Ret can be a \c{std::expected}-compatible type that
+ returns a value, or \l{Handling Java Exceptions}{any Java exception thrown}
+ by the called method.
+
*/
/*!
@@ -1150,7 +1198,10 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
QJniObject myJavaString2 = myJavaString1.callObjectMethod<jstring>("toString");
\endcode
- The method signature is deduced at compile time from \c Ret and the types of \a args.
+ The method signature is deduced at compile time from \c Ret and the types
+ of \a args. \c Ret can be a \c{std::expected}-compatible type that returns
+ a value, or \l{Handling Java Exceptions}{any Java exception thrown} by the
+ called method.
*/
/*!
@@ -1164,7 +1215,10 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
QJniObject string = QJniObject::callStaticObjectMethod<jstring>("CustomClass", "getClassName");
\endcode
- The method signature is deduced at compile time from \c Ret and the types of \a args.
+ The method signature is deduced at compile time from \c Ret and the types
+ of \a args. \c Ret can be a \c{std::expected}-compatible type that returns
+ a value, or \l{Handling Java Exceptions}{any Java exception thrown} by the
+ called method.
*/
/*!
diff --git a/src/corelib/kernel/qmetaassociation.h b/src/corelib/kernel/qmetaassociation.h
index 6d8de13e90a..d481ae91079 100644
--- a/src/corelib/kernel/qmetaassociation.h
+++ b/src/corelib/kernel/qmetaassociation.h
@@ -25,8 +25,8 @@ public:
using reference = QVariant::Reference<AssociativeIterator>;
using pointer = QVariant::Pointer<AssociativeIterator>;
- static constexpr bool canNoexceptAssignQVariant = false;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptAssignQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
AssociativeIterator(QIterator &&it) : QIterator(std::move(it)) {}
@@ -51,7 +51,7 @@ public:
using reference = QVariant::ConstReference<AssociativeConstIterator>;
using pointer = QVariant::ConstPointer<AssociativeConstIterator>;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
AssociativeConstIterator(QConstIterator &&it) : QConstIterator(std::move(it)) {}
diff --git a/src/corelib/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h
index c9d3a6bf9c6..66047afefd4 100644
--- a/src/corelib/kernel/qmetacontainer.h
+++ b/src/corelib/kernel/qmetacontainer.h
@@ -971,18 +971,11 @@ public:
Iterator mutableEnd();
QVariant at(qsizetype idx) const;
- void set(qsizetype idx, const QVariant &value);
+ void setAt(qsizetype idx, const QVariant &value);
void append(const QVariant &value);
void prepend(const QVariant &value);
void removeLast();
void removeFirst();
-
-#if QT_DEPRECATED_SINCE(6, 11)
- enum Position: quint8 { Unspecified, AtBegin, AtEnd };
- void addValue(const QVariant &value, Position position = Unspecified);
- void removeValue(Position position = Unspecified);
- QMetaType valueMetaType() const;
-#endif // QT_DEPRECATED_SINCE(6, 11)
};
#else
using Iterable = QtMetaContainerPrivate::Sequence;
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 24cc58829c8..c7e50788b45 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -469,6 +469,33 @@ QMetaType QMetaObject::metaType() const
}
}
+static inline QByteArrayView objectMetaObjectHash(const QMetaObject *m)
+{
+ // metaObjectHash didn't exist before revision 14
+ if (QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && priv(m->d.data)->revision < 14)
+ return {};
+ const auto index = priv(m->d.data)->metaObjectHashIndex;
+ if (index == -1)
+ return {};
+ return stringDataView(m, index);
+}
+
+/*!
+ \since 6.11
+
+ Returns the revisioned hash of the contents of this QMetaObject or nullptr.
+
+ The hash has the following format <hash_revision>$<hash_b64>, where
+ hash_revision is an integer and hash_b64 is the base64 encoding of the
+ hash.
+
+ Note that only hashes of the same revision should be compared.
+*/
+const char *QMetaObject::metaObjectHash() const
+{
+ return objectMetaObjectHash(this).constData();
+}
+
/*!
Returns the method offset for this class; i.e. the index position
of this class's first member function.
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index bfda30fda28..7264d2a956f 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -124,6 +124,7 @@ struct QMetaObjectPrivate
int constructorCount, constructorData;
int flags;
int signalCount;
+ int metaObjectHashIndex;
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index 6065bf2baea..9af6de73680 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -558,6 +558,8 @@ QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty &protot
property.setEnumOrFlag(prototype.isEnumType());
property.setConstant(prototype.isConstant());
property.setFinal(prototype.isFinal());
+ property.setVirtual(prototype.isVirtual());
+ property.setOverride(prototype.isOverride());
property.setRevision(prototype.revision());
if (prototype.hasNotifySignal()) {
// Find an existing method for the notify signal, or add a new one.
@@ -1177,10 +1179,11 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
int methodParametersDataSize = aggregateParameterCount(d->methods)
+ aggregateParameterCount(d->constructors);
if constexpr (mode == Construct) {
- static_assert(QMetaObjectPrivate::OutputRevision == 13, "QMetaObjectBuilder should generate the same version as moc");
+ static_assert(QMetaObjectPrivate::OutputRevision == 14, "QMetaObjectBuilder should generate the same version as moc");
pmeta->revision = QMetaObjectPrivate::OutputRevision;
pmeta->flags = d->flags.toInt() | AllocatedMetaObject;
pmeta->className = 0; // Class name is always the first string.
+ pmeta->metaObjectHashIndex = -1; // TODO support hash in the builder too
//pmeta->signalCount is handled in the "output method loop" as an optimization.
pmeta->classInfoCount = d->classInfoNames.size();
@@ -2068,6 +2071,32 @@ bool QMetaPropertyBuilder::isFinal() const
}
/*!
+ Returns \c true if the property is virtual; otherwise returns \c false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isVirtual() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Virtual);
+ else
+ return false;
+}
+
+/*!
+ Returns \c true if the property does override; otherwise returns \c false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isOverride() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Override);
+ else
+ return false;
+}
+
+/*!
* Returns \c true if the property is an alias.
* The default value is false
*/
@@ -2239,6 +2268,30 @@ void QMetaPropertyBuilder::setFinal(bool value)
}
/*!
+ Sets the \c VIRTUAL flag on this property to \a value.
+
+ \sa isFinal()
+*/
+void QMetaPropertyBuilder::setVirtual(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Virtual, value);
+}
+
+/*!
+ Sets the \c OVERRIDE flag on this property to \a value.
+
+ \sa isOverride()
+*/
+void QMetaPropertyBuilder::setOverride(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Override, value);
+}
+
+/*!
Sets the \c ALIAS flag on this property to \a value
*/
void QMetaPropertyBuilder::setAlias(bool value)
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
index 563704d60e6..9591944602a 100644
--- a/src/corelib/kernel/qmetaobjectbuilder_p.h
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -214,6 +214,8 @@ public:
bool isEnumOrFlag() const;
bool isConstant() const;
bool isFinal() const;
+ bool isVirtual() const;
+ bool isOverride() const;
bool isAlias() const;
bool isBindable() const;
bool isRequired() const;
@@ -229,6 +231,8 @@ public:
void setEnumOrFlag(bool value);
void setConstant(bool value);
void setFinal(bool value);
+ void setVirtual(bool value);
+ void setOverride(bool value);
void setAlias(bool value);
void setBindable(bool value);
void setRequired(bool value);
diff --git a/src/corelib/kernel/qmetasequence.cpp b/src/corelib/kernel/qmetasequence.cpp
index 2a3a923d5ca..018dd610146 100644
--- a/src/corelib/kernel/qmetasequence.cpp
+++ b/src/corelib/kernel/qmetasequence.cpp
@@ -531,39 +531,6 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con
*/
/*!
- \enum QMetaSequence::Iterable::Position
- \deprecated [6.11] Use append(), prepend(), removeFirst(), or removeLast()
-
- Specifies the position at which an element shall be added to or removed from
- the iterable.
-
- \value AtBegin
- Add or remove at the beginning of the iterable.
- \value AtEnd
- Add or remove at the end of the iterable.
- \value Unspecified
- Add or remove at an unspecified position in the iterable.
- */
-
-/*!
- \fn void QMetaSequence::Iterable::addValue(const QVariant &value, Position position)
- \deprecated [6.11] Use append() or prepend()
- Adds \a value to the container, at \a position, if possible.
- */
-
-/*!
- \deprecated [6.11] Use removeFirst() or removeLast()
- \fn void QMetaSequence::Iterable::removeValue(Position position)
- Removes a value from the container, at \a position, if possible.
- */
-
-/*!
- \deprecated [6.11] Use QMetaSequence::valueMetaType()
- \fn QMetaType QMetaSequence::Iterable::valueMetaType() const
- Returns the meta type for values stored in the underlying container.
- */
-
-/*!
\fn QVariant QMetaSequence::Iterable::at(qsizetype idx) const
Returns the value at position \a idx in the container.
@@ -574,13 +541,8 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con
*/
/*!
- \fn void QMetaSequence::Iterable::set(qsizetype idx, const QVariant &value)
+ \fn void QMetaSequence::Iterable::setAt(qsizetype idx, const QVariant &value)
Sets the element at position \a idx in the container to \a value.
-
- \note If the underlying container does not provide a native way to assign
- an element at an index, this method will synthesize the assignment
- using iterators. This behavior is deprecated and will be removed in a
- future version of Qt.
*/
/*!
diff --git a/src/corelib/kernel/qmetasequence.h b/src/corelib/kernel/qmetasequence.h
index e9505054159..f8052476d79 100644
--- a/src/corelib/kernel/qmetasequence.h
+++ b/src/corelib/kernel/qmetasequence.h
@@ -24,8 +24,8 @@ public:
using reference = QVariant::Reference<SequentialIterator>;
using pointer = QVariant::Pointer<SequentialIterator>;
- static constexpr bool canNoexceptAssignQVariant = false;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptAssignQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
SequentialIterator(QIterator &&it) : QIterator(std::move(it)) {}
@@ -41,7 +41,7 @@ public:
using reference = QVariant::ConstReference<SequentialConstIterator>;
using pointer = QVariant::ConstPointer<SequentialConstIterator>;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
SequentialConstIterator(QConstIterator &&it) : QConstIterator(std::move(it)) {}
@@ -184,33 +184,23 @@ public:
return;
}
- // ### Qt7: Drop this code. We shouldn't second-guess the underlying container
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ // We shouldn't second-guess the underlying container.
QtPrivate::warnSynthesizedAccess(
"at() called on an iterable without native indexed accessors. This is slow");
void *it = meta.constBegin(m_iterable.constPointer());
meta.advanceConstIterator(it, idx);
meta.valueAtConstIterator(it, dataPtr);
meta.destroyConstIterator(it);
+#endif
});
}
- void set(qsizetype idx, const QVariant &value)
+ void setAt(qsizetype idx, const QVariant &value)
{
const QMetaSequence meta = metaContainer();
QtPrivate::QVariantTypeCoercer coercer;
- const void *dataPtr = coercer.coerce(value, meta.valueMetaType());
- if (meta.canSetValueAtIndex()) {
- meta.setValueAtIndex(mutableIterable(), idx, dataPtr);
- return;
- }
-
- // ### Qt7: Drop this code. We shouldn't second-guess the underlying container
- QtPrivate::warnSynthesizedAccess(
- "set() called on an iterable without native indexed accessors. This is slow");
- void *it = meta.begin(m_iterable.mutablePointer());
- meta.advanceIterator(it, idx);
- meta.setValueAtIterator(it, dataPtr);
- meta.destroyIterator(it);
+ meta.setValueAtIndex(mutableIterable(), idx, coercer.coerce(value, meta.valueMetaType()));
}
void append(const QVariant &value)
@@ -248,55 +238,17 @@ public:
Unspecified, AtBegin, AtEnd
};
- QT_DEPRECATED_VERSION_X_6_11("Use append() or prepend() instead.")
void addValue(const QVariant &value, Position position = Unspecified)
- {
- const QMetaSequence meta = metaContainer();
- QtPrivate::QVariantTypeCoercer coercer;
- const void *valuePtr = coercer.coerce(value, meta.valueMetaType());
-
- switch (position) {
- case AtBegin:
- if (meta.canAddValueAtBegin())
- meta.addValueAtBegin(mutableIterable(), valuePtr);
- break;
- case AtEnd:
- if (meta.canAddValueAtEnd())
- meta.addValueAtEnd(mutableIterable(), valuePtr);
- break;
- case Unspecified:
- if (meta.canAddValue())
- meta.addValue(mutableIterable(), valuePtr);
- break;
- }
- }
+ Q_DECL_EQ_DELETE_X("Use append() or prepend() instead.");
- QT_DEPRECATED_VERSION_X_6_11("Use removeLast() or removeFirst() instead.")
void removeValue(Position position = Unspecified)
- {
- const QMetaSequence meta = metaContainer();
-
- switch (position) {
- case AtBegin:
- if (meta.canRemoveValueAtBegin())
- meta.removeValueAtBegin(mutableIterable());
- break;
- case AtEnd:
- if (meta.canRemoveValueAtEnd())
- meta.removeValueAtEnd(mutableIterable());
- break;
- case Unspecified:
- if (meta.canRemoveValue())
- meta.removeValue(mutableIterable());
- break;
- }
- }
+ Q_DECL_EQ_DELETE_X("Use removeLast() or removeFirst() instead.");
- QT_DEPRECATED_VERSION_X_6_11("Use QMetaSequence::valueMetaType() instead.")
QMetaType valueMetaType() const
- {
- return metaContainer().valueMetaType();
- }
+ Q_DECL_EQ_DELETE_X("Use QMetaSequence::valueMetaType() instead.");
+
+ void set(qsizetype idx, const QVariant &value)
+ Q_DECL_EQ_DELETE_X("Use setAt() instead.");
QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(6, 11)
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 848102cc57a..d3e761982f5 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -247,6 +247,8 @@ struct Q_CORE_EXPORT QMetaObject
QMetaType metaType() const;
+ const char *metaObjectHash() const;
+
int methodOffset() const;
int enumeratorOffset() const;
int propertyOffset() const;
diff --git a/src/corelib/kernel/qpermissions.cpp b/src/corelib/kernel/qpermissions.cpp
index 6767917e176..69383dafdd9 100644
--- a/src/corelib/kernel/qpermissions.cpp
+++ b/src/corelib/kernel/qpermissions.cpp
@@ -119,7 +119,7 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
To ensure the relevant permission backend is included with your
application, please \l {QT_ANDROID_PACKAGE_SOURCE_DIR}
{point the build system to your custom \c AndroidManifest.xml}
- or use \l {qt_add_android_permission()}.
+ or use \l {qt_add_android_permission}().
The relevant permission names are described in the documentation
for each permission type.
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index d538ed7b4e9..9141a8f8bad 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -402,6 +402,16 @@ QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRec
}
/*!
+ \class QUntypedPropertyBinding
+ \inmodule QtCore
+ \since 6.0
+ \ingroup tools
+ \brief Represents a type-erased property binding.
+
+ \sa QUntypedBindable
+*/
+
+/*!
Constructs a null QUntypedPropertyBinding.
\sa isNull()
@@ -409,8 +419,8 @@ QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRec
QUntypedPropertyBinding::QUntypedPropertyBinding() = default;
/*!
- \fn template<typename Functor>
- QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
+ \fn template<typename Functor> QUntypedPropertyBinding(
+ QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
\internal
*/
@@ -448,7 +458,6 @@ QUntypedPropertyBinding::QUntypedPropertyBinding(const QUntypedPropertyBinding &
: d(other.d)
{
}
-
/*!
Copy-assigns \a other to this QUntypedPropertyBinding.
*/
@@ -1183,7 +1192,7 @@ QString QPropertyBindingError::description() const
\return \c true when the binding was successfully set.
- //! \sa QUntypedPropertyBinding::valueMetaType()
+ \sa QUntypedPropertyBinding::valueMetaType()
*/
/*!
@@ -1199,8 +1208,7 @@ QString QPropertyBindingError::description() const
Returns the metatype of the property from which the QUntypedBindable was created.
If the bindable is invalid, an invalid metatype will be returned.
- \sa isValid()
- //! \sa QUntypedPropertyBinding::valueMetaType()
+ \sa isValid(), QUntypedPropertyBinding::valueMetaType()
*/
/*!
diff --git a/src/corelib/kernel/qsequentialiterable.h b/src/corelib/kernel/qsequentialiterable.h
index 92252cb19dd..76908bdae4b 100644
--- a/src/corelib/kernel/qsequentialiterable.h
+++ b/src/corelib/kernel/qsequentialiterable.h
@@ -142,10 +142,13 @@ inline QVariantRef<QSequentialIterator>::operator QVariant() const
if (m_pointer == nullptr)
return QVariant();
const QMetaType metaType(m_pointer->metaContainer().valueMetaType());
+
+ return [&] {
QVariant v(metaType);
void *dataPtr = metaType == QMetaType::fromType<QVariant>() ? &v : v.data();
m_pointer->metaContainer().valueAtIterator(m_pointer->constIterator(), dataPtr);
return v;
+ }();
}
template<>
diff --git a/src/corelib/kernel/qtmocconstants.h b/src/corelib/kernel/qtmocconstants.h
index 260ac2fa5f8..822e02e6c8e 100644
--- a/src/corelib/kernel/qtmocconstants.h
+++ b/src/corelib/kernel/qtmocconstants.h
@@ -30,7 +30,8 @@ namespace QtMocConstants {
// revision 11 is Qt 6.5: The metatype for void is stored in the metatypes array
// revision 12 is Qt 6.6: It adds the metatype for enums
// revision 13 is Qt 6.9: Adds support for 64-bit QFlags and moves the method revision
-enum { OutputRevision = 13 }; // Used by moc, qmetaobjectbuilder and qdbus
+// revision 14 is Qt 6.11: Adds a hash of meta object contents
+enum { OutputRevision = 14 }; // Used by moc, qmetaobjectbuilder and qdbus
enum PropertyFlags : uint {
Invalid = 0x00000000,
diff --git a/src/corelib/kernel/qtmochelpers.h b/src/corelib/kernel/qtmochelpers.h
index 4c549e78ad5..3d2b59d2a73 100644
--- a/src/corelib/kernel/qtmochelpers.h
+++ b/src/corelib/kernel/qtmochelpers.h
@@ -511,7 +511,8 @@ template <typename ObjectType, typename Unique, typename Strings,
typename Constructors = UintData<>, typename ClassInfo = detail::UintDataBlock<0, 0>>
constexpr auto metaObjectData(uint flags, const Strings &strings,
const Methods &methods, const Properties &properties,
- const Enums &enums, const Constructors &constructors = {},
+ const Enums &enums, int qt_metaObjectHashIndex = -1,
+ const Constructors &constructors = {},
const ClassInfo &classInfo = {})
{
constexpr uint MetaTypeCount = Properties::metaTypeCount()
@@ -520,7 +521,7 @@ constexpr auto metaObjectData(uint flags, const Strings &strings,
+ Methods::metaTypeCount()
+ Constructors::metaTypeCount();
- constexpr uint HeaderSize = 14;
+ constexpr uint HeaderSize = 15;
constexpr uint TotalSize = HeaderSize
+ Properties::dataSize()
+ Enums::dataSize()
@@ -582,6 +583,8 @@ constexpr auto metaObjectData(uint flags, const Strings &strings,
}
}
+ data[14] = qt_metaObjectHashIndex;
+
return result;
}
diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp
index 9fdac89f775..6000edaa177 100644
--- a/src/corelib/kernel/qtranslator.cpp
+++ b/src/corelib/kernel/qtranslator.cpp
@@ -392,8 +392,8 @@ public:
translation files may contain misleading or malicious translations.
\sa QCoreApplication::installTranslator(), QCoreApplication::removeTranslator(),
- QObject::tr(), QCoreApplication::translate(), {I18N Example},
- {Hello tr() Example}, {Arrow Pad Example}, {Troll Print Example}
+ QObject::tr(), QCoreApplication::translate(),
+ {Localized Clock Example}, {Arrow Pad Example}, {Troll Print Example}
*/
/*!
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 82eec0693d6..19cd1fea7fb 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -263,7 +263,7 @@ public:
ConstReference &operator=(ConstReference &&value) = delete;
// To be specialized for each Referred
- operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant);
+ operator QVariant() const noexcept(Referred::CanNoexceptConvertToQVariant);
};
template<typename Referred>
@@ -288,18 +288,18 @@ public:
~Reference() = default;
Reference &operator=(const Reference &value)
- noexcept(Referred::canNoexceptAssignQVariant)
+ noexcept(Referred::CanNoexceptAssignQVariant)
{
return operator=(QVariant(value));
}
Reference &operator=(Reference &&value)
- noexcept(Referred::canNoexceptAssignQVariant)
+ noexcept(Referred::CanNoexceptAssignQVariant)
{
return operator=(QVariant(value));
}
- operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant)
+ operator QVariant() const noexcept(Referred::CanNoexceptConvertToQVariant)
{
return ConstReference(m_referred);
}
@@ -313,7 +313,7 @@ public:
}
// To be specialized for each Referred
- Reference &operator=(const QVariant &value) noexcept(Referred::canNoexceptAssignQVariant);
+ Reference &operator=(const QVariant &value) noexcept(Referred::CanNoexceptAssignQVariant);
};
template<typename Pointed>
diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp
index 9c26de94b6d..ecd1ac77779 100644
--- a/src/corelib/mimetypes/qmimeprovider.cpp
+++ b/src/corelib/mimetypes/qmimeprovider.cpp
@@ -517,13 +517,15 @@ QMimeBinaryProvider::loadMimeTypeExtra(const QString &mimeName)
// load comment and globPatterns
// shared-mime-info since 1.3 lowercases the xml files
- QString mimeFile = m_directory + u'/' + mimeName.toLower() + ".xml"_L1;
- if (!QFile::exists(mimeFile))
- mimeFile = m_directory + u'/' + mimeName + ".xml"_L1; // pre-1.3
-
- QFile qfile(mimeFile);
- if (!qfile.open(QFile::ReadOnly))
- return it;
+ QFile qfile;
+ const QString mimeFile = m_directory + u'/' + mimeName.toLower() + ".xml"_L1;
+ qfile.setFileName(mimeFile);
+ if (!qfile.open(QFile::ReadOnly)) {
+ const QString fallbackMimeFile = m_directory + u'/' + mimeName + ".xml"_L1; // pre-1.3
+ qfile.setFileName(fallbackMimeFile);
+ if (!qfile.open(QFile::ReadOnly))
+ return it;
+ }
MimeTypeExtra &extra = it->second;
QString mainPattern;
diff --git a/src/corelib/platform/windows/qbstr_p.h b/src/corelib/platform/windows/qbstr_p.h
index 21eecfe2df7..32b1aace76f 100644
--- a/src/corelib/platform/windows/qbstr_p.h
+++ b/src/corelib/platform/windows/qbstr_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QBSTR_P_H
#define QBSTR_P_H
@@ -141,4 +142,4 @@ QT_END_NAMESPACE
#endif // Q_OS_WIN
-#endif // QCOMPTR_P_H
+#endif // QBSTR_P_H
diff --git a/src/corelib/platform/windows/qcomobject_p.h b/src/corelib/platform/windows/qcomobject_p.h
index bd6f81d1c28..b7a9c56555d 100644
--- a/src/corelib/platform/windows/qcomobject_p.h
+++ b/src/corelib/platform/windows/qcomobject_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QCOMOBJECT_P_H
#define QCOMOBJECT_P_H
diff --git a/src/corelib/platform/windows/qcomptr_p.h b/src/corelib/platform/windows/qcomptr_p.h
index 2a69e7b6038..e640528d3c2 100644
--- a/src/corelib/platform/windows/qcomptr_p.h
+++ b/src/corelib/platform/windows/qcomptr_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QCOMPTR_P_H
#define QCOMPTR_P_H
diff --git a/src/corelib/platform/windows/qcomvariant_p.h b/src/corelib/platform/windows/qcomvariant_p.h
index 34ce5f179ce..cc4ad104106 100644
--- a/src/corelib/platform/windows/qcomvariant_p.h
+++ b/src/corelib/platform/windows/qcomvariant_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QCOMVARIANT_P_H
#define QCOMVARIANT_P_H
diff --git a/src/corelib/platform/windows/qfactorycacheregistration.cpp b/src/corelib/platform/windows/qfactorycacheregistration.cpp
index 6bd69c66d14..04c81b7b665 100644
--- a/src/corelib/platform/windows/qfactorycacheregistration.cpp
+++ b/src/corelib/platform/windows/qfactorycacheregistration.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#include "qfactorycacheregistration_p.h"
diff --git a/src/corelib/platform/windows/qfactorycacheregistration_p.h b/src/corelib/platform/windows/qfactorycacheregistration_p.h
index d0b19b995b4..f6e7d9eb064 100644
--- a/src/corelib/platform/windows/qfactorycacheregistration_p.h
+++ b/src/corelib/platform/windows/qfactorycacheregistration_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QFACTORYCACHEREGISTRATION_P_H
#define QFACTORYCACHEREGISTRATION_P_H
diff --git a/src/corelib/platform/windows/qt_winrtbase_p.h b/src/corelib/platform/windows/qt_winrtbase_p.h
index 79c2bdf6b1c..69a602a59e0 100644
--- a/src/corelib/platform/windows/qt_winrtbase_p.h
+++ b/src/corelib/platform/windows/qt_winrtbase_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QT_WINRTBASE_P_H
#define QT_WINRTBASE_P_H
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index 13d74e591d5..0aeb2b07f47 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -975,6 +975,7 @@ QCborContainerPrivate *QCborContainerPrivate::detach(QCborContainerPrivate *d, q
}
/*!
+ \internal
Prepare for an insertion at position \a index
Detaches and ensures there are at least index entries in the array, padding
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index ae3bed5b751..fd2f7faeee5 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -552,6 +552,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_6_9
\value Qt_6_10
\value Qt_6_11
+ \value Qt_6_12
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 04373fe9c8a..d6fcf17efcd 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -96,8 +96,9 @@ public:
Qt_6_9 = Qt_6_7,
Qt_6_10 = 23,
Qt_6_11 = 24,
- Qt_DefaultCompiledVersion = Qt_6_11
-#if QT_VERSION >= QT_VERSION_CHECK(6, 12, 0)
+ Qt_6_12 = Qt_6_11,
+ Qt_DefaultCompiledVersion = Qt_6_12
+#if QT_VERSION >= QT_VERSION_CHECK(6, 13, 0)
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
};
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index 9cd90fa9d65..ff70289013a 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -3678,7 +3678,7 @@ void QXmlStreamWriter::setStopWritingOnError(bool stop)
The error status is never reset. Writes happening after the error
occurred may be ignored, even if the error condition is cleared.
- \sa error(), errorString(), raiseError(const QString &message),
+ \sa error(), errorString(), raiseError()
*/
bool QXmlStreamWriter::hasError() const
{
@@ -3692,7 +3692,7 @@ bool QXmlStreamWriter::hasError() const
QXmlStreamWriter::Error::None.
\since 6.10
- \sa errorString(), raiseError(const QString &message), hasError()
+ \sa errorString(), raiseError(), hasError()
*/
QXmlStreamWriter::Error QXmlStreamWriter::error() const
{
@@ -3708,7 +3708,7 @@ QXmlStreamWriter::Error QXmlStreamWriter::error() const
a null string.
\since 6.10
- \sa error(), raiseError(const QString &message), hasError()
+ \sa error(), raiseError(), hasError()
*/
QString QXmlStreamWriter::errorString() const
{
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index fed09aee45e..18007cacae6 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -301,6 +301,7 @@ bool operator<(LikelyPair lhs, LikelyPair rhs)
} // anonymous namespace
/*!
+ \internal
Fill in blank fields of a locale ID.
An ID in which some fields are zero stands for any locale that agrees with
diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp
index bf6e776ee0e..896142b4837 100644
--- a/src/corelib/text/qstringconverter.cpp
+++ b/src/corelib/text/qstringconverter.cpp
@@ -2739,7 +2739,7 @@ QStringList QStringConverter::availableCodecs()
May also provide data from residual content that was pending decoding.
When there is no residual data to account for, the return's \c error
- field will be set to \l {QCharConverter::FinalizeResult::Error::}
+ field will be set to \l {QStringConverter::FinalizeResultChar::error}
{NoError}.
If \a out is supplied and non-null, it must have space in which up to
@@ -2793,7 +2793,7 @@ auto QStringDecoder::finalize(char16_t *out, qsizetype maxlen) -> FinalizeResult
May also provide data from residual content that was pending decoding.
When there is no residual data to account for, the return's \c error
- field will be set to \l {QCharConverter::FinalizeResult::Error::}
+ field will be set to \l {QStringConverter::FinalizeResultChar::error}
{NoError}.
If \a out is supplied and non-null, it must have space in which up to
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index f3f32e20adc..5e97086694b 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -786,7 +786,7 @@
between the second and third result, and returns the second result; and
so on.
- \image javaiterators1.png
+ \image javaiterators1.svg
Here's how to iterate over the elements in reverse order:
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 371ee524d72..d6c185cd704 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -845,7 +845,7 @@ struct UnwrapHandler
using NestedType = typename QtPrivate::Future<ResultType>::type;
QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending);
- outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
+ auto chain = outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
// We use the .then([](QFuture<ResultType> outerFuture) {...}) version
// (where outerFuture == *outer), to propagate the exception if the
// outer future has failed.
@@ -883,6 +883,13 @@ struct UnwrapHandler
promise.reportCanceled();
promise.reportFinished();
});
+
+ // Inject the promise into the chain.
+ // We use a fake function as a continuation, since the promise is
+ // managed by the outer future
+ chain.d.setContinuation(ContinuationWrapper(std::move([](const QFutureInterfaceBase &) {})),
+ promise.d, QFutureInterfaceBase::ContinuationType::Then);
+
return promise.future();
}
};
diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h
index 0b88013800e..ff17560d3a1 100644
--- a/src/corelib/thread/qfutureinterface.h
+++ b/src/corelib/thread/qfutureinterface.h
@@ -42,6 +42,8 @@ template<class Function, class ResultType>
class FailureHandler;
#endif
+struct UnwrapHandler;
+
#if QT_CORE_REMOVED_SINCE(6, 10)
void Q_CORE_EXPORT watchContinuationImpl(const QObject *context,
QtPrivate::QSlotObjectBase *slotObj,
@@ -187,6 +189,8 @@ private:
friend class QtPrivate::FailureHandler;
#endif
+ friend struct QtPrivate::UnwrapHandler;
+
#if QT_CORE_REMOVED_SINCE(6, 10)
friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl(
const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi);
diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp
index 96e35dcb965..2a1af2315ca 100644
--- a/src/corelib/thread/qreadwritelock.cpp
+++ b/src/corelib/thread/qreadwritelock.cpp
@@ -234,14 +234,14 @@ QBasicReadWriteLock::contendedTryLockForRead(QDeadlineTimer timeout, void *dd)
return d->recursiveLockForRead(timeout);
auto lock = qt_unique_lock(d->mutex);
- if (d != d_ptr.loadRelaxed()) {
+ if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
// d_ptr has changed: this QReadWriteLock was unlocked before we had
// time to lock d->mutex.
// We are holding a lock to a mutex within a QReadWriteLockPrivate
// that is already released (or even is already re-used). That's ok
// because the QFreeList never frees them.
// Just unlock d->mutex (at the end of the scope) and retry.
- d = d_ptr.loadAcquire();
+ d = dd;
continue;
}
return d->lockForRead(lock, timeout);
@@ -340,11 +340,11 @@ QBasicReadWriteLock::contendedTryLockForWrite(QDeadlineTimer timeout, void *dd)
return d->recursiveLockForWrite(timeout);
auto lock = qt_unique_lock(d->mutex);
- if (d != d_ptr.loadRelaxed()) {
+ if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
// The mutex was unlocked before we had time to lock the mutex.
// We are holding to a mutex within a QReadWriteLockPrivate that is already released
// (or even is already re-used) but that's ok because the QFreeList never frees them.
- d = d_ptr.loadAcquire();
+ d = dd;
continue;
}
return d->lockForWrite(lock, timeout);
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index 10882738a39..05ba3d2beae 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -2389,6 +2389,7 @@ bool operator==(QDateTimeParser::SectionNode s1, QDateTimeParser::SectionNode s2
}
/*!
+ \internal
Sets \a cal as the calendar to use. The default is Gregorian.
*/
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 1c0371e463e..d173d824e88 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -162,7 +162,7 @@ allocateHelper(QArrayData **dptr, qsizetype objectSize, qsizetype alignment, qsi
QArrayData::AllocationOption option) noexcept
{
*dptr = nullptr;
- if (capacity == 0)
+ if (capacity <= 0)
return {};
const qsizetype headerSize = calculateHeaderSize(alignment);
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index de68a0042ac..1e647a83dc0 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -332,15 +332,13 @@ struct TCBPoint
qreal _c;
qreal _b;
- TCBPoint() {}
- TCBPoint(QPointF point, qreal t, qreal c, qreal b) : _point(point), _t(t), _c(c), _b(b) {}
- bool operator==(const TCBPoint &other) const
+ friend bool operator==(const TCBPoint &lhs, const TCBPoint &rhs) noexcept
{
- return _point == other._point &&
- qFuzzyCompare(_t, other._t) &&
- qFuzzyCompare(_c, other._c) &&
- qFuzzyCompare(_b, other._b);
+ return qFuzzyCompare(lhs._point, rhs._point)
+ && QtPrivate::fuzzyCompare(lhs._t, rhs._t)
+ && QtPrivate::fuzzyCompare(lhs._c, rhs._c)
+ && QtPrivate::fuzzyCompare(lhs._b, rhs._b);
}
};
Q_DECLARE_TYPEINFO(TCBPoint, Q_PRIMITIVE_TYPE);
@@ -1381,7 +1379,7 @@ void QEasingCurve::addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qre
if (!d_ptr->config)
d_ptr->config = curveToFunctionObject(d_ptr->type);
- d_ptr->config->_tcbPoints.append(TCBPoint(nextPoint, t, c, b));
+ d_ptr->config->_tcbPoints.append(TCBPoint{nextPoint, t, c, b});
if (nextPoint == QPointF(1.0, 1.0)) {
d_ptr->config->_bezierCurves = tcbToBezier(d_ptr->config->_tcbPoints);
diff --git a/src/corelib/tools/qmargins.h b/src/corelib/tools/qmargins.h
index f833a338b16..cbdb093adc8 100644
--- a/src/corelib/tools/qmargins.h
+++ b/src/corelib/tools/qmargins.h
@@ -333,20 +333,13 @@ private:
qreal m_right;
qreal m_bottom;
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_FLOAT_COMPARE
friend constexpr bool qFuzzyCompare(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
- return ((!lhs.m_left || !rhs.m_left) ? qFuzzyIsNull(lhs.m_left - rhs.m_left)
- : qFuzzyCompare(lhs.m_left, rhs.m_left))
- && ((!lhs.m_top || !rhs.m_top) ? qFuzzyIsNull(lhs.m_top - rhs.m_top)
- : qFuzzyCompare(lhs.m_top, rhs.m_top))
- && ((!lhs.m_right || !rhs.m_right) ? qFuzzyIsNull(lhs.m_right - rhs.m_right)
- : qFuzzyCompare(lhs.m_right, rhs.m_right))
- && ((!lhs.m_bottom || !rhs.m_bottom) ? qFuzzyIsNull(lhs.m_bottom - rhs.m_bottom)
- : qFuzzyCompare(lhs.m_bottom, rhs.m_bottom));
+ return QtPrivate::fuzzyCompare(lhs.m_left, rhs.m_left)
+ && QtPrivate::fuzzyCompare(lhs.m_top, rhs.m_top)
+ && QtPrivate::fuzzyCompare(lhs.m_right, rhs.m_right)
+ && QtPrivate::fuzzyCompare(lhs.m_bottom, rhs.m_bottom);
}
- QT_WARNING_POP
friend constexpr bool qFuzzyIsNull(const QMarginsF &m) noexcept
{
return qFuzzyIsNull(m.m_left) && qFuzzyIsNull(m.m_top)
diff --git a/src/corelib/tools/qpoint.h b/src/corelib/tools/qpoint.h
index ae896ba7079..1b767324058 100644
--- a/src/corelib/tools/qpoint.h
+++ b/src/corelib/tools/qpoint.h
@@ -259,14 +259,11 @@ public:
}
private:
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_FLOAT_COMPARE
friend constexpr bool qFuzzyCompare(const QPointF &p1, const QPointF &p2) noexcept
{
- return ((!p1.xp || !p2.xp) ? qFuzzyIsNull(p1.xp - p2.xp) : qFuzzyCompare(p1.xp, p2.xp))
- && ((!p1.yp || !p2.yp) ? qFuzzyIsNull(p1.yp - p2.yp) : qFuzzyCompare(p1.yp, p2.yp));
+ return QtPrivate::fuzzyCompare(p1.xp, p2.xp)
+ && QtPrivate::fuzzyCompare(p1.yp, p2.yp);
}
- QT_WARNING_POP
friend constexpr bool qFuzzyIsNull(const QPointF &point) noexcept
{
return qFuzzyIsNull(point.xp) && qFuzzyIsNull(point.yp);
diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h
index 86509cb6483..680bf2812d3 100644
--- a/src/corelib/tools/qsize.h
+++ b/src/corelib/tools/qsize.h
@@ -254,16 +254,11 @@ public:
inline QSizeF &operator/=(qreal c);
private:
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_FLOAT_COMPARE
friend constexpr bool qFuzzyCompare(const QSizeF &s1, const QSizeF &s2) noexcept
{
- // Cannot use qFuzzyCompare(), because it will give incorrect results
- // if one of the arguments is 0.0.
- return ((!s1.wd || !s2.wd) ? qFuzzyIsNull(s1.wd - s2.wd) : qFuzzyCompare(s1.wd, s2.wd))
- && ((!s1.ht || !s2.ht) ? qFuzzyIsNull(s1.ht - s2.ht) : qFuzzyCompare(s1.ht, s2.ht));
+ return QtPrivate::fuzzyCompare(s1.wd, s2.wd)
+ && QtPrivate::fuzzyCompare(s1.ht, s2.ht);
}
- QT_WARNING_POP
friend constexpr bool qFuzzyIsNull(const QSizeF &size) noexcept
{ return qFuzzyIsNull(size.wd) && qFuzzyIsNull(size.ht); }
friend constexpr bool comparesEqual(const QSizeF &lhs, const QSizeF &rhs) noexcept