on_error.hpp 6.5 KB

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