rippled
Loading...
Searching...
No Matches
Expected.h
1#pragma once
2
3#include <xrpl/basics/contract.h>
4
5#include <boost/outcome.hpp>
6
7#include <stdexcept>
8
9namespace xrpl {
10
18// Exception thrown by an invalid access to Expected.
20{
21 bad_expected_access() : runtime_error("bad expected access")
22 {
23 }
24};
25
26namespace detail {
27
28// Custom policy for Expected. Always throw on an invalid access.
29struct throw_policy : public boost::outcome_v2::policy::base
30{
31 template <class Impl>
32 static constexpr void
33 wide_value_check(Impl&& self)
34 {
35 if (!base::_has_value(std::forward<Impl>(self)))
36 Throw<bad_expected_access>();
37 }
38
39 template <class Impl>
40 static constexpr void
41 wide_error_check(Impl&& self)
42 {
43 if (!base::_has_error(std::forward<Impl>(self)))
44 Throw<bad_expected_access>();
45 }
46
47 template <class Impl>
48 static constexpr void
50 {
51 if (!base::_has_exception(std::forward<Impl>(self)))
52 Throw<bad_expected_access>();
53 }
54};
55
56} // namespace detail
57
58// Definition of Unexpected, which is used to construct the unexpected
59// return type of an Expected.
60template <class E>
62{
63public:
64 static_assert(!std::is_same<E, void>::value, "E must not be void");
65
66 Unexpected() = delete;
67
68 constexpr explicit Unexpected(E const& e) : val_(e)
69 {
70 }
71
72 constexpr explicit Unexpected(E&& e) : val_(std::move(e))
73 {
74 }
75
76 constexpr E const&
77 value() const&
78 {
79 return val_;
80 }
81
82 constexpr E&
84 {
85 return val_;
86 }
87
88 constexpr E&&
89 value() &&
90 {
91 return std::move(val_);
92 }
93
94 constexpr E const&&
95 value() const&&
96 {
97 return std::move(val_);
98 }
99
100private:
102};
103
104// Unexpected deduction guide that converts array to const*.
105template <typename E, std::size_t N>
107
108// Definition of Expected. All of the machinery comes from boost::result.
109template <class T, class E>
110class [[nodiscard]] Expected : private boost::outcome_v2::result<T, E, detail::throw_policy>
111{
112 using Base = boost::outcome_v2::result<T, E, detail::throw_policy>;
113
114public:
115 template <typename U>
117 constexpr Expected(U&& r) : Base(boost::outcome_v2::in_place_type_t<T>{}, std::forward<U>(r))
118 {
119 }
120
121 template <typename U>
124 : Base(boost::outcome_v2::in_place_type_t<E>{}, std::move(e.value()))
125 {
126 }
127
128 constexpr bool
129 has_value() const
130 {
131 return Base::has_value();
132 }
133
134 constexpr T const&
135 value() const
136 {
137 return Base::value();
138 }
139
140 constexpr T&
142 {
143 return Base::value();
144 }
145
146 constexpr E const&
147 error() const
148 {
149 return Base::error();
150 }
151
152 constexpr E&
154 {
155 return Base::error();
156 }
157
158 constexpr explicit
159 operator bool() const
160 {
161 return has_value();
162 }
163
164 // Add operator* and operator-> so the Expected API looks a bit more like
165 // what std::expected is likely to look like. See:
166 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
167 [[nodiscard]] constexpr T&
169 {
170 return this->value();
171 }
172
173 [[nodiscard]] constexpr T const&
174 operator*() const
175 {
176 return this->value();
177 }
178
179 [[nodiscard]] constexpr T*
181 {
182 return &this->value();
183 }
184
185 [[nodiscard]] constexpr T const*
187 {
188 return &this->value();
189 }
190};
191
192// Specialization of Expected<void, E>. Allows returning either success
193// (without a value) or the reason for the failure.
194template <class E>
195class [[nodiscard]]
196Expected<void, E> : private boost::outcome_v2::result<void, E, detail::throw_policy>
197{
198 using Base = boost::outcome_v2::result<void, E, detail::throw_policy>;
199
200public:
201 // The default constructor makes a successful Expected<void, E>.
202 // This aligns with std::expected behavior proposed in P0323R10.
203 constexpr Expected() : Base(boost::outcome_v2::success())
204 {
205 }
206
207 template <typename U>
209 constexpr Expected(Unexpected<U> e) : Base(E(std::move(e.value())))
210 {
211 }
212
213 constexpr E const&
214 error() const
215 {
216 return Base::error();
217 }
218
219 constexpr E&
221 {
222 return Base::error();
223 }
224
225 constexpr explicit
226 operator bool() const
227 {
228 return Base::has_value();
229 }
230};
231
232} // namespace xrpl
boost::outcome_v2::result< void, E, detail::throw_policy > Base
Definition Expected.h:198
constexpr E & error()
Definition Expected.h:220
constexpr E const & error() const
Definition Expected.h:214
constexpr Expected(Unexpected< U > e)
Definition Expected.h:209
constexpr bool has_value() const
Definition Expected.h:129
constexpr T const & value() const
Definition Expected.h:135
constexpr Expected(U &&r)
Definition Expected.h:117
constexpr T const & operator*() const
Definition Expected.h:174
constexpr T & operator*()
Definition Expected.h:168
boost::outcome_v2::result< T, E, detail::throw_policy > Base
Definition Expected.h:112
constexpr T * operator->()
Definition Expected.h:180
constexpr E & error()
Definition Expected.h:153
constexpr T const * operator->() const
Definition Expected.h:186
constexpr Expected(Unexpected< U > e)
Definition Expected.h:123
constexpr T & value()
Definition Expected.h:141
constexpr E const & error() const
Definition Expected.h:147
constexpr E && value() &&
Definition Expected.h:89
constexpr E const & value() const &
Definition Expected.h:77
Unexpected()=delete
constexpr Unexpected(E &&e)
Definition Expected.h:72
constexpr E & value() &
Definition Expected.h:83
constexpr E const && value() const &&
Definition Expected.h:95
constexpr Unexpected(E const &e)
Definition Expected.h:68
T is_same_v
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Expected is an approximation of std::expected (hoped for in C++23)
Definition Expected.h:20
static constexpr void wide_value_check(Impl &&self)
Definition Expected.h:33
static constexpr void wide_error_check(Impl &&self)
Definition Expected.h:41
static constexpr void wide_exception_check(Impl &&self)
Definition Expected.h:49