1 #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
2 #define BOOST_LEAF_RESULT_HPP_INCLUDED
4 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc.
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 #ifndef BOOST_LEAF_ENABLE_WARNINGS
10 # if defined(__clang__)
11 # pragma clang system_header
12 # elif (__GNUC__*100+__GNUC_MINOR__>301)
13 # pragma GCC system_header
14 # elif defined(_MSC_VER)
15 # pragma warning(push,1)
19 #include <boost/leaf/error.hpp>
22 namespace boost { namespace leaf {
25 public std::exception,
28 char const * what() const noexcept final override
30 return "boost::leaf::bad_result";
35 explicit bad_result( error_id id ) noexcept:
38 BOOST_LEAF_ASSERT(value());
42 ////////////////////////////////////////
51 using value_type_const = T const;
52 using value_cref = T const &;
53 using value_ref = T &;
54 using value_rv_cref = T const &&;
55 using value_rv_ref = T &&;
61 using type = std::reference_wrapper<T>;
62 using value_type_const = T;
64 using value_ref = T &;
65 using value_cref = T &;
66 using value_rv_ref = T &;
67 using value_rv_cref = T &;
70 class result_discriminant
84 explicit result_discriminant( error_id id ) noexcept:
87 BOOST_LEAF_ASSERT(state_==0 || (state_&3)==1);
91 explicit result_discriminant( kind_val ) noexcept:
96 struct kind_ctx_ptr { };
97 explicit result_discriminant( kind_ctx_ptr ) noexcept:
102 kind_t kind() const noexcept
104 return kind_t(state_&3);
107 error_id get_error_id() const noexcept
109 BOOST_LEAF_ASSERT(kind()==no_error || kind()==err_id);
110 return make_error_id(state_);
115 ////////////////////////////////////////
123 using result_discriminant = leaf_detail::result_discriminant;
127 error_result( error_result && ) = default;
128 error_result( error_result const & ) = delete;
129 error_result & operator=( error_result const & ) = delete;
133 error_result( result & r ) noexcept:
139 operator result<U>() noexcept
141 switch(r_.what_.kind())
143 case result_discriminant::val:
144 return result<U>(error_id());
145 case result_discriminant::ctx_ptr:
146 return result<U>(std::move(r_.ctx_));
148 return result<U>(std::move(r_.what_));
152 operator error_id() noexcept
154 switch(r_.what_.kind())
156 case result_discriminant::val:
158 case result_discriminant::ctx_ptr:
160 error_id captured_id = r_.ctx_->propagate_captured_errors();
161 leaf_detail::id_factory<>::current_id = captured_id.value();
165 return r_.what_.get_error_id();
170 using stored_type = typename leaf_detail::stored<T>::type;
171 using value_type = typename leaf_detail::stored<T>::value_type;
172 using value_type_const = typename leaf_detail::stored<T>::value_type_const;
173 using value_ref = typename leaf_detail::stored<T>::value_ref;
174 using value_cref = typename leaf_detail::stored<T>::value_cref;
175 using value_rv_ref = typename leaf_detail::stored<T>::value_rv_ref;
176 using value_rv_cref = typename leaf_detail::stored<T>::value_rv_cref;
184 result_discriminant what_;
186 void destroy() const noexcept
188 switch(this->what_.kind())
190 case result_discriminant::val:
191 stored_.~stored_type();
193 case result_discriminant::ctx_ptr:
194 BOOST_LEAF_ASSERT(!ctx_ || ctx_->captured_id_);
202 result_discriminant move_from( result<U> && x ) noexcept
204 auto x_what = x.what_;
205 switch(x_what.kind())
207 case result_discriminant::val:
208 (void) new(&stored_) stored_type(std::move(x.stored_));
210 case result_discriminant::ctx_ptr:
211 BOOST_LEAF_ASSERT(!x.ctx_ || x.ctx_->captured_id_);
212 (void) new(&ctx_) context_ptr(std::move(x.ctx_));
219 result( result_discriminant && what ) noexcept:
220 what_(std::move(what))
222 BOOST_LEAF_ASSERT(what_.kind()==result_discriminant::err_id || what_.kind()==result_discriminant::no_error);
225 error_id get_error_id() const noexcept
227 BOOST_LEAF_ASSERT(what_.kind()!=result_discriminant::val);
228 return what_.kind()==result_discriminant::ctx_ptr ? ctx_->captured_id_ : what_.get_error_id();
231 static int init_T_with_U( T && );
235 void enforce_value_state() const
237 if( what_.kind() != result_discriminant::val )
238 ::boost::leaf::throw_exception(bad_result(get_error_id()));
243 result( result && x ) noexcept:
244 what_(move_from(std::move(x)))
249 result( result<U> && x ) noexcept:
250 what_(move_from(std::move(x)))
256 stored_(stored_type()),
257 what_(result_discriminant::kind_val{})
261 result( value_type && v ) noexcept:
262 stored_(std::forward<value_type>(v)),
263 what_(result_discriminant::kind_val{})
267 result( value_type const & v ):
269 what_(result_discriminant::kind_val{})
273 result( error_id err ) noexcept:
278 // SFINAE: T can be initialized with a U, e.g. result<std::string>("literal").
279 // Not using is_constructible on purpose, bug with COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
281 result( U && u, decltype(init_T_with_U(std::forward<U>(u))) * = 0 ):
282 stored_(std::forward<U>(u)),
283 what_(result_discriminant::kind_val{})
287 result( std::error_code const & ec ) noexcept:
292 template <class Enum>
293 result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type * = 0 ) noexcept:
298 result( context_ptr && ctx ) noexcept:
299 ctx_(std::move(ctx)),
300 what_(result_discriminant::kind_ctx_ptr{})
309 result & operator=( result && x ) noexcept
312 what_ = move_from(std::move(x));
317 result & operator=( result<U> && x ) noexcept
320 what_ = move_from(std::move(x));
324 explicit operator bool() const noexcept
326 return what_.kind() == result_discriminant::val;
329 value_cref value() const &
331 enforce_value_state();
337 enforce_value_state();
341 value_rv_cref value() const &&
343 enforce_value_state();
344 return std::move(stored_);
347 value_rv_ref value() &&
349 enforce_value_state();
350 return std::move(stored_);
353 value_cref operator*() const &
358 value_ref operator*() &
363 value_rv_cref operator*() const &&
368 value_rv_ref operator*() &&
373 value_type_const * operator->() const
378 value_type * operator->()
383 error_result error() noexcept
385 return error_result{*this};
388 template <class... Item>
389 error_id load( Item && ... item ) noexcept
391 return error_id(error()).load(std::forward<Item>(item)...);
395 ////////////////////////////////////////
397 namespace leaf_detail
404 result<leaf_detail::void_>
406 using result_discriminant = leaf_detail::result_discriminant;
407 using void_ = leaf_detail::void_;
408 using base = result<void_>;
413 result( result_discriminant && what ) noexcept:
414 base(std::move(what))
420 using value_type = void;
422 result( result && x ) noexcept:
431 result( error_id err ) noexcept:
436 result( std::error_code const & ec ) noexcept:
441 template <class Enum>
442 result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, Enum>::type * = 0 ) noexcept:
447 result( context_ptr && ctx ) noexcept:
458 base::enforce_value_state();
461 using base::operator=;
462 using base::operator bool;
463 using base::get_error_id;
468 ////////////////////////////////////////
471 struct is_result_type;
474 struct is_result_type<result<T>>: std::true_type