exception_handler.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Copyright Andrey Semashev 2007 - 2015.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. /*!
  8. * \file exception_handler.hpp
  9. * \author Andrey Semashev
  10. * \date 12.07.2009
  11. *
  12. * This header contains tools for exception handlers support in different parts of the library.
  13. */
  14. #ifndef BOOST_LOG_UTILITY_EXCEPTION_HANDLER_HPP_INCLUDED_
  15. #define BOOST_LOG_UTILITY_EXCEPTION_HANDLER_HPP_INCLUDED_
  16. #include <new> // std::nothrow_t
  17. #include <boost/mpl/bind.hpp>
  18. #include <boost/mpl/quote.hpp>
  19. #include <boost/mpl/fold.hpp>
  20. #include <boost/mpl/placeholders.hpp>
  21. #include <boost/mpl/has_xxx.hpp>
  22. #include <boost/mpl/vector.hpp>
  23. #include <boost/core/enable_if.hpp>
  24. #include <boost/preprocessor/cat.hpp>
  25. #include <boost/preprocessor/repetition/enum_params.hpp>
  26. #include <boost/preprocessor/repetition/repeat_from_to.hpp>
  27. #include <boost/log/detail/config.hpp>
  28. #include <boost/log/utility/functional/nop.hpp>
  29. #include <boost/log/detail/header.hpp>
  30. #ifdef BOOST_HAS_PRAGMA_ONCE
  31. #pragma once
  32. #endif
  33. #ifndef BOOST_LOG_MAX_EXCEPTION_TYPES
  34. //! Maximum number of exception types that can be specified for exception handlers
  35. #define BOOST_LOG_MAX_EXCEPTION_TYPES 10
  36. #endif
  37. namespace boost {
  38. BOOST_LOG_OPEN_NAMESPACE
  39. namespace aux {
  40. BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_exception_types, exception_types, false)
  41. //! Root class for the exception handler class hierarchy
  42. template< typename HandlerT >
  43. class eh_root
  44. {
  45. public:
  46. //! The exception handler type
  47. typedef HandlerT handler_type;
  48. //! The handler result type
  49. typedef void result_type;
  50. protected:
  51. //! Exception handler
  52. handler_type m_Handler;
  53. public:
  54. //! Initializing constructor
  55. explicit eh_root(handler_type const& handler) : m_Handler(handler)
  56. {
  57. }
  58. //! Exception launcher
  59. void operator()() const
  60. {
  61. throw;
  62. }
  63. };
  64. //! A cons-list element of the exception handler class hierarchy
  65. template< typename ExceptionT, typename BaseT >
  66. class eh_cons :
  67. public BaseT
  68. {
  69. //! Base type
  70. typedef BaseT base_type;
  71. public:
  72. //! The exception handler type
  73. typedef typename base_type::handler_type handler_type;
  74. public:
  75. //! Initializing constructor
  76. explicit eh_cons(handler_type const& handler) : base_type(handler)
  77. {
  78. }
  79. //! Exception launcher
  80. void operator()() const
  81. {
  82. try
  83. {
  84. base_type::operator()();
  85. }
  86. catch (ExceptionT& e)
  87. {
  88. this->m_Handler(e);
  89. }
  90. }
  91. };
  92. template< template< typename, typename > class EHT, typename HandlerT >
  93. struct make_self_contained_exception_handler
  94. {
  95. typedef EHT< typename HandlerT::exception_types, HandlerT > type;
  96. };
  97. } // namespace aux
  98. /*!
  99. * An exception handler functional object. The handler aggregates a user-defined
  100. * functional object that will be called when one of the specified exception types
  101. * is caught.
  102. */
  103. template< typename SequenceT, typename HandlerT >
  104. class exception_handler :
  105. public mpl::fold<
  106. SequenceT,
  107. aux::eh_root< HandlerT >,
  108. mpl::bind< mpl::quote2< aux::eh_cons >, mpl::_2, mpl::_1 >
  109. >::type
  110. {
  111. //! Base type
  112. typedef typename mpl::fold<
  113. SequenceT,
  114. aux::eh_root< HandlerT >,
  115. mpl::bind< mpl::quote2< aux::eh_cons >, mpl::_2, mpl::_1 >
  116. >::type base_type;
  117. public:
  118. #ifndef BOOST_LOG_DOXYGEN_PASS
  119. typedef typename base_type::handler_type handler_type;
  120. #else
  121. //! The exception handler type
  122. typedef HandlerT handler_type;
  123. //! The handler result type
  124. typedef void result_type;
  125. #endif
  126. public:
  127. /*!
  128. * Initializing constructor. Creates an exception handler with the specified
  129. * function object that will receive the exception.
  130. */
  131. explicit exception_handler(handler_type const& handler) : base_type(handler)
  132. {
  133. }
  134. /*!
  135. * Exception launcher. Rethrows the current exception in order to detect its type
  136. * and pass it to the aggregated function object.
  137. *
  138. * \note Must be called from within a \c catch statement.
  139. */
  140. void operator()() const
  141. {
  142. base_type::operator()();
  143. }
  144. };
  145. /*!
  146. * A no-throw exception handler functional object. Acts similar to \c exception_handler,
  147. * but in case if the exception cannot be handled the exception is not propagated
  148. * from the handler. Instead the user-defined functional object is called with
  149. * no parameters.
  150. */
  151. template< typename SequenceT, typename HandlerT >
  152. class nothrow_exception_handler :
  153. public exception_handler< SequenceT, HandlerT >
  154. {
  155. //! Base type
  156. typedef exception_handler< SequenceT, HandlerT > base_type;
  157. public:
  158. #ifndef BOOST_LOG_DOXYGEN_PASS
  159. typedef typename base_type::handler_type handler_type;
  160. #else
  161. //! The exception handler type
  162. typedef HandlerT handler_type;
  163. //! The handler result type
  164. typedef void result_type;
  165. #endif
  166. public:
  167. /*!
  168. * Initializing constructor. Creates an exception handler with the specified
  169. * function object that will receive the exception.
  170. */
  171. explicit nothrow_exception_handler(handler_type const& handler) : base_type(handler)
  172. {
  173. }
  174. /*!
  175. * Exception launcher. Rethrows the current exception in order to detect its type
  176. * and pass it to the aggregated function object. If the type of the exception
  177. * could not be detected, the user-defined handler is called with no arguments.
  178. *
  179. * \note Must be called from within a \c catch statement.
  180. */
  181. void operator()() const
  182. {
  183. try
  184. {
  185. base_type::operator()();
  186. }
  187. catch (...)
  188. {
  189. this->m_Handler();
  190. }
  191. }
  192. };
  193. /*!
  194. * The function creates an empty exception handler that effectively suppresses any exception
  195. */
  196. inline nop make_exception_suppressor()
  197. {
  198. return nop();
  199. }
  200. #ifndef BOOST_LOG_DOXYGEN_PASS
  201. template< typename HandlerT >
  202. inline typename boost::lazy_enable_if_c<
  203. aux::has_exception_types< HandlerT >::value,
  204. aux::make_self_contained_exception_handler< exception_handler, HandlerT >
  205. >::type make_exception_handler(HandlerT const& handler)
  206. {
  207. typedef typename aux::make_self_contained_exception_handler< exception_handler, HandlerT >::type eh_t;
  208. return eh_t(handler);
  209. }
  210. template< typename HandlerT >
  211. inline typename boost::lazy_enable_if_c<
  212. aux::has_exception_types< HandlerT >::value,
  213. aux::make_self_contained_exception_handler< nothrow_exception_handler, HandlerT >
  214. >::type make_exception_handler(HandlerT const& handler, std::nothrow_t const&)
  215. {
  216. typedef typename aux::make_self_contained_exception_handler< nothrow_exception_handler, HandlerT >::type eh_t;
  217. return eh_t(handler);
  218. }
  219. #define BOOST_LOG_MAKE_EXCEPTION_HANDLER_INTERNAL(z, n, data)\
  220. template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T), typename HandlerT >\
  221. inline exception_handler<\
  222. BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\
  223. HandlerT\
  224. > make_exception_handler(HandlerT const& handler)\
  225. {\
  226. typedef exception_handler<\
  227. BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\
  228. HandlerT\
  229. > eh_t;\
  230. return eh_t(handler);\
  231. }\
  232. template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T), typename HandlerT >\
  233. inline nothrow_exception_handler<\
  234. BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\
  235. HandlerT\
  236. > make_exception_handler(HandlerT const& handler, std::nothrow_t const&)\
  237. {\
  238. typedef nothrow_exception_handler<\
  239. BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\
  240. HandlerT\
  241. > eh_t;\
  242. return eh_t(handler);\
  243. }
  244. BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_EXCEPTION_TYPES, BOOST_LOG_MAKE_EXCEPTION_HANDLER_INTERNAL, ~)
  245. #undef BOOST_LOG_MAKE_EXCEPTION_HANDLER_INTERNAL
  246. #else // BOOST_LOG_DOXYGEN_PASS
  247. /*!
  248. * The function creates an exception handler functional object. The handler will call to the
  249. * user-specified functional object with an exception as its argument.
  250. *
  251. * \param handler User-defined functional object that will receive exceptions.
  252. * \return A nullary functional object that should be called from within a \c catch statement.
  253. *
  254. * \note This form requires the user-defined functional object to have an \c exception_types
  255. * nested type. This type should be an MPL sequence of all expected exception types.
  256. */
  257. template< typename HandlerT >
  258. exception_handler< typename HandlerT::exception_types, HandlerT >
  259. make_exception_handler(HandlerT const& handler);
  260. /*!
  261. * The function creates an exception handler functional object. The handler will call to the
  262. * user-specified functional object with an exception as its argument. If the exception type
  263. * cannot be identified, the handler will call the user-defined functor with no arguments,
  264. * instead of propagating exception to the caller.
  265. *
  266. * \overload
  267. *
  268. * \param handler User-defined functional object that will receive exceptions.
  269. * \return A nullary functional object that should be called from within a \c catch statement.
  270. *
  271. * \note This form requires the user-defined functional object to have an \c exception_types
  272. * nested type. This type should be an MPL sequence of all expected exception types.
  273. */
  274. template< typename HandlerT >
  275. nothrow_exception_handler< typename HandlerT::exception_types, HandlerT >
  276. make_exception_handler(HandlerT const& handler, std::nothrow_t const&);
  277. /*!
  278. * The function creates an exception handler functional object. The handler will call to the
  279. * user-specified functional object with an exception as its argument. All expected exception
  280. * types should be specified as first template parameters explicitly, in the order they would
  281. * be specified in a corresponding <tt>try/catch</tt> statement.
  282. *
  283. * \overload
  284. *
  285. * \param handler User-defined functional object that will receive exceptions.
  286. * \return A nullary functional object that should be called from within a \c catch statement.
  287. */
  288. template< typename... ExceptionsT, typename HandlerT >
  289. exception_handler< MPL_sequence_of_ExceptionsT, HandlerT >
  290. make_exception_handler(HandlerT const& handler);
  291. /*!
  292. * The function creates an exception handler functional object. The handler will call to the
  293. * user-specified functional object with an exception as its argument. If the exception type
  294. * cannot be identified, the handler will call the user-defined functor with no arguments,
  295. * instead of propagating exception to the caller. All expected exception types should be
  296. * specified as first template parameters explicitly, in the order they would be specified in
  297. * a corresponding <tt>try/catch</tt> statement.
  298. *
  299. * \overload
  300. *
  301. * \param handler User-defined functional object that will receive exceptions.
  302. * \return A nullary functional object that should be called from within a \c catch statement.
  303. */
  304. template< typename... ExceptionsT, typename HandlerT >
  305. nothrow_exception_handler< MPL_sequence_of_ExceptionsT, HandlerT >
  306. make_exception_handler(HandlerT const& handler, std::nothrow_t const&);
  307. #endif // BOOST_LOG_DOXYGEN_PASS
  308. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  309. } // namespace boost
  310. #include <boost/log/detail/footer.hpp>
  311. #endif // BOOST_LOG_UTILITY_EXCEPTION_HANDLER_HPP_INCLUDED_