123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741 |
- #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
- #define BOOST_LEAF_RESULT_HPP_INCLUDED
- // Copyright 2018-2023 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)
- #include <boost/leaf/config.hpp>
- #include <boost/leaf/detail/print.hpp>
- #include <boost/leaf/detail/capture_list.hpp>
- #include <boost/leaf/exception.hpp>
- #include <climits>
- #include <functional>
- namespace boost { namespace leaf {
- namespace leaf_detail { class dynamic_allocator; }
- ////////////////////////////////////////
- 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, bool Printable = is_printable<T>::value>
- struct result_value_printer;
- template <class T>
- struct result_value_printer<T, true>
- {
- template <class CharT, class Traits>
- static void print( std::basic_ostream<CharT, Traits> & s, T const & x )
- {
- (void) (s << x);
- }
- };
- template <class T>
- struct result_value_printer<T, false>
- {
- template <class CharT, class Traits>
- static void print( std::basic_ostream<CharT, Traits> & s, T const & )
- {
- (void) (s << "{not printable}");
- }
- };
- template <class CharT, class Traits, class T>
- void print_result_value( std::basic_ostream<CharT, Traits> & s, T const & x )
- {
- result_value_printer<T>::print(s, x);
- }
- }
- ////////////////////////////////////////
- namespace leaf_detail
- {
- template <class T>
- struct stored
- {
- using type = T;
- using value_no_ref = T;
- using value_no_ref_const = T const;
- using value_cref = T const &;
- using value_ref = T &;
- using value_rv_cref = T const &&;
- using value_rv_ref = T &&;
- static value_no_ref_const * cptr( type const & v ) noexcept
- {
- return &v;
- }
- static value_no_ref * ptr( type & v ) noexcept
- {
- return &v;
- }
- };
- template <class T>
- struct stored<T &>
- {
- using type = std::reference_wrapper<T>;
- using value_no_ref = T;
- using value_no_ref_const = T;
- using value_ref = T &;
- using value_cref = T &;
- using value_rv_ref = T &;
- using value_rv_cref = T &;
- static value_no_ref_const * cptr( type const & v ) noexcept
- {
- return &v.get();
- }
- static value_no_ref * ptr( type const & v ) noexcept
- {
- return &v.get();
- }
- };
- class result_discriminant
- {
- int state_;
- public:
- enum kind_t
- {
- err_id_zero = 0,
- err_id = 1,
- err_id_capture_list = 2,
- val = 3
- };
- explicit result_discriminant( error_id id ) noexcept:
- state_(id.value())
- {
- BOOST_LEAF_ASSERT(state_ == 0 || (state_&3) == 1);
- BOOST_LEAF_ASSERT(kind()==err_id_zero || kind()==err_id);
- }
- #if BOOST_LEAF_CFG_CAPTURE
- explicit result_discriminant( int err_id, leaf_detail::capture_list const & ) noexcept:
- state_((err_id&~3) | 2)
- {
- BOOST_LEAF_ASSERT((err_id&3) == 1);
- BOOST_LEAF_ASSERT(kind() == err_id_capture_list);
- }
- #endif
- struct kind_val { };
- explicit result_discriminant( kind_val ) noexcept:
- state_(val)
- {
- BOOST_LEAF_ASSERT((state_&3) == 3);
- BOOST_LEAF_ASSERT(kind()==val);
- }
- kind_t kind() const noexcept
- {
- return kind_t(state_&3);
- }
- error_id get_error_id() const noexcept
- {
- BOOST_LEAF_ASSERT(kind()==err_id_zero || kind()==err_id || kind()==err_id_capture_list);
- return make_error_id(int((state_&~3)|1));
- }
- };
- }
- ////////////////////////////////////////
- template <class T>
- class BOOST_LEAF_SYMBOL_VISIBLE result
- {
- template <class U>
- friend class result;
- friend class leaf_detail::dynamic_allocator;
- #if BOOST_LEAF_CFG_CAPTURE
- using capture_list = leaf_detail::capture_list;
- #endif
- using result_discriminant = leaf_detail::result_discriminant;
- using stored_type = typename leaf_detail::stored<T>::type;
- using value_no_ref = typename leaf_detail::stored<T>::value_no_ref;
- using value_no_ref_const = typename leaf_detail::stored<T>::value_no_ref_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_;
- #if BOOST_LEAF_CFG_CAPTURE
- mutable capture_list cap_;
- #endif
- };
- result_discriminant what_;
- 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
- {
- result_discriminant const what = r_.what_;
- switch( what.kind() )
- {
- case result_discriminant::val:
- return result<U>(error_id());
- case result_discriminant::err_id_capture_list:
- #if BOOST_LEAF_CFG_CAPTURE
- return result<U>(what.get_error_id().value(), std::move(r_.cap_));
- #else
- BOOST_LEAF_ASSERT(0); // Possible ODR violation.
- #endif
- case result_discriminant::err_id_zero:
- case result_discriminant::err_id:
- return result<U>(what.get_error_id());
- }
- }
- operator error_id() noexcept
- {
- result_discriminant const what = r_.what_;
- return what.kind() == result_discriminant::val? error_id() : what.get_error_id();
- }
- };
- void destroy() const noexcept
- {
- switch(this->what_.kind())
- {
- case result_discriminant::err_id_zero:
- case result_discriminant::err_id:
- break;
- case result_discriminant::err_id_capture_list:
- #if BOOST_LEAF_CFG_CAPTURE
- cap_.~capture_list();
- #else
- BOOST_LEAF_ASSERT(0); // Possible ODR violation.
- #endif
- break;
- case result_discriminant::val:
- stored_.~stored_type();
- }
- }
- template <class U>
- result_discriminant move_from( result<U> && x ) noexcept
- {
- auto x_what = x.what_;
- switch(x_what.kind())
- {
- case result_discriminant::err_id_zero:
- case result_discriminant::err_id:
- break;
- case result_discriminant::err_id_capture_list:
- #if BOOST_LEAF_CFG_CAPTURE
- (void) new(&cap_) capture_list(std::move(x.cap_));
- #else
- BOOST_LEAF_ASSERT(0); // Possible ODR violation.
- #endif
- break;
- case result_discriminant::val:
- (void) new(&stored_) stored_type(std::move(x.stored_));
- }
- return x_what;
- }
- error_id get_error_id() const noexcept
- {
- BOOST_LEAF_ASSERT(what_.kind() != result_discriminant::val);
- return what_.get_error_id();
- }
- stored_type const * get() const noexcept
- {
- return has_value() ? &stored_ : nullptr;
- }
- stored_type * get() noexcept
- {
- return has_value() ? &stored_ : nullptr;
- }
- protected:
- #if BOOST_LEAF_CFG_CAPTURE
- result( int err_id, leaf_detail::capture_list && cap ) noexcept:
- cap_(std::move(cap)),
- what_(err_id, cap)
- {
- }
- #endif
- void enforce_value_state() const
- {
- switch( what_.kind() )
- {
- case result_discriminant::err_id_capture_list:
- #if BOOST_LEAF_CFG_CAPTURE
- cap_.unload(what_.get_error_id().value());
- #else
- BOOST_LEAF_ASSERT(0); // Possible ODR violation.
- #endif
- case result_discriminant::err_id_zero:
- case result_discriminant::err_id:
- ::boost::leaf::leaf_detail::throw_exception_impl(bad_result(get_error_id()));
- case result_discriminant::val:
- break;
- }
- }
- template <class U>
- void move_assign( result<U> && x ) noexcept
- {
- destroy();
- what_ = move_from(std::move(x));
- }
- public:
- using value_type = T;
- // NOTE: Copy constructor implicitly deleted.
- result( result && x ) noexcept:
- what_(move_from(std::move(x)))
- {
- }
- template <class U, class = typename std::enable_if<std::is_convertible<U, T>::value>::type>
- result( result<U> && x ) noexcept:
- what_(move_from(std::move(x)))
- {
- }
- result():
- stored_(stored_type()),
- what_(result_discriminant::kind_val{})
- {
- }
- result( value_no_ref && v ) noexcept:
- stored_(std::forward<value_no_ref>(v)),
- what_(result_discriminant::kind_val{})
- {
- }
- result( value_no_ref const & v ):
- stored_(v),
- what_(result_discriminant::kind_val{})
- {
- }
- template<class... A, class = typename std::enable_if<std::is_constructible<T, A...>::value && sizeof...(A) >= 2>::type>
- result( A && ... a ) noexcept:
- stored_(std::forward<A>(a)...),
- what_(result_discriminant::kind_val{})
- {
- }
- result( error_id err ) noexcept:
- what_(err)
- {
- }
- #if defined(BOOST_STRICT_CONFIG) || !defined(__clang__)
- // This should be the default implementation, but std::is_convertible
- // breaks under COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
- // On the other hand, the workaround exposes a rather severe bug in
- //__GNUC__ under 11: https://github.com/boostorg/leaf/issues/25.
- // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
- template<class A, class = typename std::enable_if<std::is_constructible<T, A>::value && std::is_convertible<A, T>::value>::type>
- result( A && a ) noexcept:
- stored_(std::forward<A>(a)),
- what_(result_discriminant::kind_val{})
- {
- }
- #else
- private:
- static int init_T_with_A( T && );
- public:
- // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
- template <class A>
- result( A && a, decltype(init_T_with_A(std::forward<A>(a))) * = nullptr ):
- stored_(std::forward<A>(a)),
- what_(result_discriminant::kind_val{})
- {
- }
- #endif
- #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
- result( std::error_code const & ec ) noexcept:
- what_(error_id(ec))
- {
- }
- template <class Enum, class = typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type>
- result( Enum e ) noexcept:
- what_(error_id(e))
- {
- }
- #endif
- ~result() noexcept
- {
- destroy();
- }
- // NOTE: Assignment operator implicitly deleted.
- result & operator=( result && x ) noexcept
- {
- move_assign(std::move(x));
- return *this;
- }
- template <class U, class = typename std::enable_if<std::is_convertible<U, T>::value>::type>
- result & operator=( result<U> && x ) noexcept
- {
- move_assign(std::move(x));
- return *this;
- }
- bool has_value() const noexcept
- {
- return what_.kind() == result_discriminant::val;
- }
- bool has_error() const noexcept
- {
- return !has_value();
- }
- explicit operator bool() const noexcept
- {
- return has_value();
- }
- #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
- value_cref value() const
- {
- enforce_value_state();
- return stored_;
- }
- value_ref value()
- {
- enforce_value_state();
- return stored_;
- }
- #else
- 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_);
- }
- #endif
- value_no_ref_const * operator->() const noexcept
- {
- return has_value() ? leaf_detail::stored<T>::cptr(stored_) : nullptr;
- }
- value_no_ref * operator->() noexcept
- {
- return has_value() ? leaf_detail::stored<T>::ptr(stored_) : nullptr;
- }
- #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
- value_cref operator*() const noexcept
- {
- auto p = get();
- BOOST_LEAF_ASSERT(p != nullptr);
- return *p;
- }
- value_ref operator*() noexcept
- {
- auto p = get();
- BOOST_LEAF_ASSERT(p != nullptr);
- return *p;
- }
- #else
- value_cref operator*() const & noexcept
- {
- auto p = get();
- BOOST_LEAF_ASSERT(p != nullptr);
- return *p;
- }
- value_ref operator*() & noexcept
- {
- auto p = get();
- BOOST_LEAF_ASSERT(p != nullptr);
- return *p;
- }
- value_rv_cref operator*() const && noexcept
- {
- auto p = get();
- BOOST_LEAF_ASSERT(p != nullptr);
- return std::move(*p);
- }
- value_rv_ref operator*() && noexcept
- {
- auto p = get();
- BOOST_LEAF_ASSERT(p != nullptr);
- return std::move(*p);
- }
- #endif
- 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)...);
- }
- void unload()
- {
- #if BOOST_LEAF_CFG_CAPTURE
- if( what_.kind() == result_discriminant::err_id_capture_list )
- cap_.unload(what_.get_error_id().value());
- #endif
- }
- template <class CharT, class Traits>
- void print( std::basic_ostream<CharT, Traits> & os ) const
- {
- result_discriminant const what = what_;
- if( what.kind() == result_discriminant::val )
- leaf_detail::print_result_value(os, value());
- else
- {
- error_id const err_id = what.get_error_id();
- os << "Error ID " << err_id;
- if( what.kind() == result_discriminant::err_id_capture_list )
- {
- #if BOOST_LEAF_CFG_CAPTURE
- # if BOOST_LEAF_CFG_DIAGNOSTICS
- cap_.print(os, ". Captured error objects:\n", err_id.value());
- # endif
- #else
- BOOST_LEAF_ASSERT(0); // Possible ODR violation.
- #endif
- }
- }
- }
- template <class CharT, class Traits>
- friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, result const & r )
- {
- r.print(os);
- return os;
- }
- };
- ////////////////////////////////////////
- namespace leaf_detail
- {
- struct void_ { };
- }
- template <>
- class BOOST_LEAF_SYMBOL_VISIBLE result<void>:
- result<leaf_detail::void_>
- {
- template <class U>
- friend class result;
- friend class leaf_detail::dynamic_allocator;
- using result_discriminant = leaf_detail::result_discriminant;
- using void_ = leaf_detail::void_;
- using base = result<void_>;
- #if BOOST_LEAF_CFG_CAPTURE
- result( int err_id, leaf_detail::capture_list && cap ) noexcept:
- base(err_id, std::move(cap))
- {
- }
- #endif
- public:
- using value_type = void;
- // NOTE: Copy constructor implicitly deleted.
- result( result && x ) noexcept:
- base(std::move(x))
- {
- }
- result() noexcept
- {
- }
- result( error_id err ) noexcept:
- base(err)
- {
- }
- #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
- result( std::error_code const & ec ) noexcept:
- base(ec)
- {
- }
- template <class Enum, class = typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type>
- result( Enum e ) noexcept:
- base(e)
- {
- }
- #endif
- ~result() noexcept
- {
- }
- // NOTE: Assignment operator implicitly deleted.
- result & operator=( result && x ) noexcept
- {
- base::move_assign(std::move(x));
- return *this;
- }
- void value() const
- {
- base::enforce_value_state();
- }
- void const * operator->() const noexcept
- {
- return base::operator->();
- }
- void * operator->() noexcept
- {
- return base::operator->();
- }
- void operator*() const noexcept
- {
- BOOST_LEAF_ASSERT(has_value());
- }
- template <class CharT, class Traits>
- void print( std::basic_ostream<CharT, Traits> & os ) const
- {
- if( what_.kind() == result_discriminant::val )
- os << "No error";
- else
- os << *static_cast<base const *>(this);
- }
- template <class CharT, class Traits>
- friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, result const & r )
- {
- r.print(os);
- return os;
- }
- using base::operator=;
- using base::operator bool;
- using base::get_error_id;
- using base::error;
- using base::load;
- using base::unload;
- };
- ////////////////////////////////////////
- template <class R>
- struct is_result_type;
- template <class T>
- struct is_result_type<result<T>>: std::true_type
- {
- };
- } }
- #endif
|