on_error.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED
  2. #define BOOST_LEAF_ON_ERROR_HPP_INCLUDED
  3. // Copyright 2018-2022 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/error.hpp>
  8. namespace boost { namespace leaf {
  9. class error_monitor
  10. {
  11. #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
  12. int const uncaught_exceptions_;
  13. #endif
  14. int const err_id_;
  15. public:
  16. error_monitor() noexcept:
  17. #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
  18. uncaught_exceptions_(std::uncaught_exceptions()),
  19. #endif
  20. err_id_(leaf_detail::current_id())
  21. {
  22. }
  23. int check_id() const noexcept
  24. {
  25. int err_id = leaf_detail::current_id();
  26. if( err_id != err_id_ )
  27. return err_id;
  28. else
  29. {
  30. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  31. # if BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
  32. if( std::uncaught_exceptions() > uncaught_exceptions_ )
  33. # else
  34. if( std::uncaught_exception() )
  35. # endif
  36. return leaf_detail::new_id();
  37. #endif
  38. return 0;
  39. }
  40. }
  41. int get_id() const noexcept
  42. {
  43. int err_id = leaf_detail::current_id();
  44. if( err_id != err_id_ )
  45. return err_id;
  46. else
  47. return leaf_detail::new_id();
  48. }
  49. error_id check() const noexcept
  50. {
  51. return leaf_detail::make_error_id(check_id());
  52. }
  53. error_id assigned_error_id() const noexcept
  54. {
  55. return leaf_detail::make_error_id(get_id());
  56. }
  57. };
  58. ////////////////////////////////////////////
  59. namespace leaf_detail
  60. {
  61. template <int I, class Tuple>
  62. struct tuple_for_each_preload
  63. {
  64. BOOST_LEAF_CONSTEXPR static void trigger( Tuple & tup, int err_id ) noexcept
  65. {
  66. BOOST_LEAF_ASSERT((err_id&3)==1);
  67. tuple_for_each_preload<I-1,Tuple>::trigger(tup,err_id);
  68. std::get<I-1>(tup).trigger(err_id);
  69. }
  70. };
  71. template <class Tuple>
  72. struct tuple_for_each_preload<0, Tuple>
  73. {
  74. BOOST_LEAF_CONSTEXPR static void trigger( Tuple const &, int ) noexcept { }
  75. };
  76. template <class E>
  77. class preloaded_item
  78. {
  79. using decay_E = typename std::decay<E>::type;
  80. slot<decay_E> * s_;
  81. decay_E e_;
  82. public:
  83. BOOST_LEAF_CONSTEXPR preloaded_item( E && e ):
  84. s_(tls::read_ptr<slot<decay_E>>()),
  85. e_(std::forward<E>(e))
  86. {
  87. }
  88. BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
  89. {
  90. BOOST_LEAF_ASSERT((err_id&3)==1);
  91. if( s_ )
  92. {
  93. if( !s_->has_value(err_id) )
  94. s_->put(err_id, std::move(e_));
  95. }
  96. #if BOOST_LEAF_CFG_DIAGNOSTICS
  97. else
  98. {
  99. int c = int(tls::read_uint<tls_tag_unexpected_enabled_counter>());
  100. BOOST_LEAF_ASSERT(c>=0);
  101. if( c )
  102. load_unexpected(err_id, std::move(e_));
  103. }
  104. #endif
  105. }
  106. };
  107. template <class F>
  108. class deferred_item
  109. {
  110. using E = decltype(std::declval<F>()());
  111. slot<E> * s_;
  112. F f_;
  113. public:
  114. BOOST_LEAF_CONSTEXPR deferred_item( F && f ) noexcept:
  115. s_(tls::read_ptr<slot<E>>()),
  116. f_(std::forward<F>(f))
  117. {
  118. }
  119. BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
  120. {
  121. BOOST_LEAF_ASSERT((err_id&3)==1);
  122. if( s_ )
  123. {
  124. if( !s_->has_value(err_id) )
  125. s_->put(err_id, f_());
  126. }
  127. #if BOOST_LEAF_CFG_DIAGNOSTICS
  128. else
  129. {
  130. int c = int(tls::read_uint<tls_tag_unexpected_enabled_counter>());
  131. BOOST_LEAF_ASSERT(c>=0);
  132. if( c )
  133. load_unexpected(err_id, std::forward<E>(f_()));
  134. }
  135. #endif
  136. }
  137. };
  138. template <class F, class A0 = fn_arg_type<F,0>, int arity = function_traits<F>::arity>
  139. class accumulating_item;
  140. template <class F, class A0>
  141. class accumulating_item<F, A0 &, 1>
  142. {
  143. using E = A0;
  144. slot<E> * s_;
  145. F f_;
  146. public:
  147. BOOST_LEAF_CONSTEXPR accumulating_item( F && f ) noexcept:
  148. s_(tls::read_ptr<slot<E>>()),
  149. f_(std::forward<F>(f))
  150. {
  151. }
  152. BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
  153. {
  154. BOOST_LEAF_ASSERT((err_id&3)==1);
  155. if( s_ )
  156. {
  157. if( E * e = s_->has_value(err_id) )
  158. (void) f_(*e);
  159. else
  160. (void) f_(s_->put(err_id, E()));
  161. }
  162. }
  163. };
  164. template <class... Item>
  165. class preloaded
  166. {
  167. preloaded & operator=( preloaded const & ) = delete;
  168. std::tuple<Item...> p_;
  169. bool moved_;
  170. error_monitor id_;
  171. public:
  172. BOOST_LEAF_CONSTEXPR explicit preloaded( Item && ... i ):
  173. p_(std::forward<Item>(i)...),
  174. moved_(false)
  175. {
  176. }
  177. BOOST_LEAF_CONSTEXPR preloaded( preloaded && x ) noexcept:
  178. p_(std::move(x.p_)),
  179. moved_(false),
  180. id_(std::move(x.id_))
  181. {
  182. x.moved_ = true;
  183. }
  184. ~preloaded() noexcept
  185. {
  186. if( moved_ )
  187. return;
  188. if( auto id = id_.check_id() )
  189. tuple_for_each_preload<sizeof...(Item),decltype(p_)>::trigger(p_,id);
  190. }
  191. };
  192. template <class T, int arity = function_traits<T>::arity>
  193. struct deduce_item_type;
  194. template <class T>
  195. struct deduce_item_type<T, -1>
  196. {
  197. using type = preloaded_item<T>;
  198. };
  199. template <class F>
  200. struct deduce_item_type<F, 0>
  201. {
  202. using type = deferred_item<F>;
  203. };
  204. template <class F>
  205. struct deduce_item_type<F, 1>
  206. {
  207. using type = accumulating_item<F>;
  208. };
  209. }
  210. template <class... Item>
  211. BOOST_LEAF_NODISCARD BOOST_LEAF_CONSTEXPR inline
  212. leaf_detail::preloaded<typename leaf_detail::deduce_item_type<Item>::type...>
  213. on_error( Item && ... i )
  214. {
  215. return leaf_detail::preloaded<typename leaf_detail::deduce_item_type<Item>::type...>(std::forward<Item>(i)...);
  216. }
  217. } }
  218. #endif