19 #ifndef PSTORE_ADT_ERROR_OR_HPP 20 #define PSTORE_ADT_ERROR_OR_HPP 23 #include <system_error> 28 #include "pstore/support/gsl.hpp" 33 template <
typename Error>
34 struct is_error : std::integral_constant<bool, std::is_error_code_enum<Error>::value ||
35 std::is_error_condition_enum<Error>::value> {
40 template <
typename Other>
43 using wrapper = std::reference_wrapper<typename std::remove_reference<T>::type>;
45 typename std::conditional<std::is_reference<T>::value, wrapper, T>::type;
49 using reference = T &;
50 using const_reference =
typename std::remove_reference<T>::type
const &;
58 template <
typename ErrorCode,
59 typename =
typename std::enable_if<is_error<ErrorCode>::value>::type>
60 explicit error_or (ErrorCode
const erc) {
61 new (get_error_storage ()) std::error_code (make_error_code (erc));
64 explicit error_or (std::error_code
const erc) {
65 new (get_error_storage ()) std::error_code (erc);
68 template <
typename Other,
69 typename =
typename std::enable_if<std::is_convertible<Other, T>::value>::type>
72 new (get_storage ()) storage_type (std::forward<Other> (other));
75 template <
typename... Args>
76 explicit error_or (
in_place_t const inp, Args &&... args)
79 new (get_storage ()) storage_type (std::forward<Args> (args)...);
82 error_or (error_or
const & rhs) { copy_construct (rhs); }
84 template <
typename Other,
85 typename =
typename std::enable_if<std::is_convertible<Other, T>::value>::type>
91 error_or (error_or && rhs) noexcept { move_construct (std::move (rhs)); }
93 template <
typename Other,
94 typename =
typename std::enable_if<std::is_convertible<Other, T>::value>::type>
97 move_construct (std::move (rhs));
106 template <
typename ErrorCode,
107 typename =
typename std::enable_if<is_error<ErrorCode>::value>::type>
108 error_or & operator= (ErrorCode rhs) {
112 error_or & operator= (std::error_code
const & rhs) {
116 error_or & operator= (error_or
const & rhs) {
120 error_or & operator= (error_or && rhs) {
121 move_assign (std::move (rhs));
129 bool operator== (std::error_code
const rhs)
const {
return get_error () == rhs; }
130 bool operator== (error_or
const & rhs);
131 bool operator== (T
const & rhs)
const {
132 return static_cast<bool> (*this) && this->
get () == rhs;
134 template <
typename Error>
135 typename std::enable_if<is_error<Error>::value,
bool>::type operator== (Error rhs)
const {
136 return get_error () == rhs;
139 bool operator!= (T
const & rhs)
const {
return !operator== (rhs); }
140 bool operator!= (std::error_code
const rhs)
const {
return !operator== (rhs); }
141 bool operator!= (error_or
const & rhs) {
return !operator== (rhs); }
142 template <
typename Error>
143 typename std::enable_if<is_error<Error>::value,
bool>::type operator!= (Error rhs)
const {
144 return !operator== (rhs);
153 explicit operator bool () const noexcept {
return !has_error_; }
155 std::error_code get_error ()
const noexcept;
157 reference
get () noexcept {
return *get_storage (); }
158 const_reference
get ()
const noexcept {
return *get_storage (); }
159 pointer operator-> () noexcept {
return to_pointer (get_storage ()); }
160 const_pointer operator-> ()
const noexcept {
return to_pointer (get_storage ()); }
161 reference operator* () noexcept {
return *get_storage (); }
162 const_reference operator* ()
const noexcept {
return *get_storage (); }
165 template <
typename Other>
168 template <
typename T1>
169 static constexpr
bool same_object (T1
const & lhs, T1
const & rhs) noexcept {
173 template <
typename T1,
typename T2>
174 static constexpr
bool same_object (T1
const & lhs, T2
const & rhs) noexcept {
180 template <
typename Other>
183 template <
typename Other>
186 template <
typename Other>
189 pointer to_pointer (wrapper * PSTORE_NONNULL val) noexcept {
return &val->get (); }
192 const_pointer to_pointer (wrapper
const * PSTORE_NONNULL val)
const noexcept {
196 template <
typename ErrorOr,
198 static ResultType * PSTORE_NONNULL value_storage_impl (ErrorOr && e) noexcept {
199 PSTORE_ASSERT (!e.has_error_);
200 return reinterpret_cast<ResultType *
> (&e.storage_);
203 storage_type * PSTORE_NONNULL get_storage () noexcept {
return value_storage_impl (*
this); }
204 storage_type
const * PSTORE_NONNULL get_storage ()
const noexcept {
205 return value_storage_impl (*
this);
208 template <
typename ErrorOr,
210 static ResultType * PSTORE_NONNULL error_storage_impl (ErrorOr && e) noexcept {
211 PSTORE_ASSERT (e.has_error_);
212 return reinterpret_cast<ResultType *
> (&e.error_storage_);
214 std::error_code * PSTORE_NONNULL get_error_storage () noexcept;
215 std::error_code
const * PSTORE_NONNULL get_error_storage ()
const noexcept;
218 typename std::aligned_storage<sizeof (storage_type), alignof (storage_type)>::type
220 std::aligned_storage<sizeof (std::error_code), alignof (std::error_code)>::type
223 bool has_error_ =
true;
229 template <
typename T>
232 get_storage ()->~storage_type ();
234 using error_code = std::error_code;
235 get_error_storage ()->~error_code ();
241 template <
typename T>
242 template <
typename Other>
244 has_error_ = rhs.has_error_;
246 new (get_error_storage ()) std::error_code (rhs.get_error ());
248 new (get_storage ()) storage_type (*rhs.get_storage ());
254 template <
typename T>
255 template <
typename Other>
257 if (same_object (*
this, rhs)) {
261 if (has_error_ && rhs.has_error_) {
262 *get_error_storage () = *rhs.get_error_storage ();
263 }
else if (!has_error_ && !rhs.has_error_) {
264 *get_storage () = *rhs.get_storage ();
274 template <
typename T>
275 template <
typename Other>
277 has_error_ = rhs.has_error_;
279 new (get_error_storage ()) std::error_code (rhs.get_error ());
281 new (get_storage ()) storage_type (std::move (*rhs.get_storage ()));
287 template <
typename T>
288 template <
typename Other>
290 if (same_object (*
this, rhs)) {
294 if (has_error_ && rhs.has_error_) {
295 *get_error_storage () = std::move (*rhs.get_error_storage ());
296 }
else if (!has_error_ && !rhs.has_error_) {
297 *get_storage () = std::move (*rhs.get_storage ());
300 new (
this)
error_or (std::move (rhs));
307 template <
typename T>
309 if (has_error_ != rhs.has_error_) {
313 return this->operator== (rhs.get_error ());
315 return this->operator== (rhs.get ());
320 template <
typename T>
322 return has_error_ ? *get_error_storage () : std::error_code{};
327 template <
typename T>
329 return error_storage_impl (*
this);
331 template <
typename T>
333 return error_storage_impl (*
this);
345 template <
typename T,
typename Function>
346 auto operator>>= (
error_or<T> && t, Function f) -> decltype ((f (t.get ()))) {
350 return error_or<
typename decltype (f (t.get ()))::value_type> (t.get_error ());
354 template <
typename... Args>
359 template <std::size_t I,
class... Types>
360 typename std::tuple_element<I, std::tuple<Types...>>::type &
361 get (error_or_n<Types...> & eon) noexcept {
362 return std::get<I> (*eon);
365 template <std::size_t I,
class... Types>
366 typename std::tuple_element<I, std::tuple<Types...>>::type &&
367 get (error_or_n<Types...> && eon) noexcept {
368 return std::get<I> (*eon);
371 template <std::size_t I,
class... Types>
372 typename std::tuple_element<I, std::tuple<Types...>>::type
const &
373 get (error_or_n<Types...>
const & eon) noexcept {
374 return std::get<I> (*eon);
380 template <std::
size_t N>
382 template <
typename Function,
typename Tuple,
typename... Args>
383 static auto apply (Function && f, Tuple && t, Args &&... a)
385 std::forward<Tuple> (t),
386 std::get<N - 1U> (std::forward<Tuple> (t)),
387 std::forward<Args> (a)...)) {
390 std::get<N - 1U> (std::forward<Tuple> (t)),
391 std::forward<Args> (a)...);
397 template <
typename Function,
typename Tuple,
typename... Args>
398 static auto apply (Function && f, Tuple && t, Args &&... a)
399 -> decltype (std::forward<Function> (f) (std::forward<Args> (a)...)) {
401 return std::forward<Function> (f) (std::forward<Args> (a)...);
405 template <
typename Function,
typename Tuple>
406 inline auto apply (Function && f, Tuple && t)
407 -> decltype (
applier<std::tuple_size<
typename std::decay<Tuple>::type>::value>::apply (
408 std::forward<Function> (f), std::forward<Tuple> (t))) {
411 std::forward<Function> (f), std::forward<Tuple> (t));
417 template <
typename Function,
typename... Args>
419 -> decltype (details::apply (f, t.get ())) {
422 return details::apply (std::forward<Function> (f), t.get ());
424 return decltype (details::apply (f, t.get ())){t.get_error ()};
429 #endif // PSTORE_ADT_ERROR_OR_HPP Provides definitions needed by the code that are available in C++17 <utility>.
Definition: chunked_sequence.hpp:607
Definition: error_or.hpp:39
Definition: error_or.hpp:34
A utility template intended to simplify the writing of the const- and non-const variants of member fu...
Definition: utility.hpp:24
Definition: error_or.hpp:381
Definition: nonpod2.cpp:40
An implementation of the standard assert() macro with the exception that it will, on failure...
typename std::conditional< std::is_const< typename std::remove_reference< T >::type >::value, RC, R >::type type
If T is const, R const otherwise R.
Definition: inherit_const.hpp:112