1 #ifndef BOOST_LEAF_CAPTURE_HPP_INCLUDED 2 #define BOOST_LEAF_CAPTURE_HPP_INCLUDED 3 4 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc. 5 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) 8 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) 16 # endif 17 #endif 18 19 #include <boost/leaf/exception.hpp> 20 #include <boost/leaf/on_error.hpp> 21 22 namespace boost { namespace leaf { 23 24 namespace leaf_detail 25 { 26 template <class R, bool IsResult = is_result_type<R>::value> 27 struct is_result_tag; 28 29 template <class R> 30 struct is_result_tag<R, false> 31 { 32 }; 33 34 template <class R> 35 struct is_result_tag<R, true> 36 { 37 }; 38 } 39 40 #ifdef BOOST_LEAF_NO_EXCEPTIONS 41 42 namespace leaf_detail 43 { 44 template <class R, class F, class... A> 45 inline 46 decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R,false>,context_ptr && ctx,F && f,A...a)47 capture_impl(is_result_tag<R, false>, context_ptr && ctx, F && f, A... a) noexcept 48 { 49 auto active_context = activate_context(*ctx); 50 return std::forward<F>(f)(std::forward<A>(a)...); 51 } 52 53 template <class R, class F, class... A> 54 inline 55 decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R,true>,context_ptr && ctx,F && f,A...a)56 capture_impl(is_result_tag<R, true>, context_ptr && ctx, F && f, A... a) noexcept 57 { 58 auto active_context = activate_context(*ctx); 59 if( auto r = std::forward<F>(f)(std::forward<A>(a)...) ) 60 return r; 61 else 62 { 63 ctx->captured_id_ = r.error(); 64 return std::move(ctx); 65 } 66 } 67 68 template <class R, class Future> 69 inline 70 decltype(std::declval<Future>().get()) future_get_impl(is_result_tag<R,false>,Future & fut)71 future_get_impl(is_result_tag<R, false>, Future & fut) noexcept 72 { 73 return fut.get(); 74 } 75 76 template <class R, class Future> 77 inline 78 decltype(std::declval<Future>().get()) future_get_impl(is_result_tag<R,true>,Future & fut)79 future_get_impl(is_result_tag<R, true>, Future & fut) noexcept 80 { 81 if( auto r = fut.get() ) 82 return r; 83 else 84 return error_id(r.error()); // unloads 85 } 86 } 87 88 #else 89 90 namespace leaf_detail 91 { 92 class capturing_exception: 93 public std::exception 94 { 95 std::exception_ptr ex_; 96 context_ptr ctx_; 97 98 public: 99 capturing_exception(std::exception_ptr && ex,context_ptr && ctx)100 capturing_exception(std::exception_ptr && ex, context_ptr && ctx) noexcept: 101 ex_(std::move(ex)), 102 ctx_(std::move(ctx)) 103 { 104 BOOST_LEAF_ASSERT(ex_); 105 BOOST_LEAF_ASSERT(ctx_); 106 BOOST_LEAF_ASSERT(ctx_->captured_id_); 107 } 108 unload_and_rethrow_original_exception() const109 [[noreturn]] void unload_and_rethrow_original_exception() const 110 { 111 BOOST_LEAF_ASSERT(ctx_->captured_id_); 112 auto active_context = activate_context(*ctx_); 113 id_factory<>::current_id = ctx_->captured_id_.value(); 114 std::rethrow_exception(ex_); 115 } 116 117 template <class CharT, class Traits> print(std::basic_ostream<CharT,Traits> & os) const118 void print( std::basic_ostream<CharT, Traits> & os ) const 119 { 120 ctx_->print(os); 121 } 122 }; 123 124 template <class R, class F, class... A> 125 inline 126 decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R,false>,context_ptr && ctx,F && f,A...a)127 capture_impl(is_result_tag<R, false>, context_ptr && ctx, F && f, A... a) 128 { 129 auto active_context = activate_context(*ctx); 130 error_monitor cur_err; 131 try 132 { 133 return std::forward<F>(f)(std::forward<A>(a)...); 134 } 135 catch( capturing_exception const & ) 136 { 137 throw; 138 } 139 catch( exception_base const & e ) 140 { 141 ctx->captured_id_ = e.get_error_id(); 142 throw_exception( capturing_exception(std::current_exception(), std::move(ctx)) ); 143 } 144 catch(...) 145 { 146 ctx->captured_id_ = cur_err.assigned_error_id(); 147 throw_exception( capturing_exception(std::current_exception(), std::move(ctx)) ); 148 } 149 } 150 151 template <class R, class F, class... A> 152 inline 153 decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R,true>,context_ptr && ctx,F && f,A...a)154 capture_impl(is_result_tag<R, true>, context_ptr && ctx, F && f, A... a) 155 { 156 auto active_context = activate_context(*ctx); 157 error_monitor cur_err; 158 try 159 { 160 if( auto && r = std::forward<F>(f)(std::forward<A>(a)...) ) 161 return std::move(r); 162 else 163 { 164 ctx->captured_id_ = r.error(); 165 return std::move(ctx); 166 } 167 } 168 catch( capturing_exception const & ) 169 { 170 throw; 171 } 172 catch( exception_base const & e ) 173 { 174 ctx->captured_id_ = e.get_error_id(); 175 throw_exception( capturing_exception(std::current_exception(), std::move(ctx)) ); 176 } 177 catch(...) 178 { 179 ctx->captured_id_ = cur_err.assigned_error_id(); 180 throw_exception( capturing_exception(std::current_exception(), std::move(ctx)) ); 181 } 182 } 183 184 template <class R, class Future> 185 inline 186 decltype(std::declval<Future>().get()) future_get_impl(is_result_tag<R,false>,Future & fut)187 future_get_impl(is_result_tag<R, false>, Future & fut ) 188 { 189 try 190 { 191 return fut.get(); 192 } 193 catch( capturing_exception const & cap ) 194 { 195 cap.unload_and_rethrow_original_exception(); 196 } 197 } 198 199 template <class R, class Future> 200 inline 201 decltype(std::declval<Future>().get()) future_get_impl(is_result_tag<R,true>,Future & fut)202 future_get_impl(is_result_tag<R, true>, Future & fut ) 203 { 204 try 205 { 206 if( auto r = fut.get() ) 207 return r; 208 else 209 return error_id(r.error()); // unloads 210 } 211 catch( capturing_exception const & cap ) 212 { 213 cap.unload_and_rethrow_original_exception(); 214 } 215 } 216 } 217 218 #endif 219 220 template <class F, class... A> 221 inline 222 decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture(context_ptr && ctx,F && f,A...a)223 capture(context_ptr && ctx, F && f, A... a) 224 { 225 using namespace leaf_detail; 226 return capture_impl(is_result_tag<decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))>(), std::move(ctx), std::forward<F>(f), std::forward<A>(a)...); 227 } 228 229 template <class Future> 230 inline 231 decltype(std::declval<Future>().get()) future_get(Future & fut)232 future_get( Future & fut ) 233 { 234 using namespace leaf_detail; 235 return future_get_impl(is_result_tag<decltype(std::declval<Future>().get())>(), fut); 236 } 237 238 //////////////////////////////////////// 239 240 #ifndef BOOST_LEAF_NO_EXCEPTIONS 241 242 template <class T> 243 class result; 244 245 namespace leaf_detail 246 { catch_exceptions_helper(std::exception const & ex,leaf_detail_mp11::mp_list<>)247 inline error_id catch_exceptions_helper( std::exception const & ex, leaf_detail_mp11::mp_list<> ) 248 { 249 return leaf::new_error(std::current_exception()); 250 } 251 252 template <class Ex1, class... Ex> catch_exceptions_helper(std::exception const & ex,leaf_detail_mp11::mp_list<Ex1,Ex...>)253 inline error_id catch_exceptions_helper( std::exception const & ex, leaf_detail_mp11::mp_list<Ex1,Ex...> ) 254 { 255 if( Ex1 const * p = dynamic_cast<Ex1 const *>(&ex) ) 256 return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ }).load(*p); 257 else 258 return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ }); 259 } 260 261 template <class T> 262 struct deduce_exception_to_result_return_type_impl 263 { 264 using type = result<T>; 265 }; 266 267 template <class T> 268 struct deduce_exception_to_result_return_type_impl<result<T>> 269 { 270 using type = result<T>; 271 }; 272 273 template <class T> 274 using deduce_exception_to_result_return_type = typename deduce_exception_to_result_return_type_impl<T>::type; 275 } 276 277 template <class... Ex, class F> 278 inline 279 leaf_detail::deduce_exception_to_result_return_type<leaf_detail::fn_return_type<F>> exception_to_result(F && f)280 exception_to_result( F && f ) noexcept 281 { 282 try 283 { 284 return std::forward<F>(f)(); 285 } 286 catch( std::exception const & ex ) 287 { 288 return leaf_detail::catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>()); 289 } 290 catch(...) 291 { 292 return leaf::new_error(std::current_exception()); 293 } 294 } 295 296 #endif 297 298 } } 299 300 #endif 301