summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/CMakeLists.txt7
-rw-r--r--src/corelib/configure.cmake29
-rw-r--r--src/corelib/doc/snippets/code/doc_src_properties.cpp2
-rw-r--r--src/corelib/doc/src/cmake/cmake-configure-variables.qdoc1
-rw-r--r--src/corelib/doc/src/objectmodel/properties.qdoc16
-rw-r--r--src/corelib/global/patches/tlexpected/0006-Namespace-TL_-macros-with-Q23_.patch914
-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/qioring.cpp30
-rw-r--r--src/corelib/io/qioring_linux.cpp13
-rw-r--r--src/corelib/io/qioring_p.h39
-rw-r--r--src/corelib/io/qioring_win.cpp754
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_darwin.mm24
-rw-r--r--src/corelib/itemmodels/qrangemodel.cpp1
-rw-r--r--src/corelib/itemmodels/qrangemodel_impl.h209
-rw-r--r--src/corelib/itemmodels/qrangemodeladapter.h204
-rw-r--r--src/corelib/itemmodels/qrangemodeladapter.qdoc39
-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/qiterable.h6
-rw-r--r--src/corelib/kernel/qjniobject.cpp76
-rw-r--r--src/corelib/kernel/qmetaassociation.h6
-rw-r--r--src/corelib/kernel/qmetaobject.cpp55
-rw-r--r--src/corelib/kernel/qmetaobject.h2
-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.h61
-rw-r--r--src/corelib/kernel/qobjectdefs.h2
-rw-r--r--src/corelib/kernel/qsequentialiterable.h3
-rw-r--r--src/corelib/kernel/qtmocconstants.h6
-rw-r--r--src/corelib/kernel/qtmochelpers.h7
-rw-r--r--src/corelib/kernel/qvariant.h10
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp21
-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/tools/qarraydata.cpp2
-rw-r--r--src/corelib/tools/qmargins.h15
-rw-r--r--src/corelib/tools/qpoint.h7
-rw-r--r--src/corelib/tools/qsize.h9
49 files changed, 2545 insertions, 487 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index dec68c5f9f4..ea8cf7b9c8e 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -583,7 +583,7 @@ 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
@@ -763,6 +763,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/configure.cmake b/src/corelib/configure.cmake
index c1d15c75054..4386b907c13 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -605,6 +605,27 @@ 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;
+ /* END TEST: */
+ return 0;
+}
+"
+)
+
# cpp_winrt
qt_config_compile_test(cpp_winrt
LABEL "cpp/winrt"
@@ -785,6 +806,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
@@ -1259,7 +1285,7 @@ qt_feature("openssl-hash" PRIVATE
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) OR APPLE OR (LINUX AND QT_FEATURE_liburing) OR (WIN32 AND QT_FEATURE_windows_ioring)
)
qt_configure_add_summary_section(NAME "Qt Core")
@@ -1272,6 +1298,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/snippets/code/doc_src_properties.cpp b/src/corelib/doc/snippets/code/doc_src_properties.cpp
index eafa7acda3b..07f574c2de2 100644
--- a/src/corelib/doc/snippets/code/doc_src_properties.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_properties.cpp
@@ -16,6 +16,8 @@ Q_PROPERTY(type name
[BINDABLE bindableProperty]
[CONSTANT]
[FINAL]
+ [VIRTUAL]
+ [OVERRIDE]
[REQUIRED])
//! [0]
diff --git a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
index 0a0dc0b3c50..42cb3ecb42b 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
diff --git a/src/corelib/doc/src/objectmodel/properties.qdoc b/src/corelib/doc/src/objectmodel/properties.qdoc
index 0e66c8445c2..71e14222763 100644
--- a/src/corelib/doc/src/objectmodel/properties.qdoc
+++ b/src/corelib/doc/src/objectmodel/properties.qdoc
@@ -128,10 +128,18 @@
constant value may be different for different instances of the object. A
constant property cannot have a WRITE method or a NOTIFY signal.
- \li The presence of the \c FINAL attribute indicates that the property
- will not be overridden by a derived class. This can be used for performance
- optimizations in some cases, but is not enforced by moc. Care must be taken
- never to override a \c FINAL property.
+ \li \c FINAL, \c VIRTUAL, \c OVERRIDE modifiers mirror the semantics of their C++ and
+ \l {Override Semantics}{QML counterparts}, allowing to make property overriding explicit at the
+ meta-object level.
+
+ \note At present, these modifiers are not enforced by moc.
+ They are recognized syntactically and are primarily used for QML runtime enforcement and tooling
+ diagnostics. Future versions may introduce stricter compile-time validation and warnings for
+ invalid overrides across modules.
+
+ \note If you want to change accessing behaviour for a property, use the
+ polymorphism provided by C++.
+
\li The presence of the \c REQUIRED attribute indicates that the property
should be set by a user of the class. This is not enforced by moc, and is
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/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/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..0db832bc6bf 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>
@@ -162,6 +166,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 +215,28 @@ 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;
+
+ 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 +275,7 @@ struct QIORingRequestBase : Base
template <>
struct QIORingResult<QtPrivate::Operation::Open>
{
+ // On Windows this is a HANDLE
qintptr fd;
};
template <>
@@ -260,6 +293,7 @@ template <>
struct QIORingRequest<QtPrivate::Operation::Close> final
: QIORingRequestBase<QtPrivate::Operation::Close, QIORingRequestEmptyBase>
{
+ // On Windows this is a HANDLE
qintptr fd;
};
@@ -318,6 +352,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 +365,7 @@ template <>
struct QIORingRequest<QtPrivate::Operation::Stat> final
: QIORingRequestBase<QtPrivate::Operation::Stat, QIORingRequestEmptyBase>
{
+ // On Windows this is a HANDLE
qintptr fd;
};
@@ -473,6 +509,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..42c51f428d6
--- /dev/null
+++ b/src/corelib/io/qioring_win.cpp
@@ -0,0 +1,754 @@
+// 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;
+
+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());
+ return 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());
+ // @todo: FILE_WRITE_FLAGS can be set to write-through, could be used for Unbuffered mode.
+ return BuildIoRingWriteFile(ioRingHandle, fileRef, bufferRef, maxSize, offset,
+ FILE_WRITE_FLAGS_NONE, userData, IOSQE_FLAGS_NONE);
+}
+
+QIORing::~QIORing()
+{
+ if (initialized) {
+ CloseHandle(eventHandle);
+ CloseIoRing(ioRingHandle);
+ }
+}
+
+bool QIORing::initializeIORing()
+{
+ if (initialized)
+ return true;
+
+ IORING_CAPABILITIES capabilities;
+ 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 = 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);
+ 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 = SetIoRingCompletionEvent(ioRingHandle, eventHandle);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Failed to assign the event handle to QIORing");
+ return false;
+ }
+ IORING_INFO info;
+ if (SUCCEEDED(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 (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 = 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 = 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 = 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 = 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_darwin.mm b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
index 7231d12fe7d..fca225263ba 100644
--- a/src/corelib/io/qrandomaccessasyncfile_darwin.mm
+++ b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
@@ -95,10 +95,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);
}
}
@@ -212,8 +210,8 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const
void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted()
{
QMutexLocker locker(&m_mutex);
+ --m_numChannelsToClose;
if (m_opToCancel == kAllOperationIds) {
- --m_numChannelsToClose;
if (m_numChannelsToClose == 0 && m_runningOps.isEmpty())
m_cancellationCondition.wakeOne();
}
@@ -222,11 +220,19 @@ void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted()
dispatch_io_t QRandomAccessAsyncFilePrivate::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)
@@ -247,6 +253,7 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId
if (channel) {
QMutexLocker locker(&m_mutex);
m_runningOps.insert(opId);
+ ++m_numChannelsToClose;
}
return channel;
}
@@ -593,6 +600,7 @@ 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;
diff --git a/src/corelib/itemmodels/qrangemodel.cpp b/src/corelib/itemmodels/qrangemodel.cpp
index d72722f063d..f37812876ea 100644
--- a/src/corelib/itemmodels/qrangemodel.cpp
+++ b/src/corelib/itemmodels/qrangemodel.cpp
@@ -1385,6 +1385,7 @@ void QRangeModel::resetRoleNames()
/*!
\property QRangeModel::autoConnectPolicy
+ \since 6.11
\brief if and when the model auto-connects to property changed notifications.
If QRangeModel operates on a data structure that holds the same type of
diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h
index 3e35ad3981c..f6b08099fe7 100644
--- a/src/corelib/itemmodels/qrangemodel_impl.h
+++ b/src/corelib/itemmodels/qrangemodel_impl.h
@@ -23,6 +23,7 @@
#include <QtCore/qmap.h>
#include <QtCore/qscopedvaluerollback.h>
#include <QtCore/qset.h>
+#include <QtCore/qvarlengtharray.h>
#include <algorithm>
#include <functional>
@@ -1203,76 +1204,48 @@ public:
return std::move(result.data());
}
+ static constexpr bool isRangeModelRole(int role)
+ {
+ return role == Qt::RangeModelDataRole
+ || role == Qt::RangeModelAdapterRole;
+ }
+
+ static constexpr bool isPrimaryRole(int role)
+ {
+ return role == Qt::DisplayRole || role == Qt::EditRole;
+ }
+
QMap<int, QVariant> itemData(const QModelIndex &index) const
{
QMap<int, QVariant> result;
- bool tried = false;
- const auto readItemData = [this, &index, &result, &tried](const auto &value){
- Q_UNUSED(this);
- Q_UNUSED(index);
- using value_type = q20::remove_cvref_t<decltype(value)>;
- using multi_role = QRangeModelDetails::is_multi_role<value_type>;
- using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
- if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
- using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
- tried = true;
- const auto roles = this->itemModel().roleNames().keys();
- for (auto &role : roles) {
- if (role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole)
- continue;
- QVariant data = ItemAccess::readRole(value, role);
- if (data.isValid())
- result[role] = std::move(data);
- }
- } else if constexpr (multi_role()) {
- tried = true;
- if constexpr (std::is_convertible_v<value_type, decltype(result)>) {
+ if (index.isValid()) {
+ bool tried = false;
+
+ // optimisation for items backed by a QMap<int, QVariant> or equivalent
+ readAt(index, [&result, &tried](const auto &value) {
+ if constexpr (std::is_convertible_v<decltype(value), decltype(result)>) {
+ tried = true;
result = value;
- } else {
- const auto roleNames = [this]() -> QHash<int, QByteArray> {
- Q_UNUSED(this);
- if constexpr (!multi_role::int_key)
- return this->itemModel().roleNames();
- else
- return {};
- }();
- for (auto it = std::begin(value); it != std::end(value); ++it) {
- const int role = [&roleNames, key = QRangeModelDetails::key(it)]() {
- Q_UNUSED(roleNames);
- if constexpr (multi_role::int_key)
- return int(key);
- else
- return roleNames.key(key.toUtf8(), -1);
- }();
-
- if (role != -1 && role != Qt::RangeModelDataRole && role != Qt::RangeModelAdapterRole)
- result.insert(role, QRangeModelDetails::value(it));
- }
}
- } else if constexpr (has_metaobject<value_type>) {
- if (row_traits::fixed_size() <= 1) {
- tried = true;
- const auto roleNames = this->itemModel().roleNames();
- const auto end = roleNames.keyEnd();
- for (auto it = roleNames.keyBegin(); it != end; ++it) {
- const int role = *it;
- if (role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole)
- continue;
- QVariant data = readRole(index, role, QRangeModelDetails::pointerTo(value));
- if (data.isValid())
- result[role] = std::move(data);
- }
+ });
+ if (!tried) {
+ const auto roles = this->itemModel().roleNames().keys();
+ QVarLengthArray<QModelRoleData, 16> roleDataArray;
+ roleDataArray.reserve(roles.size());
+ for (auto role : roles) {
+ if (isRangeModelRole(role))
+ continue;
+ roleDataArray.emplace_back(role);
}
- }
- };
-
- if (index.isValid()) {
- readAt(index, readItemData);
+ QModelRoleDataSpan roleDataSpan(roleDataArray);
+ multiData(index, roleDataSpan);
- if (!tried) { // no multi-role item found
- result = this->itemModel().QAbstractItemModel::itemData(index);
- result.remove(Qt::RangeModelAdapterRole);
+ for (auto &&roleData : std::move(roleDataSpan)) {
+ QVariant data = roleData.data();
+ if (data.isValid())
+ result[roleData.role()] = std::move(data);
+ }
}
}
return result;
@@ -1288,27 +1261,34 @@ public:
using multi_role = QRangeModelDetails::is_multi_role<value_type>;
using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
+ const auto readModelData = [&value](QModelRoleData &roleData){
+ const int role = roleData.role();
+ if (role == Qt::RangeModelDataRole) {
+ // Qt QML support: "modelData" role returns the entire multi-role item.
+ // QML can only use raw pointers to QObject (so we unwrap), and gadgets
+ // only by value (so we take the reference).
+ if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
+ roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
+ else
+ roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
+ } else if (role == Qt::RangeModelAdapterRole) {
+ // for QRangeModelAdapter however, we want to respect smart pointer wrappers
+ if constexpr (std::is_copy_assignable_v<value_type>)
+ roleData.setData(QVariant::fromValue(value));
+ else
+ roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
+ } else {
+ return false;
+ }
+ return true;
+ };
+
if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
tried = true;
for (auto &roleData : roleDataSpan) {
- if (roleData.role() == Qt::RangeModelDataRole) {
- // Qt QML support: "modelData" role returns the entire multi-role item.
- // QML can only use raw pointers to QObject (so we unwrap), and gadgets
- // only by value (so we take the reference).
- if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
- roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
- else
- roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
- } else if (roleData.role() == Qt::RangeModelAdapterRole) {
- // for QRangeModelAdapter however, we want to respect smart pointer wrappers
- if constexpr (std::is_copy_assignable_v<value_type>)
- roleData.setData(QVariant::fromValue(value));
- else
- roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
- } else {
+ if (!readModelData(roleData))
roleData.setData(ItemAccess::readRole(value, roleData.role()));
- }
}
} else if constexpr (multi_role()) {
tried = true;
@@ -1337,21 +1317,7 @@ public:
if (row_traits::fixed_size() <= 1) {
tried = true;
for (auto &roleData : roleDataSpan) {
- if (roleData.role() == Qt::RangeModelDataRole) {
- // Qt QML support: "modelData" role returns the entire multi-role item.
- // QML can only use raw pointers to QObject (so we unwrap), and gadgets
- // only by value (so we take the reference).
- if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
- roleData.setData(QVariant::fromValue(QRangeModelDetails::refTo(value)));
- else
- roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
- } else if (roleData.role() == Qt::RangeModelAdapterRole) {
- // for QRangeModelAdapter however, we want to respect smart pointer wrappers
- if constexpr (std::is_copy_assignable_v<value_type>)
- roleData.setData(QVariant::fromValue(value));
- else
- roleData.setData(QVariant::fromValue(QRangeModelDetails::pointerTo(value)));
- } else {
+ if (!readModelData(roleData)) {
roleData.setData(readRole(index, roleData.role(),
QRangeModelDetails::pointerTo(value)));
}
@@ -1360,7 +1326,7 @@ public:
tried = true;
for (auto &roleData : roleDataSpan) {
const int role = roleData.role();
- if (role == Qt::DisplayRole || role == Qt::EditRole) {
+ if (isPrimaryRole(role)) {
roleData.setData(readProperty(index.column(),
QRangeModelDetails::pointerTo(value)));
} else {
@@ -1372,12 +1338,10 @@ public:
tried = true;
for (auto &roleData : roleDataSpan) {
const int role = roleData.role();
- if (role == Qt::DisplayRole || role == Qt::EditRole
- || role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole) {
+ if (isPrimaryRole(role) || isRangeModelRole(role))
roleData.setData(read(value));
- } else {
+ else
roleData.clearData();
- }
}
}
});
@@ -1395,7 +1359,8 @@ public:
auto emitDataChanged = qScopeGuard([&success, this, &index, role]{
if (success) {
Q_EMIT this->dataChanged(index, index,
- role == Qt::EditRole || role == Qt::RangeModelDataRole || role == Qt::RangeModelDataRole
+ role == Qt::EditRole || role == Qt::RangeModelDataRole
+ || role == Qt::RangeModelAdapterRole
? QList<int>{} : QList<int>{role});
}
});
@@ -1408,25 +1373,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>();
@@ -1440,10 +1414,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
@@ -1455,17 +1429,16 @@ public:
if constexpr (QRangeModelDetails::item_access<wrapped_value_type>()) {
using ItemAccess = QRangeModelDetails::QRangeModelItemAccess<wrapped_value_type>;
- if (role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole)
+ if (isRangeModelRole(role))
return setRangeModelDataRole();
return ItemAccess::writeRole(target, data, role);
} if constexpr (has_metaobject<value_type>) {
if (row_traits::fixed_size() <= 1) { // multi-role value
- if (role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole)
+ if (isRangeModelRole(role))
return setRangeModelDataRole();
return writeRole(role, QRangeModelDetails::pointerTo(target), data);
} else if (column <= row_traits::fixed_size() // multi-column
- && (role == Qt::DisplayRole || role == Qt::EditRole
- || role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole)) {
+ && (isPrimaryRole(role) || isRangeModelRole(role))) {
return writeProperty(column, QRangeModelDetails::pointerTo(target), data);
}
} else if constexpr (multi_role::value) {
@@ -1492,14 +1465,20 @@ public:
return write(target[roleToSet], data);
else
return write(target[roleNames.value(roleToSet)], data);
- } else if (role == Qt::DisplayRole || role == Qt::EditRole
- || role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole) {
+ } else if (isPrimaryRole(role) || isRangeModelRole(role)) {
return write(target, data);
}
return false;
};
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;
}
@@ -1607,7 +1586,7 @@ public:
tried = true;
auto targetCopy = makeCopy(target);
for (auto &&[role, value] : data.asKeyValueRange()) {
- if (role == Qt::RangeModelDataRole || role == Qt::RangeModelAdapterRole)
+ if (isRangeModelRole(role))
continue;
if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
const QByteArray roleName = roleNames.value(role);
diff --git a/src/corelib/itemmodels/qrangemodeladapter.h b/src/corelib/itemmodels/qrangemodeladapter.h
index bd3342e6185..2a23e01eba2 100644
--- a/src/corelib/itemmodels/qrangemodeladapter.h
+++ b/src/corelib/itemmodels/qrangemodeladapter.h
@@ -141,6 +141,7 @@ public:
}
DataReference(const DataReference &other) = default;
+ DataReference(DataReference &&other) = default;
// reference (not std::reference_wrapper) semantics
DataReference &operator=(const DataReference &other)
@@ -149,29 +150,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 +191,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 +1042,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
{
@@ -1503,6 +1520,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 5ab128a8c5f..ff595529d34 100644
--- a/src/corelib/itemmodels/qrangemodeladapter.qdoc
+++ b/src/corelib/itemmodels/qrangemodeladapter.qdoc
@@ -118,11 +118,9 @@
would bypass the QAbstractItemModel notification protocol, those reference
objects prevent direct modifications of the items.
- \note Calling mutable overloads generates some overhead. Make a const copy
- of the adapter (which will not copy the data), or use \c{std::as_const} to
- make sure that only the const overloads are used in performance critical,
- read-heavy code. This is the same technique as when accessing elements in
- an implicitly shared Qt container.
+ \note Accessing the reference object always makes a call to the model to get
+ a copy of the value. This can be expensive; for performance critical access
+ to data, store a copy.
\section3 Item access
@@ -331,16 +329,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.
+
+ \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()
+ \sa range(), at, model()
*/
/*!
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/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/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index a5d34eac707..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.
@@ -4405,6 +4432,34 @@ bool QMetaProperty::isFinal() const
}
/*!
+ \since 6.11
+ Returns \c true if the property is virtual; otherwise returns \c false.
+
+ A property is virtual if the \c{Q_PROPERTY()}'s \c VIRTUAL attribute
+ is set.
+*/
+bool QMetaProperty::isVirtual() const
+{
+ if (!mobj)
+ return false;
+ return data.flags() & Virtual;
+}
+
+/*!
+ \since 6.11
+ Returns \c true if the property does override; otherwise returns \c false.
+
+ A property does override if the \c{Q_PROPERTY()}'s \c OVERRIDE attribute
+ is set.
+*/
+bool QMetaProperty::isOverride() const
+{
+ if (!mobj)
+ return false;
+ return data.flags() & Override;
+}
+
+/*!
\since 5.15
Returns \c true if the property is required; otherwise returns \c false.
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 0f793ca753b..ff3cc751c3a 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -365,6 +365,8 @@ public:
bool isUser() const;
bool isConstant() const;
bool isFinal() const;
+ bool isVirtual() const;
+ bool isOverride() const;
bool isRequired() const;
bool isBindable() const;
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.h b/src/corelib/kernel/qmetasequence.h
index e9505054159..26156e7924f 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,13 +184,15 @@ 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
});
}
@@ -204,13 +206,15 @@ 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(
"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);
+#endif
}
void append(const QVariant &value)
@@ -248,55 +252,14 @@ 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();
+ Q_DECL_EQ_DELETE_X("Use removeLast() or removeFirst() instead.");
- 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;
- }
- }
-
- 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.");
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/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 79c0138bb28..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,
@@ -39,7 +40,8 @@ enum PropertyFlags : uint {
Resettable = 0x00000004,
EnumOrFlag = 0x00000008,
Alias = 0x00000010,
- // Reserved for future usage = 0x00000020,
+ Virtual = 0x00000020,
+ Override = 0x00000040,
StdCppSet = 0x00000100,
Constant = 0x00000400,
Final = 0x00000800,
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/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 de7043e8c1d..ecd1ac77779 100644
--- a/src/corelib/mimetypes/qmimeprovider.cpp
+++ b/src/corelib/mimetypes/qmimeprovider.cpp
@@ -512,20 +512,21 @@ QMimeBinaryProvider::MimeTypeExtraMap::const_iterator
QMimeBinaryProvider::loadMimeTypeExtra(const QString &mimeName)
{
#if QT_CONFIG(xmlstreamreader)
- auto it = m_mimetypeExtra.find(mimeName);
- if (it == m_mimetypeExtra.cend()) {
+ auto [it, insertionOccurred] = m_mimetypeExtra.try_emplace(mimeName);
+ if (insertionOccurred) {
// 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 m_mimetypeExtra.cend();
+ 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;
+ }
- it = m_mimetypeExtra.try_emplace(mimeName).first;
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/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/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