rippled
Expected.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2021 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_BASICS_EXPECTED_H_INCLUDED
21 #define RIPPLE_BASICS_EXPECTED_H_INCLUDED
22 
23 #include <ripple/basics/contract.h>
24 #include <boost/outcome.hpp>
25 #include <stdexcept>
26 #include <type_traits>
27 
28 namespace ripple {
29 
37 // Exception thrown by an invalid access to Expected.
39 {
40  bad_expected_access() : runtime_error("bad expected access")
41  {
42  }
43 };
44 
45 namespace detail {
46 
47 // Custom policy for Expected. Always throw on an invalid access.
48 struct throw_policy : public boost::outcome_v2::policy::base
49 {
50  template <class Impl>
51  static constexpr void
52  wide_value_check(Impl&& self)
53  {
54  if (!base::_has_value(std::forward<Impl>(self)))
55  Throw<bad_expected_access>();
56  }
57 
58  template <class Impl>
59  static constexpr void
60  wide_error_check(Impl&& self)
61  {
62  if (!base::_has_error(std::forward<Impl>(self)))
63  Throw<bad_expected_access>();
64  }
65 
66  template <class Impl>
67  static constexpr void
68  wide_exception_check(Impl&& self)
69  {
70  if (!base::_has_exception(std::forward<Impl>(self)))
71  Throw<bad_expected_access>();
72  }
73 };
74 
75 } // namespace detail
76 
77 // Definition of Unexpected, which is used to construct the unexpected
78 // return type of an Expected.
79 template <class E>
81 {
82 public:
83  static_assert(!std::is_same<E, void>::value, "E must not be void");
84 
85  Unexpected() = delete;
86 
87  constexpr explicit Unexpected(E const& e) : val_(e)
88  {
89  }
90 
91  constexpr explicit Unexpected(E&& e) : val_(std::move(e))
92  {
93  }
94 
95  constexpr const E&
96  value() const&
97  {
98  return val_;
99  }
100 
101  constexpr E&
102  value() &
103  {
104  return val_;
105  }
106 
107  constexpr E&&
108  value() &&
109  {
110  return std::move(val_);
111  }
112 
113  constexpr const E&&
114  value() const&&
115  {
116  return std::move(val_);
117  }
118 
119 private:
120  E val_;
121 };
122 
123 // Unexpected deduction guide that converts array to const*.
124 template <typename E, std::size_t N>
125 Unexpected(E (&)[N]) -> Unexpected<E const*>;
126 
127 // Definition of Expected. All of the machinery comes from boost::result.
128 template <class T, class E>
129 class [[nodiscard]] Expected
130  : private boost::outcome_v2::result<T, E, detail::throw_policy>
131 {
132  using Base = boost::outcome_v2::result<T, E, detail::throw_policy>;
133 
134 public:
135  template <
136  typename U,
138  constexpr Expected(U r) : Base(T{std::forward<U>(r)})
139  {
140  }
141 
142  template <
143  typename U,
145  constexpr Expected(Unexpected<U> e) : Base(E{std::forward<U>(e.value())})
146  {
147  }
148 
149  constexpr bool has_value() const
150  {
151  return Base::has_value();
152  }
153 
154  constexpr T const& value() const
155  {
156  return Base::value();
157  }
158 
159  constexpr T& value()
160  {
161  return Base::value();
162  }
163 
164  constexpr E const& error() const
165  {
166  return Base::error();
167  }
168 
169  constexpr E& error()
170  {
171  return Base::error();
172  }
173 
174  constexpr explicit operator bool() const
175  {
176  return has_value();
177  }
178 
179  // Add operator* and operator-> so the Expected API looks a bit more like
180  // what std::expected is likely to look like. See:
181  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
182  [[nodiscard]] constexpr T& operator*()
183  {
184  return this->value();
185  }
186 
187  [[nodiscard]] constexpr T const& operator*() const
188  {
189  return this->value();
190  }
191 
192  [[nodiscard]] constexpr T* operator->()
193  {
194  return &this->value();
195  }
196 
197  [[nodiscard]] constexpr T const* operator->() const
198  {
199  return &this->value();
200  }
201 };
202 
203 // Specialization of Expected<void, E>. Allows returning either success
204 // (without a value) or the reason for the failure.
205 template <class E>
206 class [[nodiscard]] Expected<void, E>
207  : private boost::outcome_v2::result<void, E, detail::throw_policy>
208 {
209  using Base = boost::outcome_v2::result<void, E, detail::throw_policy>;
210 
211 public:
212  // The default constructor makes a successful Expected<void, E>.
213  // This aligns with std::expected behavior proposed in P0323R10.
214  constexpr Expected() : Base(boost::outcome_v2::success())
215  {
216  }
217 
218  template <
219  typename U,
221  constexpr Expected(Unexpected<U> e) : Base(E{std::forward<U>(e.value())})
222  {
223  }
224 
225  constexpr E const& error() const
226  {
227  return Base::error();
228  }
229 
230  constexpr E& error()
231  {
232  return Base::error();
233  }
234 
235  constexpr explicit operator bool() const
236  {
237  return Base::has_value();
238  }
239 };
240 
241 } // namespace ripple
242 
243 #endif // RIPPLE_BASICS_EXPECTED_H_INCLUDED
ripple::bad_expected_access::bad_expected_access
bad_expected_access()
Definition: Expected.h:40
std::is_same
ripple::Expected::error
constexpr E & error()
Definition: Expected.h:169
ripple::Expected::value
constexpr T const & value() const
Definition: Expected.h:154
ripple::bad_expected_access
Expected is an approximation of std::expected (hoped for in C++23)
Definition: Expected.h:38
ripple::Expected::error
constexpr E const & error() const
Definition: Expected.h:164
ripple::Unexpected::Unexpected
constexpr Unexpected(E const &e)
Definition: Expected.h:87
ripple::Unexpected
Unexpected(E(&)[N]) -> Unexpected< E const * >
ripple::Expected::value
constexpr T & value()
Definition: Expected.h:159
ripple::Expected::Expected
constexpr Expected(U r)
Definition: Expected.h:138
boost
Definition: IPAddress.h:103
ripple::Expected::has_value
constexpr bool has_value() const
Definition: Expected.h:149
ripple::Unexpected::value
constexpr const E && value() const &&
Definition: Expected.h:114
ripple::detail::throw_policy
Definition: Expected.h:48
ripple::Expected< void, E >::error
constexpr E & error()
Definition: Expected.h:230
stdexcept
ripple::Expected::Expected
constexpr Expected(Unexpected< U > e)
Definition: Expected.h:145
ripple::Expected< void, E >::Expected
constexpr Expected(Unexpected< U > e)
Definition: Expected.h:221
ripple::Unexpected::value
constexpr const E & value() const &
Definition: Expected.h:96
ripple::Unexpected::value
constexpr E & value() &
Definition: Expected.h:102
ripple::Expected::Base
boost::outcome_v2::result< T, E, detail::throw_policy > Base
Definition: Expected.h:132
ripple::Expected
Definition: Expected.h:129
ripple::Expected< void, E >::Expected
constexpr Expected()
Definition: Expected.h:214
ripple::detail::throw_policy::wide_value_check
static constexpr void wide_value_check(Impl &&self)
Definition: Expected.h:52
std::enable_if_t
ripple::Expected::operator->
constexpr T * operator->()
Definition: Expected.h:192
std::runtime_error
STL class.
ripple::detail::throw_policy::wide_error_check
static constexpr void wide_error_check(Impl &&self)
Definition: Expected.h:60
ripple::Expected::operator*
constexpr T const & operator*() const
Definition: Expected.h:187
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Unexpected::Unexpected
constexpr Unexpected(E &&e)
Definition: Expected.h:91
ripple::Expected< void, E >::Base
boost::outcome_v2::result< void, E, detail::throw_policy > Base
Definition: Expected.h:209
std
STL namespace.
ripple::Unexpected::value
constexpr E && value() &&
Definition: Expected.h:108
ripple::Expected< void, E >::error
constexpr E const & error() const
Definition: Expected.h:225
ripple::Unexpected
Definition: Expected.h:80
ripple::Expected::operator*
constexpr T & operator*()
Definition: Expected.h:182
ripple::Unexpected::Unexpected
Unexpected()=delete
ripple::Expected::operator->
constexpr T const * operator->() const
Definition: Expected.h:197
type_traits
ripple::detail::throw_policy::wide_exception_check
static constexpr void wide_exception_check(Impl &&self)
Definition: Expected.h:68
ripple::Unexpected::val_
E val_
Definition: Expected.h:120