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