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