123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
- #define BOOST_LEAF_RESULT_HPP_INCLUDED
- /// Copyright (c) 2018-2021 Emil Dotchevski and Reverge Studios, Inc.
- /// Distributed under the Boost Software License, Version 1.0. (See accompanying
- /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_LEAF_ENABLE_WARNINGS ///
- # if defined(_MSC_VER) ///
- # pragma warning(push,1) ///
- # elif defined(__clang__) ///
- # pragma clang system_header ///
- # elif (__GNUC__*100+__GNUC_MINOR__>301) ///
- # pragma GCC system_header ///
- # endif ///
- #endif ///
- #include <boost/leaf/error.hpp>
- #include <climits>
- namespace boost { namespace leaf {
- class bad_result:
- public std::exception,
- public error_id
- {
- char const * what() const noexcept final override
- {
- return "boost::leaf::bad_result";
- }
- public:
- explicit bad_result( error_id id ) noexcept:
- error_id(id)
- {
- BOOST_LEAF_ASSERT(value());
- }
- };
- ////////////////////////////////////////
- namespace leaf_detail
- {
- template <class T>
- struct stored
- {
- using type = T;
- using value_type = T;
- using value_type_const = T const;
- using value_cref = T const &;
- using value_ref = T &;
- using value_rv_cref = T const &&;
- using value_rv_ref = T &&;
- };
- template <class T>
- struct stored<T &>
- {
- using type = std::reference_wrapper<T>;
- using value_type_const = T;
- using value_type = T;
- using value_ref = T &;
- using value_cref = T &;
- using value_rv_ref = T &;
- using value_rv_cref = T &;
- };
- class result_discriminant
- {
- unsigned state_;
- public:
- enum kind_t
- {
- no_error = 0,
- err_id = 1,
- ctx_ptr = 2,
- val = 3
- };
- explicit result_discriminant( error_id id ) noexcept:
- state_(id.value())
- {
- BOOST_LEAF_ASSERT(state_==0 || (state_&3)==1);
- }
- struct kind_val { };
- explicit result_discriminant( kind_val ) noexcept:
- state_(val)
- {
- }
- struct kind_ctx_ptr { };
- explicit result_discriminant( kind_ctx_ptr ) noexcept:
- state_(ctx_ptr)
- {
- }
- kind_t kind() const noexcept
- {
- return kind_t(state_&3);
- }
- error_id get_error_id() const noexcept
- {
- BOOST_LEAF_ASSERT(kind()==no_error || kind()==err_id);
- return make_error_id(state_);
- }
- };
- }
- ////////////////////////////////////////
- template <class T>
- class result
- {
- template <class U>
- friend class result;
- using result_discriminant = leaf_detail::result_discriminant;
- struct error_result
- {
- error_result( error_result && ) = default;
- error_result( error_result const & ) = delete;
- error_result & operator=( error_result const & ) = delete;
- result & r_;
- error_result( result & r ) noexcept:
- r_(r)
- {
- }
- template <class U>
- operator result<U>() noexcept
- {
- switch(r_.what_.kind())
- {
- case result_discriminant::val:
- return result<U>(error_id());
- case result_discriminant::ctx_ptr:
- return result<U>(std::move(r_.ctx_));
- default:
- return result<U>(std::move(r_.what_));
- }
- }
- operator error_id() noexcept
- {
- switch(r_.what_.kind())
- {
- case result_discriminant::val:
- return error_id();
- case result_discriminant::ctx_ptr:
- {
- error_id captured_id = r_.ctx_->propagate_captured_errors();
- leaf_detail::id_factory<>::current_id = captured_id.value();
- return captured_id;
- }
- default:
- return r_.what_.get_error_id();
- }
- }
- };
- using stored_type = typename leaf_detail::stored<T>::type;
- using value_type = typename leaf_detail::stored<T>::value_type;
- using value_type_const = typename leaf_detail::stored<T>::value_type_const;
- using value_ref = typename leaf_detail::stored<T>::value_ref;
- using value_cref = typename leaf_detail::stored<T>::value_cref;
- using value_rv_ref = typename leaf_detail::stored<T>::value_rv_ref;
- using value_rv_cref = typename leaf_detail::stored<T>::value_rv_cref;
- union
- {
- stored_type stored_;
- context_ptr ctx_;
- };
- result_discriminant what_;
- void destroy() const noexcept
- {
- switch(this->what_.kind())
- {
- case result_discriminant::val:
- stored_.~stored_type();
- break;
- case result_discriminant::ctx_ptr:
- BOOST_LEAF_ASSERT(!ctx_ || ctx_->captured_id_);
- ctx_.~context_ptr();
- default:
- break;
- }
- }
- template <class U>
- result_discriminant move_from( result<U> && x ) noexcept
- {
- auto x_what = x.what_;
- switch(x_what.kind())
- {
- case result_discriminant::val:
- (void) new(&stored_) stored_type(std::move(x.stored_));
- break;
- case result_discriminant::ctx_ptr:
- BOOST_LEAF_ASSERT(!x.ctx_ || x.ctx_->captured_id_);
- (void) new(&ctx_) context_ptr(std::move(x.ctx_));
- default:
- break;
- }
- return x_what;
- }
- result( result_discriminant && what ) noexcept:
- what_(std::move(what))
- {
- BOOST_LEAF_ASSERT(what_.kind()==result_discriminant::err_id || what_.kind()==result_discriminant::no_error);
- }
- error_id get_error_id() const noexcept
- {
- BOOST_LEAF_ASSERT(what_.kind()!=result_discriminant::val);
- return what_.kind()==result_discriminant::ctx_ptr ? ctx_->captured_id_ : what_.get_error_id();
- }
- static int init_T_with_U( T && );
- protected:
- void enforce_value_state() const
- {
- if( what_.kind() != result_discriminant::val )
- ::boost::leaf::throw_exception(bad_result(get_error_id()));
- }
- public:
- result( result && x ) noexcept:
- what_(move_from(std::move(x)))
- {
- }
- template <class U>
- result( result<U> && x ) noexcept:
- what_(move_from(std::move(x)))
- {
- }
- result():
- stored_(stored_type()),
- what_(result_discriminant::kind_val{})
- {
- }
- result( value_type && v ) noexcept:
- stored_(std::forward<value_type>(v)),
- what_(result_discriminant::kind_val{})
- {
- }
- result( value_type const & v ):
- stored_(v),
- what_(result_discriminant::kind_val{})
- {
- }
- result( error_id err ) noexcept:
- what_(err)
- {
- }
- // SFINAE:
- // T can be initialized with a U, e.g. result<std::string>("literal").
- // Not using is_constructible on purpose, bug with
- // COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
- template <class U>
- result( U && u, decltype(init_T_with_U(std::forward<U>(u))) * = 0 ):
- stored_(std::forward<U>(u)),
- what_(result_discriminant::kind_val{})
- {
- }
- result( std::error_code const & ec ) noexcept:
- what_(error_id(ec))
- {
- }
- template <class Enum>
- result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type * = 0 ) noexcept:
- what_(error_id(e))
- {
- }
- result( context_ptr && ctx ) noexcept:
- ctx_(std::move(ctx)),
- what_(result_discriminant::kind_ctx_ptr{})
- {
- }
- ~result() noexcept
- {
- destroy();
- }
- result & operator=( result && x ) noexcept
- {
- destroy();
- what_ = move_from(std::move(x));
- return *this;
- }
- template <class U>
- result & operator=( result<U> && x ) noexcept
- {
- destroy();
- what_ = move_from(std::move(x));
- return *this;
- }
- explicit operator bool() const noexcept
- {
- return what_.kind() == result_discriminant::val;
- }
- value_cref value() const &
- {
- enforce_value_state();
- return stored_;
- }
- value_ref value() &
- {
- enforce_value_state();
- return stored_;
- }
- value_rv_cref value() const &&
- {
- enforce_value_state();
- return std::move(stored_);
- }
- value_rv_ref value() &&
- {
- enforce_value_state();
- return std::move(stored_);
- }
- value_cref operator*() const &
- {
- return value();
- }
- value_ref operator*() &
- {
- return value();
- }
- value_rv_cref operator*() const &&
- {
- return value();
- }
- value_rv_ref operator*() &&
- {
- return value();
- }
- value_type_const * operator->() const
- {
- return &value();
- }
- value_type * operator->()
- {
- return &value();
- }
- error_result error() noexcept
- {
- return error_result{*this};
- }
- template <class... Item>
- error_id load( Item && ... item ) noexcept
- {
- return error_id(error()).load(std::forward<Item>(item)...);
- }
- };
- ////////////////////////////////////////
- namespace leaf_detail
- {
- struct void_ { };
- }
- template <>
- class result<void>:
- result<leaf_detail::void_>
- {
- using result_discriminant = leaf_detail::result_discriminant;
- using void_ = leaf_detail::void_;
- using base = result<void_>;
- template <class U>
- friend class result;
- result( result_discriminant && what ) noexcept:
- base(std::move(what))
- {
- }
- public:
- using value_type = void;
- result( result && x ) noexcept:
- base(std::move(x))
- {
- }
- result() noexcept
- {
- }
- result( error_id err ) noexcept:
- base(err)
- {
- }
- result( std::error_code const & ec ) noexcept:
- base(ec)
- {
- }
- template <class Enum>
- result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, Enum>::type * = 0 ) noexcept:
- base(e)
- {
- }
- result( context_ptr && ctx ) noexcept:
- base(std::move(ctx))
- {
- }
- ~result() noexcept
- {
- }
- void value() const
- {
- base::enforce_value_state();
- }
- using base::operator=;
- using base::operator bool;
- using base::get_error_id;
- using base::error;
- using base::load;
- };
- ////////////////////////////////////////
- template <class R>
- struct is_result_type;
- template <class T>
- struct is_result_type<result<T>>: std::true_type
- {
- };
- } }
- #if defined(_MSC_VER) && !defined(BOOST_LEAF_ENABLE_WARNINGS) ///
- #pragma warning(pop) ///
- #endif ///
- #endif
|