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 <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 : : constexpr explicit Unexpected(E e) : m_error(std::move(e)) {}
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); }
29 : :
30 : : private:
31 : : E m_error;
32 : : };
33 : :
34 : 0 : 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 : 29749 : 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 : 4681 : constexpr Expected(T v) : m_data{std::in_place_index<0>, std::move(v)} {}
52 : : template <class Err>
53 : : constexpr Expected(Unexpected<Err> u) : m_data{std::in_place_index<1>, std::move(u).error()}
54 : : {
55 : : }
56 : :
57 : 34430 : constexpr bool has_value() const noexcept { return m_data.index() == 0; }
58 [ + + ]: 29749 : constexpr explicit operator bool() const noexcept { return has_value(); }
59 : :
60 [ - + ]: 4674 : constexpr const T& value() const& LIFETIMEBOUND
61 : : {
62 [ - + ]: 4674 : if (!has_value()) {
63 : 0 : throw BadExpectedAccess{};
64 : : }
65 : 4674 : return std::get<0>(m_data);
66 : : }
67 [ - + ]: 7 : constexpr T& value() & LIFETIMEBOUND
68 : : {
69 [ - + ]: 7 : if (!has_value()) {
70 : 0 : throw BadExpectedAccess{};
71 : : }
72 : 7 : return std::get<0>(m_data);
73 : : }
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)); }
88 : : constexpr E& error() & noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }
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 : 7 : constexpr T& operator*() & noexcept LIFETIMEBOUND { return value(); }
94 : 4674 : constexpr const T& operator*() const& noexcept LIFETIMEBOUND { return value(); }
95 : : constexpr T&& operator*() && noexcept LIFETIMEBOUND { return std::move(value()); }
96 : :
97 : : constexpr T* operator->() noexcept LIFETIMEBOUND { return &value(); }
98 : : constexpr const T* operator->() const noexcept LIFETIMEBOUND { return &value(); }
99 : : };
100 : :
101 : : template <class E>
102 : 0 : class Expected<void, E>
103 : : {
104 : : private:
105 : : std::variant<std::monostate, E> m_data;
106 : :
107 : : public:
108 : : 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 : : {
112 : 0 : }
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)); }
126 : : constexpr E& error() & noexcept LIFETIMEBOUND { return *Assert(std::get_if<1>(&m_data)); }
127 : : constexpr E&& error() && noexcept LIFETIMEBOUND { return std::move(error()); }
128 : : };
129 : :
130 : : } // namespace util
131 : :
132 : : #endif // BITCOIN_UTIL_EXPECTED_H
|