capture.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #ifndef BOOST_LEAF_CAPTURE_HPP_INCLUDED
  2. #define BOOST_LEAF_CAPTURE_HPP_INCLUDED
  3. // Copyright 2018-2023 Emil Dotchevski and Reverge Studios, Inc.
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #include <boost/leaf/config.hpp>
  7. #include <boost/leaf/exception.hpp>
  8. #include <boost/leaf/on_error.hpp>
  9. #if BOOST_LEAF_CFG_CAPTURE
  10. namespace boost { namespace leaf {
  11. namespace leaf_detail
  12. {
  13. template <class R, bool IsResult = is_result_type<R>::value>
  14. struct is_result_tag;
  15. template <class R>
  16. struct is_result_tag<R, false>
  17. {
  18. };
  19. template <class R>
  20. struct is_result_tag<R, true>
  21. {
  22. };
  23. }
  24. #ifdef BOOST_LEAF_NO_EXCEPTIONS
  25. namespace leaf_detail
  26. {
  27. template <class R, class F, class... A, class ContextPtr>
  28. inline
  29. decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
  30. capture_impl(is_result_tag<R, false>, ContextPtr && ctx, F && f, A... a) noexcept
  31. {
  32. auto active_context = activate_context(*ctx);
  33. return std::forward<F>(f)(std::forward<A>(a)...);
  34. }
  35. template <class R, class F, class... A, class ContextPtr>
  36. inline
  37. decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
  38. capture_impl(is_result_tag<R, true>, ContextPtr && ctx, F && f, A... a) noexcept
  39. {
  40. auto active_context = activate_context(*ctx);
  41. if( auto r = std::forward<F>(f)(std::forward<A>(a)...) )
  42. return r;
  43. else
  44. {
  45. ctx->captured_id_ = r.error();
  46. return std::forward<ContextPtr>(ctx);
  47. }
  48. }
  49. template <class R, class Future>
  50. inline
  51. decltype(std::declval<Future>().get())
  52. future_get_impl(is_result_tag<R, false>, Future & fut) noexcept
  53. {
  54. return fut.get();
  55. }
  56. template <class R, class Future>
  57. inline
  58. decltype(std::declval<Future>().get())
  59. future_get_impl(is_result_tag<R, true>, Future & fut) noexcept
  60. {
  61. if( auto r = fut.get() )
  62. return r;
  63. else
  64. return error_id(r.error()); // unloads
  65. }
  66. }
  67. #else
  68. namespace leaf_detail
  69. {
  70. class capturing_exception:
  71. public std::exception
  72. {
  73. std::exception_ptr ex_;
  74. context_ptr ctx_;
  75. public:
  76. template <class ContextPtr>
  77. capturing_exception(std::exception_ptr && ex, ContextPtr && ctx) noexcept:
  78. ex_(std::move(ex)),
  79. ctx_(std::forward<ContextPtr>(ctx))
  80. {
  81. BOOST_LEAF_ASSERT(ex_);
  82. BOOST_LEAF_ASSERT(ctx_);
  83. BOOST_LEAF_ASSERT(ctx_->captured_id_);
  84. }
  85. [[noreturn]] void unload_and_rethrow_original_exception() const
  86. {
  87. BOOST_LEAF_ASSERT(ctx_->captured_id_);
  88. tls::write_uint<tls_tag_id_factory_current_id>(unsigned(ctx_->captured_id_.value()));
  89. ctx_->propagate(ctx_->captured_id_);
  90. std::rethrow_exception(ex_);
  91. }
  92. };
  93. template <class R, class F, class... A, class ContextPtr>
  94. inline
  95. decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
  96. capture_impl(is_result_tag<R, false>, ContextPtr && ctx, F && f, A... a)
  97. {
  98. auto active_context = activate_context(*ctx);
  99. error_monitor cur_err;
  100. try
  101. {
  102. return std::forward<F>(f)(std::forward<A>(a)...);
  103. }
  104. catch( capturing_exception const & )
  105. {
  106. throw;
  107. }
  108. catch( exception_base const & e )
  109. {
  110. ctx->captured_id_ = e.get_error_id();
  111. leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::forward<ContextPtr>(ctx)) );
  112. }
  113. catch(...)
  114. {
  115. ctx->captured_id_ = cur_err.assigned_error_id();
  116. leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::forward<ContextPtr>(ctx)) );
  117. }
  118. }
  119. template <class R, class F, class... A, class ContextPtr>
  120. inline
  121. decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
  122. capture_impl(is_result_tag<R, true>, ContextPtr && ctx, F && f, A... a)
  123. {
  124. auto active_context = activate_context(*ctx);
  125. error_monitor cur_err;
  126. try
  127. {
  128. if( auto && r = std::forward<F>(f)(std::forward<A>(a)...) )
  129. return std::move(r);
  130. else
  131. {
  132. ctx->captured_id_ = r.error();
  133. return std::forward<ContextPtr>(ctx);
  134. }
  135. }
  136. catch( capturing_exception const & )
  137. {
  138. throw;
  139. }
  140. catch( exception_base const & e )
  141. {
  142. ctx->captured_id_ = e.get_error_id();
  143. leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::forward<ContextPtr>(ctx)) );
  144. }
  145. catch(...)
  146. {
  147. ctx->captured_id_ = cur_err.assigned_error_id();
  148. leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::forward<ContextPtr>(ctx)) );
  149. }
  150. }
  151. template <class R, class Future>
  152. inline
  153. decltype(std::declval<Future>().get())
  154. future_get_impl(is_result_tag<R, false>, Future & fut )
  155. {
  156. try
  157. {
  158. return fut.get();
  159. }
  160. catch( capturing_exception const & cap )
  161. {
  162. cap.unload_and_rethrow_original_exception();
  163. }
  164. }
  165. template <class R, class Future>
  166. inline
  167. decltype(std::declval<Future>().get())
  168. future_get_impl(is_result_tag<R, true>, Future & fut )
  169. {
  170. try
  171. {
  172. if( auto r = fut.get() )
  173. return r;
  174. else
  175. return error_id(r.error()); // unloads
  176. }
  177. catch( capturing_exception const & cap )
  178. {
  179. cap.unload_and_rethrow_original_exception();
  180. }
  181. }
  182. }
  183. #endif
  184. template <class F, class... A>
  185. inline
  186. decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
  187. capture(context_ptr const & ctx, F && f, A... a)
  188. {
  189. using namespace leaf_detail;
  190. return capture_impl(is_result_tag<decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))>(), ctx, std::forward<F>(f), std::forward<A>(a)...);
  191. }
  192. template <class F, class... A>
  193. inline
  194. decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
  195. capture(context_ptr && ctx, F && f, A... a)
  196. {
  197. using namespace leaf_detail;
  198. 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)...);
  199. }
  200. template <class Future>
  201. inline
  202. decltype(std::declval<Future>().get())
  203. future_get( Future & fut )
  204. {
  205. using namespace leaf_detail;
  206. return future_get_impl(is_result_tag<decltype(std::declval<Future>().get())>(), fut);
  207. }
  208. } }
  209. #endif
  210. #endif