Branch data Line data Source code
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 : 4 : class Unexpected
21 : : {
22 : : public:
23 : 4 : constexpr explicit Unexpected(E e) : m_error(std::move(e)) {}
24 : :
25 : : constexpr const E& error() const& noexcept LIFETIMEBOUND { return m_error; }
26 : : constexpr E& error() & noexcept LIFETIMEBOUND { return m_error; }
27 : 9 : constexpr E&& error() && noexcept LIFETIMEBOUND { return std::move(m_error); }
28 : :
29 : : private:
30 : : E m_error;
31 : : };
32 : :
33 : 2 : 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 [ + - + - ]: 382862 : 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 [ + - ]: 382703 : constexpr Expected(T v) : m_data{std::in_place_index<0>, std::move(v)} {}
51 : : template <class Err>
52 [ + - # # ]: 3 : constexpr Expected(Unexpected<Err> u) : m_data{std::in_place_index<1>, std::move(u).error()}
[ # # # # ]
53 : : {
54 : 0 : }
55 : :
56 [ + + + - : 561574 : constexpr bool has_value() const noexcept { return m_data.index() == 0; }
+ - ][ + -
# # # # ]
57 [ + + ][ - + : 178864 : constexpr explicit operator bool() const noexcept { return has_value(); }
- + - + -
+ + - + -
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + +
- + - + -
+ - + - -
+ ]
58 : :
59 [ + + ]: 169939 : constexpr const T& value() const& LIFETIMEBOUND
60 : : {
61 [ + + ]: 169939 : if (!has_value()) {
62 : 1 : throw BadExpectedAccess{};
63 : : }
64 : 169938 : return std::get<0>(m_data);
65 : : }
66 [ - + ]: 8894 : constexpr T& value() & LIFETIMEBOUND
67 : : {
68 [ - + ]: 8894 : if (!has_value()) {
69 : 0 : throw BadExpectedAccess{};
70 : : }
71 : 8894 : return std::get<0>(m_data);
72 : : }
73 [ + - ]: 11 : constexpr T&& value() && LIFETIMEBOUND { return std::move(value()); }
74 : :
75 : : template <class U>
76 [ - + ]: 1 : T value_or(U&& default_value) const&
77 : : {
78 [ - + - - ]: 1 : return has_value() ? value() : std::forward<U>(default_value);
79 : : }
80 : : template <class U>
81 [ + - ]: 1 : T value_or(U&& default_value) &&
82 : : {
83 [ + - ]: 1 : return has_value() ? std::move(value()) : std::forward<U>(default_value);
84 : : }
85 : :
86 [ + - - + ]: 28 : constexpr const E& error() const& noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }
87 [ + - - + ]: 42 : constexpr E& error() & noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }
88 : 1 : constexpr E&& error() && noexcept LIFETIMEBOUND { return std::move(error()); }
89 : :
90 [ + - ]: 1 : constexpr void swap(Expected& other) noexcept { m_data.swap(other.m_data); }
91 : :
92 : 8458 : constexpr T& operator*() & noexcept LIFETIMEBOUND { return value(); }
93 : 169891 : constexpr const T& operator*() const& noexcept LIFETIMEBOUND { return value(); }
94 : 380 : constexpr T&& operator*() && noexcept LIFETIMEBOUND { return std::move(value()); }
95 : :
96 : 26 : constexpr T* operator->() noexcept LIFETIMEBOUND { return &value(); }
97 : 31 : constexpr const T* operator->() const noexcept LIFETIMEBOUND { return &value(); }
98 : : };
99 : :
100 : : template <class E>
101 [ + - ]: 520 : class Expected<void, E>
102 : : {
103 : : private:
104 : : std::variant<std::monostate, E> m_data;
105 : :
106 : : public:
107 : : constexpr Expected() : m_data{std::in_place_index<0>, std::monostate{}} {}
108 : : template <class Err>
109 [ + - + - : 6 : constexpr Expected(Unexpected<Err> u) : m_data{std::in_place_index<1>, std::move(u).error()}
+ - - - ]
[ # # # #
# # # # ]
110 : : {
111 : 3 : }
112 : :
113 [ + - + - ]: 518 : constexpr bool has_value() const noexcept { return m_data.index() == 0; }
114 [ + + ]: 517 : constexpr explicit operator bool() const noexcept { return has_value(); }
115 : :
116 : 1 : constexpr void operator*() const noexcept { return value(); }
117 [ + + ]: 3 : constexpr void value() const
118 : : {
119 [ + + ]: 3 : if (!has_value()) {
120 : 1 : throw BadExpectedAccess{};
121 : : }
122 : 2 : }
123 : :
124 [ + - - + ]: 8 : constexpr const E& error() const& noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }
125 [ + - - + ]: 6 : constexpr E& error() & noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }
126 : 1 : constexpr E&& error() && noexcept LIFETIMEBOUND { return std::move(error()); }
127 : : };
128 : :
129 : : } // namespace util
130 : :
131 : : #endif // BITCOIN_UTIL_EXPECTED_H
|