diff --git a/include/boost/leaf/capture_exception.hpp b/include/boost/leaf/capture_exception.hpp index 00b7b92..a243722 100644 --- a/include/boost/leaf/capture_exception.hpp +++ b/include/boost/leaf/capture_exception.hpp @@ -110,7 +110,7 @@ namespace boost { namespace leaf { { throw; } - catch( error_id const & id ) + catch( error_id id ) { throw_exception(captured_exception_impl( std::current_exception(), std::make_shared>(id,std::move(ss)), true, &print_types::print )); } diff --git a/include/boost/leaf/detail/dynamic_store.hpp b/include/boost/leaf/detail/dynamic_store.hpp index f3b7bfd..3b64a7f 100644 --- a/include/boost/leaf/detail/dynamic_store.hpp +++ b/include/boost/leaf/detail/dynamic_store.hpp @@ -29,9 +29,9 @@ namespace boost { namespace leaf { public: - virtual error_id const & error() const noexcept = 0; + virtual error_id error() const noexcept = 0; virtual error_id unload() noexcept = 0; - virtual error_id unload( error_id const & ) noexcept = 0; + virtual error_id unload( error_id ) noexcept = 0; }; } diff --git a/include/boost/leaf/detail/dynamic_store_impl.hpp b/include/boost/leaf/detail/dynamic_store_impl.hpp index 86bf29f..c57bf44 100644 --- a/include/boost/leaf/detail/dynamic_store_impl.hpp +++ b/include/boost/leaf/detail/dynamic_store_impl.hpp @@ -19,7 +19,7 @@ namespace boost { namespace leaf { template struct tuple_for_each { - static void unload( error_id const & id, Tuple && tup ) noexcept + static void unload( error_id id, Tuple && tup ) noexcept { tuple_for_each::unload(id,std::move(tup)); auto && opt = std::get(std::move(tup)); @@ -52,7 +52,7 @@ namespace boost { namespace leaf { error_id id_; std::tuple...> s_; - error_id const & error() const noexcept + error_id error() const noexcept { return id_; } @@ -62,7 +62,7 @@ namespace boost { namespace leaf { return unload(id_); } - error_id unload( error_id const & id ) noexcept + error_id unload( error_id id ) noexcept { dynamic_store_internal::tuple_for_each::unload(id,std::move(s_)); return id; @@ -70,7 +70,7 @@ namespace boost { namespace leaf { public: - dynamic_store_impl( error_id const & id, static_store && ss ) noexcept: + dynamic_store_impl( error_id id, static_store && ss ) noexcept: id_(id), s_(std::make_tuple( std::get,decltype(ss.s_)>::value>(std::move(ss.s_)).extract_optional(id)... )) { diff --git a/include/boost/leaf/detail/static_store.1.hpp b/include/boost/leaf/detail/static_store.1.hpp new file mode 100644 index 0000000..4d5131b --- /dev/null +++ b/include/boost/leaf/detail/static_store.1.hpp @@ -0,0 +1,548 @@ +#ifndef BOOST_LEAF_AFBBD676B2FF11E8984C7976AE35F1A2 +#define BOOST_LEAF_AFBBD676B2FF11E8984C7976AE35F1A2 + +// Copyright (c) 2018 Emil Dotchevski +// Copyright (c) 2018 Second Spectrum, 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 +#include +#include +#include + +namespace boost { namespace leaf { + + namespace leaf_detail + { + template ::value> + struct match_type; + + template + struct match_type + { + using type = decltype(E::value); + + static type const & get( E const & e ) noexcept + { + return e.value; + } + }; + + template + struct match_type + { + using type = E; + + static type const & get( E const & e ) noexcept + { + return e; + } + }; + + template + bool check_value_pack( T const & x, T const & v ) noexcept + { + return x==v; + } + + template + bool check_value_pack( T const & x, T const & v1, VRest const & ... v_rest ) noexcept + { + return x==v1 || check_value_pack(x,v_rest...); + } + + template + bool check_exception_pack( std::exception const * ex, Ex const * ) noexcept + { + return dynamic_cast(ex)!=0; + } + + template + bool check_exception_pack( std::exception const * ex, Ex const *, ExRest const * ... ex_rest ) noexcept + { + return dynamic_cast(ex)!=0 || check_exception_pack(ex, ex_rest...); + } + } + + template ::type... V> + struct match + { + using type = typename leaf_detail::match_type::type; + type const & value; + + explicit match( E const & e ): + value(leaf_detail::match_type::get(e)) + { + } + + bool operator()() const noexcept + { + return leaf_detail::check_value_pack(value,V...); + } + }; + + template + struct catch_ + { + std::exception const & value; + + explicit catch_( std::exception const & ex ): + value(ex) + { + } + + bool operator()() const noexcept + { + return leaf_detail::check_exception_pack(&value,static_cast(0)...); + } + }; + + template + struct returned + { + R value; + }; + + namespace leaf_detail + { + namespace static_store_internal + { + template + struct tuple_for_each + { + static void reset( Tuple & tup ) noexcept + { + tuple_for_each::reset(tup); + std::get(tup).reset(); + } + }; + + template + struct tuple_for_each<0, Tuple> + { + static void reset( Tuple & ) noexcept { } + }; + + //////////////////////////////////////// + + class enable_any + { + protected: + + enable_any() noexcept + { + ++tl_unexpected_enabled_counter(); + } + + ~enable_any() noexcept + { + --tl_unexpected_enabled_counter(); + } + }; + + template + class static_store_slot: + public slot + { + public: + optional extract_optional( error_id id ) && noexcept + { + slot const & s = *this; + if( s.has_value() && s.value().id==id ) + return optional(std::move(*this).value().e); + else + return optional(); + } + }; + + template <> + class static_store_slot: + public slot, + enable_any + { + }; + + template <> + class static_store_slot: + public slot, + enable_any + { + }; + + //////////////////////////////////////// + + template + struct type_index; + + template + struct type_index + { + static const int value = 0; + }; + + template + struct type_index + { + static const int value = 1 + type_index::value; + }; + + template + struct tuple_type_index; + + template + struct tuple_type_index> + { + static const int value = type_index::value; + }; + + //////////////////////////////////////// + + template + struct check_one_argument + { + static bool check( SlotsTuple const & tup, error_info const & ei ) noexcept + { + auto & sl = std::get,SlotsTuple>::value>(tup); + return sl.has_value() && sl.value().id==ei.error(); + } + }; + + template + struct check_one_argument + { + static bool check( SlotsTuple const &, error_info const & ) noexcept + { + return true; + } + }; + + template + struct check_one_argument + { + static constexpr bool check( SlotsTuple const &, error_info const & ) + { + return true; + } + }; + + template + struct check_one_argument + { + static constexpr bool check( SlotsTuple const &, error_info const & ) + { + return true; + } + }; + + template ::type... V> + struct check_one_argument> + { + static bool check( SlotsTuple const & tup, error_info const & ei ) noexcept + { + auto & sl = std::get,SlotsTuple>::value>(tup); + if( sl.has_value() ) + { + auto const & v = sl.value(); + return v.id==ei.error() && match(v.e)(); + } + else + return false; + } + }; + + template + struct check_one_argument> + { + static bool check( SlotsTuple const &, error_info const & ei ) noexcept + { + if( std::exception const * ex = ei.exception() ) + return catch_(*ex)(); + else + return false; + } + }; + + template + struct check_arguments; + + template + struct check_arguments + { + static bool check( SlotsTuple const & tup, error_info const & ei ) noexcept + { + return check_one_argument::check(tup,ei) && check_arguments::check(tup,ei); + } + }; + + template + struct check_arguments + { + static constexpr bool check( SlotsTuple const &, error_info const & ) noexcept + { + return true; + } + }; + + //////////////////////////////////////// + + template + struct get_one_argument + { + template + static T const & get( StaticStore const & ss, error_info const & ei, R * ) noexcept + { + T const * arg = ss.template peek(ei.error()); + assert(arg!=0); + return *arg; + } + }; + + template + struct get_one_argument + { + template + static T const * get( StaticStore const & ss, error_info const & ei, R * ) noexcept + { + return ss.template peek(ei.error()); + } + }; + + template + struct get_one_argument + { + template + static R get( StaticStore const & ss, error_info const & ei, R * r ) noexcept + { + assert(r!=0); + return *r; + } + }; + + template + struct get_one_argument + { + template + static error_info const & get( StaticStore const &, error_info const & ei, R * ) noexcept + { + return ei; + } + }; + + template + struct get_one_argument + { + template + static diagnostic_info const & get( StaticStore const & ss, error_info const & ei, R * ) noexcept + { + diagnostic_info const * uei = ss.template peek(ei.error()); + assert(uei!=0); + uei->set_error_info(ei); + return *uei; + } + }; + + template + struct get_one_argument + { + template + static verbose_diagnostic_info const & get( StaticStore const & ss, error_info const & ei, R * ) noexcept + { + verbose_diagnostic_info const * vdi = ss.template peek(ei.error()); + assert(vdi!=0); + vdi->set_error_info(ei); + return *vdi; + } + }; + + template ::type... V> + struct get_one_argument> + { + template + static match get( StaticStore const & ss, error_info const & ei, R * ) noexcept + { + E const * arg = ss.template peek(ei.error()); + assert(arg!=0); + return match(*arg); + } + }; + + template + struct get_one_argument> + { + template + static catch_ get( StaticStore const &, error_info const & ei, R * ) noexcept + { + std::exception const * ex = ei.exception(); + assert(ex!=0); + return catch_(*ex); + } + }; + + //////////////////////////////////////// + + template struct argument_matches_any_error: std::false_type { }; + template struct argument_matches_any_error: is_error_type { }; + template struct argument_matches_any_error: std::true_type { }; + template struct argument_matches_any_error: std::true_type { }; + template struct argument_matches_any_error: std::true_type { }; + template struct argument_matches_any_error: std::true_type { }; + + template + struct handler_matches_any_error: std::false_type + { + }; + + template class L, class Car, class... Cdr> + struct handler_matches_any_error> + { + constexpr static bool value = + argument_matches_any_error::type>::type>::value && + handler_matches_any_error>::value; + }; + + template class L> + struct handler_matches_any_error>: std::true_type + { + }; + } + + template + class dynamic_store_impl; + + template + class static_store + { + template + friend class dynamic_store_impl; + + static_store( static_store const & ) = delete; + static_store & operator=( static_store const & ) = delete; + + std::tuple...> s_; + bool reset_; + + template + bool check_handler( error_info const & ei, leaf_detail_mp11::mp_list ) const noexcept + { + using namespace static_store_internal; + return check_arguments::type>::type...>::check(s_,ei); + } + + template + typename function_traits::return_type call_handler( error_info const & ei, R * r, F && f, leaf_detail_mp11::mp_list ) const + { + using namespace static_store_internal; + return std::forward(f)( get_one_argument::type>::type>::get(*this, ei, r)... ); + } + + public: + + constexpr explicit static_store() noexcept: + reset_(false) + { + } + + ~static_store() noexcept + { + if( reset_&& !std::uncaught_exception() ) + static_store_internal::tuple_for_each::reset(s_); + } + + void set_reset( bool r ) noexcept + { + reset_ = r; + } + + template + P const * peek( error_id id ) const noexcept + { + auto & opt = std::get::value>(s_); + if( opt.has_value() ) + { + auto & v = opt.value(); + if( v.id==id ) + return &v.e; + } + return 0; + } + + template + typename function_traits::return_type handle_error( error_info const & ei, R * r, F && f ) const + { + using namespace static_store_internal; + assert(!ei.error()); + static_assert( handler_matches_any_error::mp_args>::value, "The last handler passed to handle_all must match any error." ); + return call_handler( ei, r, std::forward(f), typename function_traits::mp_args{ } ); + } + + template + typename function_traits::return_type handle_error( error_info const & ei, R * r, CarF && car_f, CdarF && cdar_f, CddrF && ... cddr_f ) const + { + using namespace static_store_internal; + assert(!ei.error()); + if( handler_matches_any_error::mp_args>::value || check_handler( ei, typename function_traits::mp_args{ } ) ) + return call_handler( ei, r, std::forward(car_f), typename function_traits::mp_args{ } ); + else + return handle_error( ei, r, std::forward(cdar_f), std::forward(cddr_f)...); + } + }; + + // Static store deduction + + template struct translate_expect_deduction { typedef T type; }; + template struct translate_expect_deduction { typedef T type; }; + template struct translate_expect_deduction { typedef T type; }; + template struct translate_expect_deduction { typedef T type; }; + template ::type... V> struct translate_expect_deduction> { typedef E type; }; + template struct translate_expect_deduction> { typedef void type; }; + + template + struct translate_list_impl; + + template class L, class... T> + struct translate_list_impl> + { + using type = leaf_detail_mp11::mp_list::type...>; + }; + + template using translate_list = typename translate_list_impl::type; + + template struct does_not_participate_in_expect_deduction: std::false_type { }; + template struct does_not_participate_in_expect_deduction: std::true_type { }; + template struct does_not_participate_in_expect_deduction: std::true_type { }; + template struct does_not_participate_in_expect_deduction: std::true_type { }; + template <> struct does_not_participate_in_expect_deduction: std::true_type { }; + + template + struct handler_args_set + { + template using to_remove = does_not_participate_in_expect_deduction; + + using type = + leaf_detail_mp11::mp_remove_if< + leaf_detail_mp11::mp_unique< + translate_list< + leaf_detail_mp11::mp_append< + typename function_traits::mp_args... + > + > + >, + to_remove + >; + }; + + template + struct deduce_static_store; + + template class L, class... T> + struct deduce_static_store> + { + typedef static_store type; + }; + } // leaf_detail + +} } + +#endif diff --git a/include/boost/leaf/detail/static_store.hpp b/include/boost/leaf/detail/static_store.hpp index bdfc748..6730164 100644 --- a/include/boost/leaf/detail/static_store.hpp +++ b/include/boost/leaf/detail/static_store.hpp @@ -14,6 +14,14 @@ namespace boost { namespace leaf { + template + struct failed + { + R value; + }; + + template struct is_error_type>: std::false_type { }; + namespace leaf_detail { template ::value> @@ -212,6 +220,15 @@ namespace boost { namespace leaf { } }; + template + struct check_one_argument> + { + static bool check( SlotsTuple const &, error_info const & ) noexcept + { + return true; + } + }; + template ::type... V> struct check_one_argument> { @@ -275,8 +292,8 @@ namespace boost { namespace leaf { template struct get_one_argument { - template - static T const & get( StaticStore const & ss, error_info const & ei ) noexcept + template + static T const & get( StaticStore const & ss, error_info const & ei, R * ) noexcept { T const * arg = ss.template peek(ei.error()); assert(arg!=0); @@ -287,18 +304,29 @@ namespace boost { namespace leaf { template struct get_one_argument { - template - static T const * get( StaticStore const & ss, error_info const & ei ) noexcept + template + static T const * get( StaticStore const & ss, error_info const & ei, R * ) noexcept { return ss.template peek(ei.error()); } }; + template + struct get_one_argument> + { + template + static failed get( StaticStore const & ss, error_info const & ei, R * r ) noexcept + { + assert(r!=0); + return failed{ std::forward(*r) }; + } + }; + template ::type... V> struct get_one_argument> { - template - static match get( StaticStore const & ss, error_info const & ei ) noexcept + template + static match get( StaticStore const & ss, error_info const & ei, R * ) noexcept { E const * arg = ss.template peek(ei.error()); assert(arg!=0); @@ -309,8 +337,8 @@ namespace boost { namespace leaf { template struct get_one_argument> { - template - static catch_ get( StaticStore const &, error_info const & ei ) noexcept + template + static catch_ get( StaticStore const &, error_info const & ei, R * ) noexcept { std::exception const * ex = ei.exception(); assert(ex!=0); @@ -321,8 +349,8 @@ namespace boost { namespace leaf { template <> struct get_one_argument { - template - static error_info const & get( StaticStore const &, error_info const & ei ) noexcept + template + static error_info const & get( StaticStore const &, error_info const & ei, R * ) noexcept { return ei; } @@ -331,8 +359,8 @@ namespace boost { namespace leaf { template <> struct get_one_argument { - template - static diagnostic_info const & get( StaticStore const & ss, error_info const & ei ) noexcept + template + static diagnostic_info const & get( StaticStore const & ss, error_info const & ei, R * ) noexcept { diagnostic_info const * uei = ss.template peek(ei.error()); assert(uei!=0); @@ -344,8 +372,8 @@ namespace boost { namespace leaf { template <> struct get_one_argument { - template - static verbose_diagnostic_info const & get( StaticStore const & ss, error_info const & ei ) noexcept + template + static verbose_diagnostic_info const & get( StaticStore const & ss, error_info const & ei, R * ) noexcept { verbose_diagnostic_info const * vdi = ss.template peek(ei.error()); assert(vdi!=0); @@ -358,6 +386,8 @@ namespace boost { namespace leaf { template struct argument_matches_any_error: std::false_type { }; template struct argument_matches_any_error: is_error_type { }; + template struct argument_matches_any_error const &>: std::true_type { }; + template struct argument_matches_any_error &&>: std::true_type { }; template <> struct argument_matches_any_error: std::true_type { }; template <> struct argument_matches_any_error: std::true_type { }; template <> struct argument_matches_any_error: std::true_type { }; @@ -398,14 +428,14 @@ namespace boost { namespace leaf { bool check_handler( error_info const & ei, leaf_detail_mp11::mp_list ) const noexcept { using namespace static_store_internal; - return check_arguments::type>::type...>::check(s_,ei); + return check_arguments::type>::type...>::check(s_, ei); } - template - typename function_traits::return_type call_handler( error_info const & ei, F && f, leaf_detail_mp11::mp_list ) const + template + typename function_traits::return_type call_handler( error_info const & ei, R * r, F && f, leaf_detail_mp11::mp_list ) const { using namespace static_store_internal; - return std::forward(f)( get_one_argument::type>::type>::get(*this,ei)... ); + return std::forward(f)( get_one_argument::type>::type>::get(*this, ei, r)... ); } public: @@ -439,22 +469,22 @@ namespace boost { namespace leaf { return 0; } - template - typename function_traits::return_type handle_error( error_info const & ei, F && f ) const + template + typename function_traits::return_type handle_error( error_info const & ei, R * r, F && f ) const { using namespace static_store_internal; static_assert( handler_matches_any_error::mp_args>::value, "The last handler passed to handle_all must match any error." ); - return call_handler( ei, std::forward(f), typename function_traits::mp_args{ } ); + return call_handler( ei, r, std::forward(f), typename function_traits::mp_args{ } ); } - template - typename function_traits::return_type handle_error( error_info const & ei, CarF && car_f, CdarF && cdar_f, CddrF && ... cddr_f ) const + template + typename function_traits::return_type handle_error( error_info const & ei, R * r, CarF && car_f, CdarF && cdar_f, CddrF && ... cddr_f ) const { using namespace static_store_internal; if( handler_matches_any_error::mp_args>::value || check_handler( ei, typename function_traits::mp_args{ } ) ) - return call_handler( ei, std::forward(car_f), typename function_traits::mp_args{ } ); + return call_handler( ei, r, std::forward(car_f), typename function_traits::mp_args{ } ); else - return handle_error( ei, std::forward(cdar_f), std::forward(cddr_f)...); + return handle_error( ei, r, std::forward(cdar_f), std::forward(cddr_f)...); } }; @@ -464,6 +494,9 @@ namespace boost { namespace leaf { template struct translate_expect_deduction { typedef T type; }; template struct translate_expect_deduction { typedef T type; }; template struct translate_expect_deduction { typedef T type; }; + template struct translate_expect_deduction const> { typedef failed type; }; + template struct translate_expect_deduction const &> { typedef failed type; }; + template struct translate_expect_deduction &&> { typedef failed type; }; template ::type... V> struct translate_expect_deduction> { typedef E type; }; template struct translate_expect_deduction> { typedef void type; }; @@ -479,6 +512,7 @@ namespace boost { namespace leaf { template using translate_list = typename translate_list_impl::type; template struct does_not_participate_in_expect_deduction: std::false_type { }; + template struct does_not_participate_in_expect_deduction>: std::true_type { }; template <> struct does_not_participate_in_expect_deduction: std::true_type { }; template <> struct does_not_participate_in_expect_deduction: std::true_type { }; diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index d9f7be2..5416dcb 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -22,23 +22,19 @@ namespace boost { namespace system { class error_code; } } namespace boost { namespace leaf { - class error_id; - - error_id next_error() noexcept; - error_id last_error() noexcept; - error_id get_error_id( std::error_code const & ) noexcept; - class error_id { template friend error_id new_error( E && ... ) noexcept; - friend error_id leaf::next_error() noexcept; - friend error_id leaf::last_error() noexcept; - friend error_id get_error_id( std::error_code const & ) noexcept; + friend error_id next_error() noexcept; + friend error_id last_error() noexcept; + friend error_id success() noexcept; + friend error_id get_error_id( std::error_code ) noexcept; + friend std::error_code get_error_code( error_id ) noexcept; - unsigned id_; + int id_; - explicit error_id( unsigned id ) noexcept: + explicit error_id( int id ) noexcept: id_(id) { } @@ -48,14 +44,17 @@ namespace boost { namespace leaf { id_factory( id_factory const & ) = delete; id_factory & operator=( id_factory const & ) = delete; - static unsigned new_error_id() noexcept + static int new_error_id() noexcept { - static std::atomic c; - return ++c; + static std::atomic c; + if( unsigned id = ++c ) + return int(id); + else + return int(++c); } - unsigned next_id_; - unsigned last_id_; + int next_id_; + int last_id_; id_factory() noexcept: next_id_(new_error_id()), @@ -71,19 +70,19 @@ namespace boost { namespace leaf { return s; } - unsigned next_id() noexcept + int next_id() noexcept { return next_id_; } - unsigned last_id() noexcept + int last_id() noexcept { return last_id_; } - unsigned get() noexcept + int new_id() noexcept { - unsigned id = last_id_ = next_id_; + int id = last_id_ = next_id_; next_id_ = new_error_id(); return id; } @@ -91,12 +90,17 @@ namespace boost { namespace leaf { public: - friend bool operator==( error_id const & e1, error_id const & e2 ) noexcept + operator bool() const noexcept + { + return id_==0; + } + + friend bool operator==( error_id e1, error_id e2 ) noexcept { return e1.id_==e2.id_; } - friend bool operator!=( error_id const & e1, error_id const & e2 ) noexcept + friend bool operator!=( error_id e1, error_id e2 ) noexcept { return e1.id_!=e2.id_; } @@ -106,7 +110,7 @@ namespace boost { namespace leaf { return *this; } - friend std::ostream & operator<<( std::ostream & os, error_id const & id ) + friend std::ostream & operator<<( std::ostream & os, error_id id ) { os << id.id_; return os; @@ -114,14 +118,12 @@ namespace boost { namespace leaf { template error_id propagate( E && ... ) const noexcept; - - std::error_code to_error_code() const noexcept; }; template error_id new_error( E && ... e ) noexcept { - return error_id(error_id::id_factory::tl_instance().get()).propagate(std::forward(e)...); + return error_id(error_id::id_factory::tl_instance().new_id()).propagate(std::forward(e)...); } inline error_id next_error() noexcept @@ -134,6 +136,11 @@ namespace boost { namespace leaf { return error_id(error_id::id_factory::tl_instance().last_id()); } + inline error_id success() noexcept + { + return error_id(0); + } + //////////////////////////////////////// namespace leaf_detail @@ -143,11 +150,11 @@ namespace boost { namespace leaf { slot_base( slot_base const & ) = delete; slot_base & operator=( slot_base const & ) = delete; - virtual bool slot_print( std::ostream &, error_id const & ) const = 0; + virtual bool slot_print( std::ostream &, error_id ) const = 0; public: - static void print( std::ostream & os, error_id const & id ) + static void print( std::ostream & os, error_id id ) { for( slot_base const * p = first(); p; p=p->next_ ) if( p->slot_print(os,id) ) @@ -195,7 +202,7 @@ namespace boost { namespace leaf { public: - explicit error_info( error_id const & id ) noexcept: + explicit error_info( error_id id ) noexcept: id_(id), ex_(0), cap_(0), @@ -203,7 +210,7 @@ namespace boost { namespace leaf { { } - error_info( error_id const & id, std::exception const * ex, void (*print_ex)(std::ostream &, std::exception const *, leaf_detail::captured_exception const *) ) noexcept: + error_info( error_id id, std::exception const * ex, void (*print_ex)(std::ostream &, std::exception const *, leaf_detail::captured_exception const *) ) noexcept: id_(id), ex_(ex), cap_(0), @@ -212,7 +219,7 @@ namespace boost { namespace leaf { assert(print_ex_!=0); } - error_info( error_id const & id, std::exception const * ex, leaf_detail::captured_exception const * cap, void (*print_ex)(std::ostream &, std::exception const *, leaf_detail::captured_exception const *) ) noexcept: + error_info( error_id id, std::exception const * ex, leaf_detail::captured_exception const * cap, void (*print_ex)(std::ostream &, std::exception const *, leaf_detail::captured_exception const *) ) noexcept: id_(id), ex_(ex), cap_(cap), @@ -221,7 +228,7 @@ namespace boost { namespace leaf { assert(print_ex_!=0); } - error_id const & error() const noexcept + error_id error() const noexcept { return id_; } @@ -441,18 +448,18 @@ namespace boost { namespace leaf { error_id id; E e; - explicit id_e_pair( error_id const & id ) noexcept: + explicit id_e_pair( error_id id ) noexcept: id(id) { } - id_e_pair( error_id const & id, E const & e ): + id_e_pair( error_id id, E const & e ): id(id), e(e) { } - id_e_pair( error_id const & id, E && e ) noexcept: + id_e_pair( error_id id, E && e ) noexcept: id(id), e(std::forward(e)) { @@ -481,7 +488,7 @@ namespace boost { namespace leaf { slot * prev_; static_assert(is_error_type::value,"Not an error type"); - bool slot_print( std::ostream &, error_id const & ) const; + bool slot_print( std::ostream &, error_id ) const; protected: @@ -549,7 +556,7 @@ namespace boost { namespace leaf { } template - int put_slot( E && e, error_id const & id ) noexcept + int put_slot( E && e, error_id id ) noexcept { using T = typename std::remove_cv::type>::type; if( slot * p = tl_slot_ptr() ) @@ -591,7 +598,7 @@ namespace boost { namespace leaf { } template - bool slot::slot_print( std::ostream & os, error_id const & id ) const + bool slot::slot_print( std::ostream & os, error_id id ) const { if( tl_slot_ptr()==this ) if( id_e_pair const * id_e = has_value() ) @@ -626,6 +633,16 @@ namespace boost { namespace leaf { return *this; } + inline bool succeeded( error_id id ) noexcept + { + return bool(id); + } + + inline error_id get_error_id( error_id id ) noexcept + { + return id; + } + } } #endif diff --git a/include/boost/leaf/error_code.hpp b/include/boost/leaf/error_code.hpp index 586435f..cd6694a 100644 --- a/include/boost/leaf/error_code.hpp +++ b/include/boost/leaf/error_code.hpp @@ -41,35 +41,26 @@ namespace boost { namespace leaf { static error_category cat; return cat; } - - inline error_category const & get_error_category0() noexcept - { - static error_category cat; - return cat; - } } - inline std::error_code error_id::to_error_code() const noexcept + inline std::error_code get_error_code( error_id id ) noexcept { - return id_ ? - std::error_code( int(id_), leaf_detail::get_error_category() ) : - std::error_code( -1, leaf_detail::get_error_category0() ); + return id? + std::error_code() : + std::error_code(id.id_, leaf_detail::get_error_category()); } - inline bool succeeded( std::error_code const & ec ) + inline bool succeeded( std::error_code ec ) { return !ec; } - inline error_id get_error_id( std::error_code const & ec ) noexcept + inline error_id get_error_id( std::error_code ec ) noexcept { - std::error_category const & cat = ec.category(); - if( &cat==&leaf_detail::get_error_category() ) - return error_id(ec.value()); - else if( &cat==&leaf_detail::get_error_category0() ) + if( &ec.category()==&leaf_detail::get_error_category() ) { - assert(ec.value()==-1); - return error_id(0); + assert(ec); + return error_id{ec.value()}; } else return leaf::next_error(); diff --git a/include/boost/leaf/handle.hpp b/include/boost/leaf/handle.hpp index aab216c..7a9fc1d 100644 --- a/include/boost/leaf/handle.hpp +++ b/include/boost/leaf/handle.hpp @@ -24,7 +24,7 @@ namespace boost { namespace leaf { if( succeeded(r) ) return r.value(); else - return ss.handle_error(error_info(get_error_id(r)), std::forward(handler)...); + return ss.handle_error(error_info(get_error_id(r)), &r, std::forward(handler)...); } namespace leaf_detail @@ -48,7 +48,7 @@ namespace boost { namespace leaf { } R operator()( A... a ) const { - return f_(a...); + return f_(std::forward(a)...); } }; @@ -62,7 +62,7 @@ namespace boost { namespace leaf { } typename dependent_type_result_void::type operator()( A... a ) const { - f_(a...); + f_(std::forward(a)...); return { }; } }; @@ -72,7 +72,7 @@ namespace boost { namespace leaf { decltype(std::declval()()) handle_some( TryBlock && try_block, Handler && ... handler ) { using namespace leaf_detail; - using R = typename function_traits::return_type; + using R = decltype(std::declval()()); typename deduce_static_store::type>::type ss; auto r = std::forward(try_block)(); @@ -83,7 +83,7 @@ namespace boost { namespace leaf { } else { - auto rr = ss.handle_error(error_info(get_error_id(r)), handler_wrapper(std::forward(handler))..., [&r] { return r; } ); + auto rr = ss.handle_error(error_info(get_error_id(r)), &r, handler_wrapper(std::forward(handler))..., [&r] { return r; } ); if( succeeded(rr) ) { ss.set_reset(true); diff --git a/include/boost/leaf/preload.hpp b/include/boost/leaf/preload.hpp index a3977e6..11e2831 100644 --- a/include/boost/leaf/preload.hpp +++ b/include/boost/leaf/preload.hpp @@ -17,7 +17,7 @@ namespace boost { namespace leaf { template struct tuple_for_each_preload { - static void trigger( Tuple & tup, error_id const & id ) noexcept + static void trigger( Tuple & tup, error_id id ) noexcept { tuple_for_each_preload::trigger(tup,id); std::get(tup).trigger(id); @@ -27,7 +27,7 @@ namespace boost { namespace leaf { template struct tuple_for_each_preload<0, Tuple> { - static void trigger( Tuple const &, error_id const & ) noexcept { } + static void trigger( Tuple const &, error_id ) noexcept { } }; } // leaf_detail @@ -49,7 +49,7 @@ namespace boost { namespace leaf { { } - void trigger( error_id const & id ) noexcept + void trigger( error_id id ) noexcept { if( s_ ) { @@ -134,7 +134,7 @@ namespace boost { namespace leaf { { } - void trigger( error_id const & id ) noexcept + void trigger( error_id id ) noexcept { if( s_ ) { diff --git a/include/boost/leaf/result.hpp b/include/boost/leaf/result.hpp index d462041..e849b79 100644 --- a/include/boost/leaf/result.hpp +++ b/include/boost/leaf/result.hpp @@ -149,7 +149,7 @@ namespace boost { namespace leaf { { } - result( error_id const & id ) noexcept: + result( error_id id ) noexcept: err_(id), which_(leaf_detail::result_variant::err) { @@ -265,7 +265,7 @@ namespace boost { namespace leaf { result() = default; - result( error_id const & id ) noexcept: + result( error_id id ) noexcept: base(id) { } diff --git a/include/boost/leaf/try.hpp b/include/boost/leaf/try.hpp index 9ed77e8..432e616 100644 --- a/include/boost/leaf/try.hpp +++ b/include/boost/leaf/try.hpp @@ -41,20 +41,20 @@ namespace boost { namespace leaf { } catch( std::exception const & ex ) { - return ss.handle_error(error_info(get_error_id(ex),&ex,&cap,&print_exception_info), std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); + return ss.handle_error(error_info(get_error_id(ex),&ex,&cap,&print_exception_info), (void *)0, std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); } catch( ... ) { - return ss.handle_error(error_info(next_error(),0,&cap,&print_exception_info), std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); + return ss.handle_error(error_info(next_error(),0,&cap,&print_exception_info), (void *)0, std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); } } catch( std::exception const & ex ) { - return ss.handle_error(error_info(get_error_id(ex),&ex,0,&print_exception_info), std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); + return ss.handle_error(error_info(get_error_id(ex),&ex,0,&print_exception_info), (void *)0, std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); } catch( ... ) { - return ss.handle_error(error_info(next_error(),0,0,&print_exception_info), std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); + return ss.handle_error(error_info(next_error(),0,0,&print_exception_info), (void *)0, std::forward(handler)..., [ ]() -> typename function_traits::return_type { throw; }); } } diff --git a/test/handle_all_error_code_test.cpp b/test/handle_all_error_code_test.cpp index fb5ef90..d7805d2 100644 --- a/test/handle_all_error_code_test.cpp +++ b/test/handle_all_error_code_test.cpp @@ -31,7 +31,7 @@ int main() int r = leaf::handle_all( [&] { - std::error_code ec = leaf::new_error(info<1>{1}).to_error_code(); + std::error_code ec = get_error_code(leaf::new_error(info<1>{1})); BOOST_TEST(ec); BOOST_TEST(ec.message()=="LEAF error, use with leaf::handle_some or leaf::handle_all."); BOOST_TEST(!std::strcmp(ec.category().name(),"LEAF error, use with leaf::handle_some or leaf::handle_all.")); @@ -52,7 +52,7 @@ int main() int r = leaf::handle_all( [&] { - return leaf::new_error(info<2>{2},std::error_code(ENOENT,std::system_category())).to_error_code(); + return get_error_code(leaf::new_error(info<2>{2},std::error_code(ENOENT,std::system_category()))); }, [ ]( info<2> const & x, std::error_code const & ec ) { diff --git a/test/handle_some_error_code_test.cpp b/test/handle_some_error_code_test.cpp index ef0d9cd..e97ca93 100644 --- a/test/handle_some_error_code_test.cpp +++ b/test/handle_some_error_code_test.cpp @@ -20,7 +20,7 @@ int main() std::error_code r = leaf::handle_some( [&] { - std::error_code ec = leaf::new_error(info<1>{1}).to_error_code(); + std::error_code ec = get_error_code(leaf::new_error(info<1>{1})); BOOST_TEST(ec); BOOST_TEST(ec.message()=="LEAF error, use with leaf::handle_some or leaf::handle_all."); BOOST_TEST(!std::strcmp(ec.category().name(),"LEAF error, use with leaf::handle_some or leaf::handle_all.")); @@ -40,16 +40,79 @@ int main() std::error_code ec = leaf::handle_some( [&] { - return leaf::new_error(info<2>{2},std::error_code(ENOENT,std::system_category())).to_error_code(); + return get_error_code(leaf::new_error(info<2>{2},std::error_code(ENOENT,std::system_category()))); }, [&]( info<2> const & x, std::error_code const & ec ) { - what = 2; + what = 1; BOOST_TEST(x.value==2); BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); return ec; } ); BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); + BOOST_TEST(what==1); + } + { + int what=0; + std::error_code ec = leaf::handle_some( + [&] + { + return std::error_code(ENOENT,std::system_category()); + }, + [&]( std::error_code const & ec ) + { + what = 1; + return ec; + }, + [&]( leaf::failed const & ec ) + { + what = 2; + BOOST_TEST(ec.value==std::error_code(ENOENT,std::system_category())); + return ec.value; + } ); + BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); + BOOST_TEST(what==2); + } + { + int what=0; + std::error_code ec = leaf::handle_some( + [&] + { + return std::error_code(ENOENT,std::system_category()); + }, + [&]( std::error_code const & ec ) + { + what = 1; + return ec; + }, + [&]( leaf::failed ec ) + { + what = 2; + BOOST_TEST(ec.value==std::error_code(ENOENT,std::system_category())); + return ec.value; + } ); + BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); + BOOST_TEST(what==2); + } + { + int what=0; + std::error_code ec = leaf::handle_some( + [&] + { + return std::error_code(ENOENT,std::system_category()); + }, + [&]( std::error_code const & ec ) + { + what = 1; + return ec; + }, + [&]( leaf::failed && ec ) + { + what = 2; + BOOST_TEST(ec.value==std::error_code(ENOENT,std::system_category())); + return ec.value; + } ); + BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); BOOST_TEST(what==2); } return boost::report_errors(); diff --git a/test/result_state_test.cpp b/test/result_state_test.cpp index 488b849..895baf4 100644 --- a/test/result_state_test.cpp +++ b/test/result_state_test.cpp @@ -495,8 +495,7 @@ int main() BOOST_TEST(val::count==0); leaf::result r2; r2=std::move(r1); BOOST_TEST(!r2); - leaf::error_id const id = r2.error(); - exp.handle_error(leaf::error_info(id),[ ]{ }); + exp.handle_error(leaf::error_info(r2.error()), (void *)0, [ ]{ }); BOOST_TEST(err::count==1); BOOST_TEST(val::count==0); } @@ -749,8 +748,7 @@ int main() BOOST_TEST(err::count==1); leaf::result r2; r2=std::move(r1); BOOST_TEST(!r2); - leaf::error_id const id = r2.error(); - exp.handle_error(leaf::error_info(id),[ ]{ }); + exp.handle_error(leaf::error_info(r2.error()), (void *)0, [ ]{ }); BOOST_TEST(err::count==1); } BOOST_TEST(err::count==0); diff --git a/test/static_store_deduction_test.cpp b/test/static_store_deduction_test.cpp index 3fcfb67..c7e313c 100644 --- a/test/static_store_deduction_test.cpp +++ b/test/static_store_deduction_test.cpp @@ -67,6 +67,11 @@ void not_called_on_purpose() test< static_store,info<2>> >( expd([ ]( info<1>, info<2> ){ }, [ ]( info<2>, leaf::error_info const & ){ }) ); test< static_store,info<2>> >( expd([ ]( info<1>, info<2> ){ }, [ ]( info<1>, leaf::error_info const &, info<2> ){ }) ); + test< static_store,info<2>> >( expd([ ]( info<1> ){ }, [ ]( info<2>, leaf::failed const & ){ }) ); + test< static_store,info<2>> >( expd([ ]( info<1> ){ }, [ ]( info<1>, leaf::failed const &, info<2> ){ }) ); + test< static_store,info<2>> >( expd([ ]( info<1>, info<2> ){ }, [ ]( info<2>, leaf::failed && ){ }) ); + test< static_store,info<2>> >( expd([ ]( info<1>, info<2> ){ }, [ ]( info<1>, leaf::failed, info<2> ){ }) ); + test< static_store,info<2>,info<3>> >( expd([ ]( info<1> ){ }, [ ]( info<2> ){ }, [ ]( info<3> ){ }) ); test< static_store,info<2>,info<3>> >( expd([ ]( info<1> ){ }, [ ]( info<1>, info<2> ){ }, [ ]( info<1>, info<3> ){ }) ); test< static_store,info<2>,info<3>> >( expd([ ]( info<1> ){ }, [ ]( info<1>, info<2> ){ }, [ ]( info<1>, info<3> ){ }) ); diff --git a/test/static_store_test.cpp b/test/static_store_test.cpp index 1195ac2..6562e3f 100644 --- a/test/static_store_test.cpp +++ b/test/static_store_test.cpp @@ -82,7 +82,7 @@ int main() BOOST_TEST(!exp.peek>(e1)); { - int r = exp.handle_error( leaf::error_info(e1), + int r = exp.handle_error( leaf::error_info(e1), (void *)0, [ ](info<1>,info<2>,info<4>) { return 1; @@ -108,7 +108,7 @@ int main() BOOST_TEST(!exp.peek>(e2)); { - int r = exp.handle_error( leaf::error_info(e2), + int r = exp.handle_error( leaf::error_info(e2), (void *)0, [ ]( info<1>, info<2>, info<4> ) { return 1; @@ -131,7 +131,7 @@ int main() } { - int r = exp0.handle_error( leaf::error_info(e0), + int r = exp0.handle_error( leaf::error_info(e0), (void *)0, [ ]( info<2> const & i2, info<1> const & i1 ) { BOOST_TEST(i1.value==1);