Add q23::expected as a private type
This patch adds a std::expected-like type in Qt for use in the Qt implementation. It is using Sy Brand's tl::expected which is similar to std::expected, and works with C++17. Although it closely resembles std::expected, it is not identical and is therefor added as a private header. The new type is intended to be accessible to all Qt modules and is therefore made available through Qt Core. It is, however, not intended for use in public APIs. [ChangeLog][Third-Party Code] Added Sy Brand's tl::expected as a third party dependency for use internally in Qt implementation. Change-Id: I09930f31bf97498643d62814c688f288d5c33265 Reviewed-by: Tim Blechmann <tim.blechmann@qt.io>
This commit is contained in:
parent
60f36b8d02
commit
6f319847d0
@ -68,6 +68,12 @@ precedence = "closest"
|
||||
SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd."
|
||||
SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"
|
||||
|
||||
[[annotations]]
|
||||
path = ["src/corelib/global/patches/tlexpected/**", "src/corelib/global/qexpected_p.h"]
|
||||
precedence = "closest"
|
||||
SPDX-FileCopyrightText = "To the extent possible under law, Sy Brand has waived all copyright and related or neighboring rights to the expected library. This work is published from: United Kingdom."
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ["src/gui/doc/snippets/textdocument-images/images.qrc"]
|
||||
precedence = "closest"
|
||||
|
@ -556,10 +556,20 @@
|
||||
"file type": "build system",
|
||||
"spdx": ["BSD-3-Clause"]
|
||||
},
|
||||
"src/corelib/Qt6CoreConfigureFileTemplate.in": {
|
||||
"src/corelib/global/qexpected_p.h": {
|
||||
"comment": "See REUSE.toml file",
|
||||
"file type": "build system",
|
||||
"spdx": ["BSD-3-Clause"]
|
||||
"file type": "3rd party",
|
||||
"spdx": ["CC0-1.0"]
|
||||
},
|
||||
"src/corelib/global/patches/tlexpected/": {
|
||||
"comment": "See REUSE.toml file",
|
||||
"file type": "3rd party",
|
||||
"spdx": ["CC0-1.0"]
|
||||
},
|
||||
"src/corelib/Qt6CoreConfigureFileTemplate.in" : {
|
||||
"comment" : "See REUSE.toml file",
|
||||
"file type" : "build system",
|
||||
"spdx" : ["BSD-3-Clause"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ qt_internal_add_module(Core
|
||||
global/qdarwinhelpers.h
|
||||
global/qendian.cpp global/qendian.h global/qendian_p.h
|
||||
global/qexceptionhandling.h
|
||||
global/qexpected_p.h
|
||||
global/qflags.h
|
||||
global/qfloat16.cpp global/qfloat16.h
|
||||
global/qforeach.h
|
||||
|
@ -0,0 +1,280 @@
|
||||
From 14c70a678a76457562a1be33d1809463dd3bf6e8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?J=C3=B8ger=20Hanseg=C3=A5rd?= <joger.hansegard@qt.io>
|
||||
Date: Wed, 19 Feb 2025 12:12:29 +0100
|
||||
Subject: [PATCH 1/3] Rename tl::unexpected::value() to tl::unexpected::error()
|
||||
|
||||
Fixes #149
|
||||
---
|
||||
include/tl/expected.hpp | 52 ++++++++++++++++++++---------------------
|
||||
tests/constructors.cpp | 20 ++++++++++++++++
|
||||
tests/issues.cpp | 2 +-
|
||||
tests/observers.cpp | 12 ++++++++++
|
||||
tests/relops.cpp | 25 ++++++++++++++++++++
|
||||
5 files changed, 84 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/include/tl/expected.hpp b/include/tl/expected.hpp
|
||||
index 3c22c5c..9d3a5e1 100644
|
||||
--- a/include/tl/expected.hpp
|
||||
+++ b/include/tl/expected.hpp
|
||||
@@ -165,10 +165,10 @@ public:
|
||||
constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
|
||||
: m_val(l, std::forward<Args>(args)...) {}
|
||||
|
||||
- constexpr const E &value() const & { return m_val; }
|
||||
- TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
|
||||
- TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
|
||||
- constexpr const E &&value() const && { return std::move(m_val); }
|
||||
+ 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); }
|
||||
+ constexpr const E &&error() const && { return std::move(m_val); }
|
||||
|
||||
private:
|
||||
E m_val;
|
||||
@@ -180,27 +180,27 @@ template <class E> unexpected(E) -> unexpected<E>;
|
||||
|
||||
template <class E>
|
||||
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||
- return lhs.value() == rhs.value();
|
||||
+ return lhs.error() == rhs.error();
|
||||
}
|
||||
template <class E>
|
||||
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||
- return lhs.value() != rhs.value();
|
||||
+ return lhs.error() != rhs.error();
|
||||
}
|
||||
template <class E>
|
||||
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||
- return lhs.value() < rhs.value();
|
||||
+ return lhs.error() < rhs.error();
|
||||
}
|
||||
template <class E>
|
||||
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||
- return lhs.value() <= rhs.value();
|
||||
+ return lhs.error() <= rhs.error();
|
||||
}
|
||||
template <class E>
|
||||
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||
- return lhs.value() > rhs.value();
|
||||
+ return lhs.error() > rhs.error();
|
||||
}
|
||||
template <class E>
|
||||
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||
- return lhs.value() >= rhs.value();
|
||||
+ return lhs.error() >= rhs.error();
|
||||
}
|
||||
|
||||
template <class E>
|
||||
@@ -1582,7 +1582,7 @@ public:
|
||||
detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
|
||||
nullptr>
|
||||
explicit constexpr expected(const unexpected<G> &e)
|
||||
- : impl_base(unexpect, e.value()),
|
||||
+ : impl_base(unexpect, e.error()),
|
||||
ctor_base(detail::default_constructor_tag{}) {}
|
||||
|
||||
template <
|
||||
@@ -1591,7 +1591,7 @@ public:
|
||||
nullptr,
|
||||
detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
|
||||
constexpr expected(unexpected<G> const &e)
|
||||
- : impl_base(unexpect, e.value()),
|
||||
+ : impl_base(unexpect, e.error()),
|
||||
ctor_base(detail::default_constructor_tag{}) {}
|
||||
|
||||
template <
|
||||
@@ -1600,7 +1600,7 @@ public:
|
||||
detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
|
||||
explicit constexpr expected(unexpected<G> &&e) noexcept(
|
||||
std::is_nothrow_constructible<E, G &&>::value)
|
||||
- : impl_base(unexpect, std::move(e.value())),
|
||||
+ : impl_base(unexpect, std::move(e.error())),
|
||||
ctor_base(detail::default_constructor_tag{}) {}
|
||||
|
||||
template <
|
||||
@@ -1609,7 +1609,7 @@ public:
|
||||
detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
|
||||
constexpr expected(unexpected<G> &&e) noexcept(
|
||||
std::is_nothrow_constructible<E, G &&>::value)
|
||||
- : impl_base(unexpect, std::move(e.value())),
|
||||
+ : impl_base(unexpect, std::move(e.error())),
|
||||
ctor_base(detail::default_constructor_tag{}) {}
|
||||
|
||||
template <class... Args,
|
||||
@@ -2017,46 +2017,46 @@ public:
|
||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||
TL_EXPECTED_11_CONSTEXPR const U &value() const & {
|
||||
if (!has_value())
|
||||
- detail::throw_exception(bad_expected_access<E>(err().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() & {
|
||||
if (!has_value())
|
||||
- detail::throw_exception(bad_expected_access<E>(err().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 && {
|
||||
if (!has_value())
|
||||
- detail::throw_exception(bad_expected_access<E>(std::move(err()).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() && {
|
||||
if (!has_value())
|
||||
- detail::throw_exception(bad_expected_access<E>(std::move(err()).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());
|
||||
- return err().value();
|
||||
+ return err().error();
|
||||
}
|
||||
TL_EXPECTED_11_CONSTEXPR E &error() & {
|
||||
TL_ASSERT(!has_value());
|
||||
- return err().value();
|
||||
+ return err().error();
|
||||
}
|
||||
constexpr const E &&error() const && {
|
||||
TL_ASSERT(!has_value());
|
||||
- return std::move(err().value());
|
||||
+ return std::move(err().error());
|
||||
}
|
||||
TL_EXPECTED_11_CONSTEXPR E &&error() && {
|
||||
TL_ASSERT(!has_value());
|
||||
- return std::move(err().value());
|
||||
+ return std::move(err().error());
|
||||
}
|
||||
|
||||
template <class U> constexpr T value_or(U &&v) const & {
|
||||
@@ -2446,19 +2446,19 @@ constexpr bool operator!=(const U &v, const expected<T, E> &x) {
|
||||
|
||||
template <class T, class E>
|
||||
constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
|
||||
- return x.has_value() ? false : x.error() == e.value();
|
||||
+ return x.has_value() ? false : x.error() == e.error();
|
||||
}
|
||||
template <class T, class E>
|
||||
constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
|
||||
- return x.has_value() ? false : x.error() == e.value();
|
||||
+ return x.has_value() ? false : x.error() == e.error();
|
||||
}
|
||||
template <class T, class E>
|
||||
constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
|
||||
- return x.has_value() ? true : x.error() != e.value();
|
||||
+ return x.has_value() ? true : x.error() != e.error();
|
||||
}
|
||||
template <class T, class E>
|
||||
constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
|
||||
- return x.has_value() ? true : x.error() != e.value();
|
||||
+ return x.has_value() ? true : x.error() != e.error();
|
||||
}
|
||||
|
||||
template <class T, class E,
|
||||
diff --git a/tests/constructors.cpp b/tests/constructors.cpp
|
||||
index df168ba..10b96de 100644
|
||||
--- a/tests/constructors.cpp
|
||||
+++ b/tests/constructors.cpp
|
||||
@@ -131,4 +131,24 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(!e);
|
||||
REQUIRE(e.error() == 42);
|
||||
}
|
||||
+
|
||||
+ {
|
||||
+ constexpr tl::unexpected<char> u('s');
|
||||
+ tl::expected<int, int> e(u);
|
||||
+ REQUIRE(e.error() == 's');
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ struct value {
|
||||
+ constexpr explicit value(char v) : val(v) {}
|
||||
+ char val;
|
||||
+ };
|
||||
+
|
||||
+ constexpr tl::unexpected<char> u('s');
|
||||
+ tl::expected<int, value> e1(u);
|
||||
+ REQUIRE(e1.error().val == 's');
|
||||
+
|
||||
+ tl::expected<int, value> e2(tl::unexpected<char>('s'));
|
||||
+ REQUIRE(e2.error().val == 's');
|
||||
+ }
|
||||
}
|
||||
diff --git a/tests/issues.cpp b/tests/issues.cpp
|
||||
index f929099..9efe14b 100644
|
||||
--- a/tests/issues.cpp
|
||||
+++ b/tests/issues.cpp
|
||||
@@ -166,7 +166,7 @@ TEST_CASE("Issue 122", "[issues.122]") {
|
||||
#ifdef __cpp_deduction_guides
|
||||
TEST_CASE("Issue 89", "[issues.89]") {
|
||||
auto s = tl::unexpected("Some string");
|
||||
- REQUIRE(s.value() == std::string("Some string"));
|
||||
+ REQUIRE(s.error() == std::string("Some string"));
|
||||
}
|
||||
#endif
|
||||
|
||||
diff --git a/tests/observers.cpp b/tests/observers.cpp
|
||||
index 5d8473c..cff3e9f 100644
|
||||
--- a/tests/observers.cpp
|
||||
+++ b/tests/observers.cpp
|
||||
@@ -34,3 +34,15 @@ TEST_CASE("Observers", "[observers]") {
|
||||
REQUIRE(o4->been_moved);
|
||||
REQUIRE(!o5.been_moved);
|
||||
}
|
||||
+
|
||||
+#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
+TEST_CASE("Observers invalid access", "[observers]") {
|
||||
+ tl::expected<int, char> err(tl::make_unexpected('!'));
|
||||
+
|
||||
+ REQUIRE_THROWS_AS(err.value(), tl::bad_expected_access<char>);
|
||||
+ REQUIRE_THROWS_AS(std::as_const(err).value(), tl::bad_expected_access<char>);
|
||||
+ REQUIRE_THROWS_AS(std::move(std::as_const(err)).value(),
|
||||
+ tl::bad_expected_access<char>);
|
||||
+ REQUIRE_THROWS_AS(std::move(err).value(), tl::bad_expected_access<char>);
|
||||
+}
|
||||
+#endif
|
||||
diff --git a/tests/relops.cpp b/tests/relops.cpp
|
||||
index 99dee5f..b873b6a 100644
|
||||
--- a/tests/relops.cpp
|
||||
+++ b/tests/relops.cpp
|
||||
@@ -15,3 +15,28 @@ TEST_CASE("Relational operators", "[relops]") {
|
||||
|
||||
REQUIRE(o6 == o6);
|
||||
}
|
||||
+
|
||||
+TEST_CASE("Relational operators unexpected", "[relops]") {
|
||||
+ tl::unexpected<int> zero(0);
|
||||
+ tl::unexpected<int> one(1);
|
||||
+
|
||||
+ REQUIRE(one == one);
|
||||
+ REQUIRE(one != zero);
|
||||
+ REQUIRE(zero < one);
|
||||
+ REQUIRE(zero <= one);
|
||||
+ REQUIRE(one <= one);
|
||||
+ REQUIRE(one > zero);
|
||||
+ REQUIRE(one >= zero);
|
||||
+ REQUIRE(one >= one);
|
||||
+}
|
||||
+
|
||||
+TEST_CASE("Relational operators expected vs unexpected", "[relops]") {
|
||||
+ tl::expected<int, int> ezero(tl::unexpect, 0);
|
||||
+ tl::unexpected<int> uzero(0);
|
||||
+ tl::unexpected<int> uone(1);
|
||||
+
|
||||
+ REQUIRE(ezero == uzero);
|
||||
+ REQUIRE(ezero != uone);
|
||||
+ REQUIRE(uzero == ezero);
|
||||
+ REQUIRE(uone != ezero);
|
||||
+}
|
||||
--
|
||||
2.44.0.windows.1
|
||||
|
@ -0,0 +1,36 @@
|
||||
From 6aefb01b0f1547d05dd7eaa549c6f2f435a3b468 Mon Sep 17 00:00:00 2001
|
||||
From: Tim Blechmann <tim.blechmann@qt.io>
|
||||
Date: Sun, 11 May 2025 10:26:58 +0200
|
||||
Subject: [PATCH] tl::expected: disable exceptions with qt's macros
|
||||
|
||||
Change-Id: Ifee3f2800e03f7ecd5c9c218acfd3d7359cd6919
|
||||
---
|
||||
src/corelib/global/qexpected_p.h | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/src/corelib/global/qexpected_p.h b/src/corelib/global/qexpected_p.h
|
||||
index a54aea1f7d7..45c6196c947 100644
|
||||
--- a/src/corelib/global/qexpected_p.h
|
||||
+++ b/src/corelib/global/qexpected_p.h
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include <QtCore/qassert.h>
|
||||
#include <QtCore/qtconfigmacros.h>
|
||||
+#include <QtCore/qconfig.h>
|
||||
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
@@ -46,6 +47,10 @@
|
||||
#define TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
#endif
|
||||
|
||||
+#if defined(TL_EXPECTED_EXCEPTIONS_ENABLED) && defined(QT_NO_EXCEPTIONS)
|
||||
+# undef TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
+#endif
|
||||
+
|
||||
#if (defined(_MSC_VER) && _MSC_VER == 1900)
|
||||
#define TL_EXPECTED_MSVC2015
|
||||
#define TL_EXPECTED_MSVC2015_CONSTEXPR
|
||||
--
|
||||
2.49.0
|
||||
|
@ -0,0 +1,311 @@
|
||||
From c6064c91aa84412d07a4f3948d19496e0f294cef Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?J=C3=B8ger=20Hanseg=C3=A5rd?= <joger.hansegard@qt.io>
|
||||
Date: Wed, 19 Feb 2025 14:05:45 +0100
|
||||
Subject: [PATCH 2/3] Require in_place_t with variadic unexpected ctors
|
||||
|
||||
This makes unexpected ctors more consistent with the C++ standard
|
||||
---
|
||||
include/tl/expected.hpp | 31 +++++-----
|
||||
tests/constructors.cpp | 123 ++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 140 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/include/tl/expected.hpp b/include/tl/expected.hpp
|
||||
index 9d3a5e1..83920bd 100644
|
||||
--- a/include/tl/expected.hpp
|
||||
+++ b/include/tl/expected.hpp
|
||||
@@ -156,13 +156,15 @@ public:
|
||||
|
||||
template <class... Args, typename std::enable_if<std::is_constructible<
|
||||
E, Args &&...>::value>::type * = nullptr>
|
||||
- constexpr explicit unexpected(Args &&...args)
|
||||
+ constexpr explicit unexpected(in_place_t, Args &&...args)
|
||||
: m_val(std::forward<Args>(args)...) {}
|
||||
+
|
||||
template <
|
||||
class U, class... Args,
|
||||
typename std::enable_if<std::is_constructible<
|
||||
E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
|
||||
- constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
|
||||
+ constexpr explicit unexpected(in_place_t, std::initializer_list<U> l,
|
||||
+ Args &&...args)
|
||||
: m_val(l, std::forward<Args>(args)...) {}
|
||||
|
||||
constexpr const E &error() const & { return m_val; }
|
||||
@@ -471,7 +473,7 @@ struct expected_storage_base {
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
|
||||
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
@@ -479,7 +481,7 @@ struct expected_storage_base {
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&...args)
|
||||
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
~expected_storage_base() {
|
||||
if (m_has_val) {
|
||||
@@ -518,7 +520,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
|
||||
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
@@ -526,7 +528,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&...args)
|
||||
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
expected_storage_base(const expected_storage_base &) = default;
|
||||
expected_storage_base(expected_storage_base &&) = default;
|
||||
@@ -563,7 +565,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
|
||||
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
@@ -571,7 +573,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&...args)
|
||||
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
expected_storage_base(const expected_storage_base &) = default;
|
||||
expected_storage_base(expected_storage_base &&) = default;
|
||||
@@ -612,7 +614,7 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
|
||||
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
@@ -620,7 +622,8 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&...args)
|
||||
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, il, std::forward<Args>(args)...),
|
||||
+ m_has_val(false) {}
|
||||
|
||||
expected_storage_base(const expected_storage_base &) = default;
|
||||
expected_storage_base(expected_storage_base &&) = default;
|
||||
@@ -656,7 +659,7 @@ template <class E> struct expected_storage_base<void, E, false, true> {
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
|
||||
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
@@ -664,7 +667,7 @@ template <class E> struct expected_storage_base<void, E, false, true> {
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&...args)
|
||||
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
expected_storage_base(const expected_storage_base &) = default;
|
||||
expected_storage_base(expected_storage_base &&) = default;
|
||||
@@ -690,7 +693,7 @@ template <class E> struct expected_storage_base<void, E, false, false> {
|
||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
|
||||
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
template <class U, class... Args,
|
||||
detail::enable_if_t<std::is_constructible<
|
||||
@@ -698,7 +701,7 @@ template <class E> struct expected_storage_base<void, E, false, false> {
|
||||
constexpr explicit expected_storage_base(unexpect_t,
|
||||
std::initializer_list<U> il,
|
||||
Args &&...args)
|
||||
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
+ : m_unexpect(in_place, il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||
|
||||
expected_storage_base(const expected_storage_base &) = default;
|
||||
expected_storage_base(expected_storage_base &&) = default;
|
||||
diff --git a/tests/constructors.cpp b/tests/constructors.cpp
|
||||
index 10b96de..f24a46a 100644
|
||||
--- a/tests/constructors.cpp
|
||||
+++ b/tests/constructors.cpp
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
+#include <array>
|
||||
#include <string>
|
||||
|
||||
struct takes_init_and_variadic {
|
||||
@@ -13,6 +14,27 @@ struct takes_init_and_variadic {
|
||||
: v(l), t(std::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
+struct trivial_type {
|
||||
+ int x;
|
||||
+ int y;
|
||||
+ trivial_type(int _x, int _y) : x{_x}, y{_y} {}
|
||||
+ trivial_type(std::initializer_list<int> list) {
|
||||
+ auto it = list.begin();
|
||||
+ x = *it;
|
||||
+ ++it;
|
||||
+ y = *it;
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+struct takes_init_and_variadic_trivial {
|
||||
+ trivial_type p;
|
||||
+ std::tuple<int, int> t;
|
||||
+ template <class... Args>
|
||||
+ takes_init_and_variadic_trivial(std::initializer_list<int> l,
|
||||
+ Args &&...args)
|
||||
+ : p(l), t(std::forward<Args>(args)...) {}
|
||||
+};
|
||||
+
|
||||
TEST_CASE("Constructors", "[constructors]") {
|
||||
{
|
||||
tl::expected<int,int> e;
|
||||
@@ -38,6 +60,12 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(e == 42);
|
||||
}
|
||||
|
||||
+ {
|
||||
+ tl::expected<int, int> e(tl::in_place);
|
||||
+ REQUIRE(e);
|
||||
+ REQUIRE(e == 0);
|
||||
+ }
|
||||
+
|
||||
{
|
||||
tl::expected<std::vector<int>,int> e (tl::in_place, {0,1});
|
||||
REQUIRE(e);
|
||||
@@ -52,6 +80,40 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(std::get<1>(*e) == 1);
|
||||
}
|
||||
|
||||
+ {
|
||||
+ tl::expected<int, std::tuple<int, int>> e(tl::unexpect, 0, 1);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(std::get<0>(e.error()) == 0);
|
||||
+ REQUIRE(std::get<1>(e.error()) == 1);
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ tl::expected<void, std::tuple<int, int>> e(tl::unexpect, 0, 1);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(std::get<0>(e.error()) == 0);
|
||||
+ REQUIRE(std::get<1>(e.error()) == 1);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<void, std::vector<int>> e(tl::unexpect, 2, 1);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error()[0] == 1);
|
||||
+ REQUIRE(e.error()[1] == 1);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<std::vector<int>, std::vector<int>> e(tl::unexpect, 2, 1);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error()[0] == 1);
|
||||
+ REQUIRE(e.error()[1] == 1);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<std::vector<int>, takes_init_and_variadic> e(tl::unexpect,
|
||||
+ {0, 1}, 2, 3);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error().v[0] == 0);
|
||||
+ REQUIRE(e.error().v[1] == 1);
|
||||
+ REQUIRE(std::get<0>(e.error().t) == 2);
|
||||
+ REQUIRE(std::get<1>(e.error().t) == 3);
|
||||
+ }
|
||||
{
|
||||
tl::expected<takes_init_and_variadic,int> e (tl::in_place, {0,1}, 2, 3);
|
||||
REQUIRE(e);
|
||||
@@ -60,6 +122,59 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(std::get<0>(e->t) == 2);
|
||||
REQUIRE(std::get<1>(e->t) == 3);
|
||||
}
|
||||
+ {
|
||||
+ tl::expected<int, takes_init_and_variadic> e(tl::unexpect, {0, 1}, 2, 3);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error().v[0] == 0);
|
||||
+ REQUIRE(e.error().v[1] == 1);
|
||||
+ REQUIRE(std::get<0>(e.error().t) == 2);
|
||||
+ REQUIRE(std::get<1>(e.error().t) == 3);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<int, takes_init_and_variadic_trivial> e(tl::unexpect, {0, 1}, 2, 3);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error().p.x == 0);
|
||||
+ REQUIRE(e.error().p.y == 1);
|
||||
+ REQUIRE(std::get<0>(e.error().t) == 2);
|
||||
+ REQUIRE(std::get<1>(e.error().t) == 3);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<void, takes_init_and_variadic_trivial> e(tl::unexpect,
|
||||
+ {0, 1}, 2, 3);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error().p.x == 0);
|
||||
+ REQUIRE(e.error().p.y == 1);
|
||||
+ REQUIRE(std::get<0>(e.error().t) == 2);
|
||||
+ REQUIRE(std::get<1>(e.error().t) == 3);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<int, std::vector<int>> e(tl::unexpect, 2, 1);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error()[0] == 1);
|
||||
+ REQUIRE(e.error()[1] == 1);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<std::vector<int>, trivial_type> e(tl::unexpect, 1, 2);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error().x == 1);
|
||||
+ REQUIRE(e.error().y == 2);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<std::vector<int>, takes_init_and_variadic_trivial> e(tl::unexpect, {1, 2}, 3, 4);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error().p.x == 1);
|
||||
+ REQUIRE(e.error().p.y == 2);
|
||||
+ REQUIRE(std::get<0>(e.error().t) == 3);
|
||||
+ REQUIRE(std::get<1>(e.error().t) == 4);
|
||||
+ }
|
||||
+ {
|
||||
+ tl::expected<void, takes_init_and_variadic> e(tl::unexpect, {0, 1}, 2, 3);
|
||||
+ REQUIRE(!e);
|
||||
+ REQUIRE(e.error().v[0] == 0);
|
||||
+ REQUIRE(e.error().v[1] == 1);
|
||||
+ REQUIRE(std::get<0>(e.error().t) == 2);
|
||||
+ REQUIRE(std::get<1>(e.error().t) == 3);
|
||||
+ }
|
||||
|
||||
{
|
||||
tl::expected<int, int> e;
|
||||
@@ -152,3 +267,11 @@ TEST_CASE("Constructors", "[constructors]") {
|
||||
REQUIRE(e2.error().val == 's');
|
||||
}
|
||||
}
|
||||
+
|
||||
+TEST_CASE("Unexpected constructors", "[constructors]") {
|
||||
+ REQUIRE(tl::unexpected<int>(1).error() == 1);
|
||||
+ REQUIRE(tl::unexpected<int>(tl::in_place).error() == 0);
|
||||
+ REQUIRE(tl::unexpected<int>(tl::in_place, 1).error() == 1);
|
||||
+ REQUIRE(tl::unexpected<std::vector<int>>(tl::in_place, {1, 2, 3}).error() ==
|
||||
+ std::vector<int>{1, 2, 3});
|
||||
+}
|
||||
--
|
||||
2.44.0.windows.1
|
||||
|
@ -0,0 +1,106 @@
|
||||
From d99fc8961341d494597a62f5513573660a7f076f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?J=C3=B8ger=20Hanseg=C3=A5rd?= <joger.hansegard@qt.io>
|
||||
Date: Tue, 18 Feb 2025 16:07:45 +0100
|
||||
Subject: [PATCH 3/3] Adapt tl::expected to q23::expected
|
||||
|
||||
---
|
||||
include/tl/{expected.hpp => qexpected_p.h} | 33 ++++++++++++++++++----
|
||||
1 file changed, 27 insertions(+), 6 deletions(-)
|
||||
rename include/tl/{expected.hpp => qexpected_p.h} (99%)
|
||||
|
||||
diff --git a/include/tl/expected.hpp b/include/tl/qexpected_p.h
|
||||
similarity index 99%
|
||||
rename from include/tl/expected.hpp
|
||||
rename to include/tl/qexpected_p.h
|
||||
index 83920bd..a54aea1 100644
|
||||
--- a/include/tl/expected.hpp
|
||||
+++ b/include/tl/qexpected_p.h
|
||||
@@ -16,15 +16,32 @@
|
||||
#ifndef TL_EXPECTED_HPP
|
||||
#define TL_EXPECTED_HPP
|
||||
|
||||
+//
|
||||
+// W A R N I N G
|
||||
+// -------------
|
||||
+//
|
||||
+// This file is not part of the Qt API. It exists purely as an
|
||||
+// implementation detail. This header file may change from version to
|
||||
+// version without notice, or even be removed.
|
||||
+//
|
||||
+// We mean it.
|
||||
+//
|
||||
+
|
||||
#define TL_EXPECTED_VERSION_MAJOR 1
|
||||
#define TL_EXPECTED_VERSION_MINOR 1
|
||||
#define TL_EXPECTED_VERSION_PATCH 0
|
||||
|
||||
+#include <QtCore/private/qglobal_p.h>
|
||||
+#include <QtCore/qassert.h>
|
||||
+#include <QtCore/qtconfigmacros.h>
|
||||
+
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
+#define TL_ASSERT Q_ASSERT
|
||||
+
|
||||
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
|
||||
#define TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
#endif
|
||||
@@ -81,7 +98,8 @@
|
||||
#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
|
||||
-namespace tl {
|
||||
+QT_BEGIN_NAMESPACE
|
||||
+namespace q23 {
|
||||
namespace detail {
|
||||
template <class T>
|
||||
struct is_trivially_copy_constructible
|
||||
@@ -91,11 +109,12 @@ template <class T, class A>
|
||||
struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
|
||||
#endif
|
||||
} // namespace detail
|
||||
-} // namespace tl
|
||||
+} // namespace q23
|
||||
+QT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
|
||||
- tl::detail::is_trivially_copy_constructible<T>
|
||||
+ q23::detail::is_trivially_copy_constructible<T>
|
||||
#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
|
||||
std::is_trivially_copy_assignable<T>
|
||||
#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
|
||||
@@ -132,7 +151,8 @@ struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
|
||||
#define TL_EXPECTED_11_CONSTEXPR constexpr
|
||||
#endif
|
||||
|
||||
-namespace tl {
|
||||
+QT_BEGIN_NAMESPACE
|
||||
+namespace q23 {
|
||||
template <class T, class E> class expected;
|
||||
|
||||
#ifndef TL_MONOSTATE_INPLACE_MUTEX
|
||||
@@ -396,7 +416,7 @@ struct is_nothrow_swappable
|
||||
#endif
|
||||
#endif
|
||||
|
||||
-// Trait for checking if a type is a tl::expected
|
||||
+// Trait for checking if a type is a q23::expected
|
||||
template <class T> struct is_expected_impl : std::false_type {};
|
||||
template <class T, class E>
|
||||
struct is_expected_impl<expected<T, E>> : std::true_type {};
|
||||
@@ -2474,6 +2494,7 @@ void swap(expected<T, E> &lhs,
|
||||
expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
-} // namespace tl
|
||||
+} // namespace q23
|
||||
+QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
--
|
||||
2.44.0.windows.1
|
||||
|
11
src/corelib/global/patches/tlexpected/0004-Prefix-SPDX.patch
Normal file
11
src/corelib/global/patches/tlexpected/0004-Prefix-SPDX.patch
Normal file
@ -0,0 +1,11 @@
|
||||
diff --git a/src/corelib/global/qexpected_p.h b/src/corelib/global/qexpected_p.h
|
||||
index 45c6196c947..1c9b37ae82f 100644
|
||||
--- a/src/corelib/global/qexpected_p.h
|
||||
+++ b/src/corelib/global/qexpected_p.h
|
||||
@@ -1,3 +1,6 @@
|
||||
+// Copyright (C) 2017 Sy Brand (tartanllama@gmail.com, @TartanLlama)
|
||||
+// SPDX-License-Identifier: CC0-1.0
|
||||
+
|
||||
///
|
||||
// expected - An implementation of std::expected with extensions
|
||||
// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
|
2508
src/corelib/global/qexpected_p.h
Normal file
2508
src/corelib/global/qexpected_p.h
Normal file
File diff suppressed because it is too large
Load Diff
14
src/corelib/global/qt_attribution.json
Normal file
14
src/corelib/global/qt_attribution.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"Id": "tlexpected",
|
||||
"Name": "tl::expected",
|
||||
"QDocModule": "qtcore",
|
||||
"QtUsage": "Available as a private type in all Qt modules",
|
||||
"Description": "Single header implementation of std::expected with functional-style extensions.",
|
||||
"Files": [ "qexpected_p.h" ],
|
||||
"Homepage": "https://github.com/TartanLlama/expected/",
|
||||
"Version": "41d3e1f48d682992a2230b2a715bca38b848b269",
|
||||
"DownloadLocation": "https://github.com/TartanLlama/expected/blob/41d3e1f48d682992a2230b2a715bca38b848b269/include/tl/expected.hpp",
|
||||
"License": "Creative Commons Zero v1.0 Universal",
|
||||
"LicenseId": "CC0-1.0",
|
||||
"Copyright": "To the extent possible under law, Sy Brand has waived all copyright and related or neighboring rights to the expected library. This work is published from: United Kingdom."
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user