/root/bitcoin/src/util/expected.h
Line | Count | Source |
1 | | // Copyright (c) The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or https://opensource.org/license/mit. |
4 | | |
5 | | #ifndef BITCOIN_UTIL_EXPECTED_H |
6 | | #define BITCOIN_UTIL_EXPECTED_H |
7 | | |
8 | | #include <attributes.h> |
9 | | #include <util/check.h> |
10 | | |
11 | | #include <cassert> |
12 | | #include <exception> |
13 | | #include <utility> |
14 | | #include <variant> |
15 | | |
16 | | namespace util { |
17 | | |
18 | | /// The util::Unexpected class represents an unexpected value stored in |
19 | | /// util::Expected. |
20 | | template <class E> |
21 | | class Unexpected |
22 | | { |
23 | | public: |
24 | 0 | constexpr explicit Unexpected(E e) : m_error(std::move(e)) {}Unexecuted instantiation: util::Unexpected<ThreadPool::SubmitError>::Unexpected(ThreadPool::SubmitError) Unexecuted instantiation: util::Unexpected<char const*>::Unexpected(char const*) Unexecuted instantiation: util::Unexpected<node::ReadRawError>::Unexpected(node::ReadRawError) |
25 | | |
26 | | constexpr const E& error() const& noexcept LIFETIMEBOUND { return m_error; } |
27 | | constexpr E& error() & noexcept LIFETIMEBOUND { return m_error; } |
28 | 0 | constexpr E&& error() && noexcept LIFETIMEBOUND { return std::move(m_error); }Unexecuted instantiation: util::Unexpected<ThreadPool::SubmitError>::error() && Unexecuted instantiation: util::Unexpected<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::error() && Unexecuted instantiation: util::Unexpected<char const*>::error() && Unexecuted instantiation: util::Unexpected<node::ReadRawError>::error() && |
29 | | |
30 | | private: |
31 | | E m_error; |
32 | | }; |
33 | | |
34 | | struct BadExpectedAccess : std::exception { |
35 | 0 | const char* what() const noexcept override { return "Bad util::Expected access"; } |
36 | | }; |
37 | | |
38 | | /// The util::Expected class provides a standard way for low-level functions to |
39 | | /// return either error values or result values. |
40 | | /// |
41 | | /// It provides a smaller version of std::expected from C++23. Missing features |
42 | | /// can be added, if needed. |
43 | | template <class T, class E> |
44 | | class Expected |
45 | | { |
46 | | private: |
47 | | std::variant<T, E> m_data; |
48 | | |
49 | | public: |
50 | | constexpr Expected() : m_data{std::in_place_index<0>, T{}} {} |
51 | 0 | constexpr Expected(T v) : m_data{std::in_place_index<0>, std::move(v)} {}Unexecuted instantiation: util::Expected<std::future<void>, ThreadPool::SubmitError>::Expected(std::future<void>) Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::Expected(std::vector<std::byte, std::allocator<std::byte> >) Unexecuted instantiation: util::Expected<TxoSpender, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Expected(TxoSpender) Unexecuted instantiation: util::Expected<std::optional<TxoSpender>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Expected(std::optional<TxoSpender>) |
52 | | template <class Err> |
53 | 0 | constexpr Expected(Unexpected<Err> u) : m_data{std::in_place_index<1>, std::move(u).error()} |
54 | 0 | { |
55 | 0 | } Unexecuted instantiation: util::Expected<std::future<void>, ThreadPool::SubmitError>::Expected<ThreadPool::SubmitError>(util::Unexpected<ThreadPool::SubmitError>) Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::Expected<node::ReadRawError>(util::Unexpected<node::ReadRawError>) Unexecuted instantiation: util::Expected<TxoSpender, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Expected<char const*>(util::Unexpected<char const*>) Unexecuted instantiation: util::Expected<std::optional<TxoSpender>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Expected<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(util::Unexpected<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) |
56 | | |
57 | 0 | constexpr bool has_value() const noexcept { return m_data.index() == 0; }Unexecuted instantiation: util::Expected<std::future<void>, ThreadPool::SubmitError>::has_value() const Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::has_value() const Unexecuted instantiation: util::Expected<std::optional<TxoSpender>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_value() const Unexecuted instantiation: util::Expected<TxoSpender, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::has_value() const |
58 | 0 | constexpr explicit operator bool() const noexcept { return has_value(); }Unexecuted instantiation: util::Expected<std::future<void>, ThreadPool::SubmitError>::operator bool() const Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::operator bool() const Unexecuted instantiation: util::Expected<std::optional<TxoSpender>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator bool() const Unexecuted instantiation: util::Expected<TxoSpender, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator bool() const |
59 | | |
60 | | constexpr const T& value() const& LIFETIMEBOUND |
61 | 0 | { |
62 | 0 | if (!has_value()) { |
63 | 0 | throw BadExpectedAccess{}; |
64 | 0 | } |
65 | 0 | return std::get<0>(m_data); |
66 | 0 | } Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::value() const & Unexecuted instantiation: util::Expected<std::optional<TxoSpender>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::value() const & Unexecuted instantiation: util::Expected<TxoSpender, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::value() const & |
67 | | constexpr T& value() & LIFETIMEBOUND |
68 | 0 | { |
69 | 0 | if (!has_value()) { |
70 | 0 | throw BadExpectedAccess{}; |
71 | 0 | } |
72 | 0 | return std::get<0>(m_data); |
73 | 0 | } Unexecuted instantiation: util::Expected<std::future<void>, ThreadPool::SubmitError>::value() & Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::value() & |
74 | | constexpr T&& value() && LIFETIMEBOUND { return std::move(value()); } |
75 | | |
76 | | template <class U> |
77 | | T value_or(U&& default_value) const& |
78 | | { |
79 | | return has_value() ? value() : std::forward<U>(default_value); |
80 | | } |
81 | | template <class U> |
82 | | T value_or(U&& default_value) && |
83 | | { |
84 | | return has_value() ? std::move(value()) : std::forward<U>(default_value); |
85 | | } |
86 | | |
87 | 0 | constexpr const E& error() const& noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }Line | Count | Source | 113 | 0 | #define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val) |
| constexpr const E& error() const& noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }Line | Count | Source | 113 | 0 | #define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val) |
| constexpr const E& error() const& noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }Line | Count | Source | 113 | 0 | #define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val) |
Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::error() const & Unexecuted instantiation: util::Expected<std::optional<TxoSpender>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::error() const & Unexecuted instantiation: util::Expected<TxoSpender, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::error() const & |
88 | 0 | constexpr E& error() & noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }Line | Count | Source | 113 | 0 | #define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val) |
|
89 | | constexpr E&& error() && noexcept LIFETIMEBOUND { return std::move(error()); } |
90 | | |
91 | | constexpr void swap(Expected& other) noexcept { m_data.swap(other.m_data); } |
92 | | |
93 | 0 | constexpr T& operator*() & noexcept LIFETIMEBOUND { return value(); } |
94 | 0 | constexpr const T& operator*() const& noexcept LIFETIMEBOUND { return value(); }Unexecuted instantiation: util::Expected<std::vector<std::byte, std::allocator<std::byte> >, node::ReadRawError>::operator*() const & Unexecuted instantiation: util::Expected<TxoSpender, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator*() const & |
95 | 0 | constexpr T&& operator*() && noexcept LIFETIMEBOUND { return std::move(value()); } |
96 | | |
97 | | constexpr T* operator->() noexcept LIFETIMEBOUND { return &value(); } |
98 | 0 | constexpr const T* operator->() const noexcept LIFETIMEBOUND { return &value(); } |
99 | | }; |
100 | | |
101 | | template <class E> |
102 | | class Expected<void, E> |
103 | | { |
104 | | private: |
105 | | std::variant<std::monostate, E> m_data; |
106 | | |
107 | | public: |
108 | 0 | constexpr Expected() : m_data{std::in_place_index<0>, std::monostate{}} {} |
109 | | template <class Err> |
110 | 0 | constexpr Expected(Unexpected<Err> u) : m_data{std::in_place_index<1>, std::move(u).error()} |
111 | 0 | { |
112 | 0 | } Unexecuted instantiation: util::Expected<void, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Expected<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(util::Unexpected<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) Unexecuted instantiation: util::Expected<void, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Expected<char const*>(util::Unexpected<char const*>) |
113 | | |
114 | 0 | constexpr bool has_value() const noexcept { return m_data.index() == 0; } |
115 | 0 | constexpr explicit operator bool() const noexcept { return has_value(); } |
116 | | |
117 | | constexpr void operator*() const noexcept { return value(); } |
118 | | constexpr void value() const |
119 | | { |
120 | | if (!has_value()) { |
121 | | throw BadExpectedAccess{}; |
122 | | } |
123 | | } |
124 | | |
125 | 0 | constexpr const E& error() const& noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }Line | Count | Source | 113 | 0 | #define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val) |
|
126 | 0 | constexpr E& error() & noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }Line | Count | Source | 113 | 0 | #define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val) |
|
127 | | constexpr E&& error() && noexcept LIFETIMEBOUND { return std::move(error()); } |
128 | | }; |
129 | | |
130 | | } // namespace util |
131 | | |
132 | | #endif // BITCOIN_UTIL_EXPECTED_H |