exception.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED
  2. #define BOOST_LEAF_EXCEPTION_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/error.hpp>
  8. #include <exception>
  9. #ifdef BOOST_LEAF_NO_EXCEPTIONS
  10. namespace boost
  11. {
  12. [[noreturn]] void throw_exception( std::exception const & ); // user defined
  13. }
  14. namespace boost { namespace leaf {
  15. namespace leaf_detail
  16. {
  17. template <class T>
  18. [[noreturn]] void throw_exception_impl( T && e )
  19. {
  20. ::boost::throw_exception(std::move(e));
  21. }
  22. class BOOST_LEAF_SYMBOL_VISIBLE exception_base
  23. {
  24. public:
  25. virtual error_id get_error_id() const noexcept = 0;
  26. protected:
  27. exception_base() noexcept { }
  28. ~exception_base() noexcept { }
  29. };
  30. }
  31. } }
  32. #else
  33. #include <memory>
  34. namespace boost { namespace leaf {
  35. namespace leaf_detail
  36. {
  37. template <class T>
  38. [[noreturn]] void throw_exception_impl( T && e )
  39. {
  40. throw std::move(e);
  41. }
  42. class BOOST_LEAF_SYMBOL_VISIBLE exception_base
  43. {
  44. std::shared_ptr<void const> auto_id_bump_;
  45. public:
  46. virtual error_id get_error_id() const noexcept = 0;
  47. protected:
  48. exception_base():
  49. auto_id_bump_(nullptr, [](void const *) { (void) new_id(); })
  50. {
  51. }
  52. ~exception_base() noexcept { }
  53. };
  54. }
  55. } }
  56. #endif
  57. ////////////////////////////////////////
  58. #define BOOST_LEAF_THROW_EXCEPTION ::boost::leaf::leaf_detail::throw_with_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::leaf_detail::make_exception
  59. namespace boost { namespace leaf {
  60. namespace leaf_detail
  61. {
  62. struct throw_with_loc
  63. {
  64. char const * const file;
  65. int const line;
  66. char const * const fn;
  67. template <class Ex>
  68. [[noreturn]] friend void operator+( throw_with_loc loc, Ex && ex )
  69. {
  70. ex.load_source_location_(loc.file, loc.line, loc.fn);
  71. ::boost::leaf::leaf_detail::throw_exception_impl(std::move(ex));
  72. }
  73. };
  74. }
  75. } }
  76. ////////////////////////////////////////
  77. namespace boost { namespace leaf {
  78. namespace leaf_detail
  79. {
  80. inline void enforce_std_exception( std::exception const & ) noexcept { }
  81. template <class Ex>
  82. class BOOST_LEAF_SYMBOL_VISIBLE exception:
  83. public Ex,
  84. public exception_base,
  85. public error_id
  86. {
  87. error_id get_error_id() const noexcept final override
  88. {
  89. return *this;
  90. }
  91. public:
  92. exception( exception const & ) = default;
  93. exception( exception && ) = default;
  94. BOOST_LEAF_CONSTEXPR exception( error_id id, Ex const & ex ) noexcept:
  95. Ex(ex),
  96. error_id(id)
  97. {
  98. enforce_std_exception(*this);
  99. }
  100. BOOST_LEAF_CONSTEXPR exception( error_id id, Ex && ex ) noexcept:
  101. Ex(std::move(ex)),
  102. error_id(id)
  103. {
  104. enforce_std_exception(*this);
  105. }
  106. explicit BOOST_LEAF_CONSTEXPR exception( error_id id ) noexcept:
  107. error_id(id)
  108. {
  109. enforce_std_exception(*this);
  110. }
  111. };
  112. template <class... T>
  113. struct at_least_one_derives_from_std_exception;
  114. template <>
  115. struct at_least_one_derives_from_std_exception<>: std::false_type { };
  116. template <class T, class... Rest>
  117. struct at_least_one_derives_from_std_exception<T, Rest...>
  118. {
  119. constexpr static const bool value = std::is_base_of<std::exception,typename std::remove_reference<T>::type>::value || at_least_one_derives_from_std_exception<Rest...>::value;
  120. };
  121. template <class Ex, class... E>
  122. inline
  123. typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
  124. make_exception( error_id err, Ex && ex, E && ... e ) noexcept
  125. {
  126. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  127. return exception<typename std::remove_reference<Ex>::type>( err.load(std::forward<E>(e)...), std::forward<Ex>(ex) );
  128. }
  129. template <class E1, class... E>
  130. inline
  131. typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
  132. make_exception( error_id err, E1 && car, E && ... cdr ) noexcept
  133. {
  134. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  135. return exception<std::exception>( err.load(std::forward<E1>(car), std::forward<E>(cdr)...) );
  136. }
  137. inline exception<std::exception> make_exception( error_id err ) noexcept
  138. {
  139. return exception<std::exception>(err);
  140. }
  141. template <class Ex, class... E>
  142. inline
  143. typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
  144. make_exception( Ex && ex, E && ... e ) noexcept
  145. {
  146. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  147. return exception<typename std::remove_reference<Ex>::type>( new_error().load(std::forward<E>(e)...), std::forward<Ex>(ex) );
  148. }
  149. template <class E1, class... E>
  150. inline
  151. typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
  152. make_exception( E1 && car, E && ... cdr ) noexcept
  153. {
  154. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  155. return exception<std::exception>( new_error().load(std::forward<E1>(car), std::forward<E>(cdr)...) );
  156. }
  157. inline exception<std::exception> make_exception() noexcept
  158. {
  159. return exception<std::exception>(leaf::new_error());
  160. }
  161. }
  162. template <class... E>
  163. [[noreturn]] void throw_exception( E && ... e )
  164. {
  165. // Warning: setting a breakpoint here will not intercept exceptions thrown
  166. // via BOOST_LEAF_THROW_EXCEPTION or originating in the few other throw
  167. // points elsewhere in LEAF. To intercept all of those exceptions as well,
  168. // set a breakpoint inside boost::leaf::leaf_detail::throw_exception_impl.
  169. leaf_detail::throw_exception_impl(leaf_detail::make_exception(std::forward<E>(e)...));
  170. }
  171. ////////////////////////////////////////
  172. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  173. template <class T>
  174. class result;
  175. namespace leaf_detail
  176. {
  177. inline error_id catch_exceptions_helper( std::exception const &, leaf_detail_mp11::mp_list<> )
  178. {
  179. return leaf::new_error(std::current_exception());
  180. }
  181. template <class Ex1, class... Ex>
  182. inline error_id catch_exceptions_helper( std::exception const & ex, leaf_detail_mp11::mp_list<Ex1,Ex...> )
  183. {
  184. if( Ex1 const * p = dynamic_cast<Ex1 const *>(&ex) )
  185. return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ }).load(*p);
  186. else
  187. return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ });
  188. }
  189. template <class T>
  190. struct deduce_exception_to_result_return_type_impl
  191. {
  192. using type = result<T>;
  193. };
  194. template <class T>
  195. struct deduce_exception_to_result_return_type_impl<result<T>>
  196. {
  197. using type = result<T>;
  198. };
  199. template <class T>
  200. using deduce_exception_to_result_return_type = typename deduce_exception_to_result_return_type_impl<T>::type;
  201. }
  202. template <class... Ex, class F>
  203. inline
  204. leaf_detail::deduce_exception_to_result_return_type<leaf_detail::fn_return_type<F>>
  205. exception_to_result( F && f ) noexcept
  206. {
  207. try
  208. {
  209. return std::forward<F>(f)();
  210. }
  211. catch( std::exception const & ex )
  212. {
  213. return leaf_detail::catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>());
  214. }
  215. catch(...)
  216. {
  217. return leaf::new_error(std::current_exception());
  218. }
  219. }
  220. #endif
  221. } }
  222. #endif