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