summaryrefslogtreecommitdiff
path: root/boost/log/utility/exception_handler.hpp
blob: 6b369704d128d92523c00534aed91830ce9391a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
/*
 *          Copyright Andrey Semashev 2007 - 2015.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   exception_handler.hpp
 * \author Andrey Semashev
 * \date   12.07.2009
 *
 * This header contains tools for exception handlers support in different parts of the library.
 */

#ifndef BOOST_LOG_UTILITY_EXCEPTION_HANDLER_HPP_INCLUDED_
#define BOOST_LOG_UTILITY_EXCEPTION_HANDLER_HPP_INCLUDED_

#include <new> // std::nothrow_t
#include <boost/mpl/bind.hpp>
#include <boost/mpl/quote.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/utility/functional/nop.hpp>
#include <boost/log/detail/header.hpp>

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

#ifndef BOOST_LOG_MAX_EXCEPTION_TYPES
//! Maximum number of exception types that can be specified for exception handlers
#define BOOST_LOG_MAX_EXCEPTION_TYPES 10
#endif

namespace boost {

BOOST_LOG_OPEN_NAMESPACE

namespace aux {

BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_exception_types, exception_types, false)

//! Root class for the exception handler class hierarchy
template< typename HandlerT >
class eh_root
{
public:
    //! The exception handler type
    typedef HandlerT handler_type;
    //! The handler result type
    typedef void result_type;

protected:
    //! Exception handler
    handler_type m_Handler;

public:
    //! Initializing constructor
    explicit eh_root(handler_type const& handler) : m_Handler(handler)
    {
    }

    //! Exception launcher
    void operator()() const
    {
        throw;
    }
};

//! A cons-list element of the exception handler class hierarchy
template< typename ExceptionT, typename BaseT >
class eh_cons :
    public BaseT
{
    //! Base type
    typedef BaseT base_type;

public:
    //! The exception handler type
    typedef typename base_type::handler_type handler_type;

public:
    //! Initializing constructor
    explicit eh_cons(handler_type const& handler) : base_type(handler)
    {
    }

    //! Exception launcher
    void operator()() const
    {
        try
        {
            base_type::operator()();
        }
        catch (ExceptionT& e)
        {
            this->m_Handler(e);
        }
    }
};

template< template< typename, typename > class EHT, typename HandlerT >
struct make_self_contained_exception_handler
{
    typedef EHT< typename HandlerT::exception_types, HandlerT > type;
};

} // namespace aux

/*!
 * An exception handler functional object. The handler aggregates a user-defined
 * functional object that will be called when one of the specified exception types
 * is caught.
 */
template< typename SequenceT, typename HandlerT >
class exception_handler :
    public mpl::fold<
        SequenceT,
        aux::eh_root< HandlerT >,
        mpl::bind< mpl::quote2< aux::eh_cons >, mpl::_2, mpl::_1 >
    >::type
{
    //! Base type
    typedef typename mpl::fold<
        SequenceT,
        aux::eh_root< HandlerT >,
        mpl::bind< mpl::quote2< aux::eh_cons >, mpl::_2, mpl::_1 >
    >::type base_type;

public:
#ifndef BOOST_LOG_DOXYGEN_PASS
    typedef typename base_type::handler_type handler_type;
#else
    //! The exception handler type
    typedef HandlerT handler_type;
    //! The handler result type
    typedef void result_type;
#endif

public:
    /*!
     * Initializing constructor. Creates an exception handler with the specified
     * function object that will receive the exception.
     */
    explicit exception_handler(handler_type const& handler) : base_type(handler)
    {
    }

    /*!
     * Exception launcher. Rethrows the current exception in order to detect its type
     * and pass it to the aggregated function object.
     *
     * \note Must be called from within a \c catch statement.
     */
    void operator()() const
    {
        base_type::operator()();
    }
};

/*!
 * A no-throw exception handler functional object. Acts similar to \c exception_handler,
 * but in case if the exception cannot be handled the exception is not propagated
 * from the handler. Instead the user-defined functional object is called with
 * no parameters.
 */
template< typename SequenceT, typename HandlerT >
class nothrow_exception_handler :
    public exception_handler< SequenceT, HandlerT >
{
    //! Base type
    typedef exception_handler< SequenceT, HandlerT > base_type;

public:
#ifndef BOOST_LOG_DOXYGEN_PASS
    typedef typename base_type::handler_type handler_type;
#else
    //! The exception handler type
    typedef HandlerT handler_type;
    //! The handler result type
    typedef void result_type;
#endif

public:
    /*!
     * Initializing constructor. Creates an exception handler with the specified
     * function object that will receive the exception.
     */
    explicit nothrow_exception_handler(handler_type const& handler) : base_type(handler)
    {
    }

    /*!
     * Exception launcher. Rethrows the current exception in order to detect its type
     * and pass it to the aggregated function object. If the type of the exception
     * could not be detected, the user-defined handler is called with no arguments.
     *
     * \note Must be called from within a \c catch statement.
     */
    void operator()() const
    {
        try
        {
            base_type::operator()();
        }
        catch (...)
        {
            this->m_Handler();
        }
    }
};

/*!
 * The function creates an empty exception handler that effectively suppresses any exception
 */
inline nop make_exception_suppressor()
{
    return nop();
}

#ifndef BOOST_LOG_DOXYGEN_PASS

template< typename HandlerT >
inline typename lazy_enable_if<
    aux::has_exception_types< HandlerT >,
    aux::make_self_contained_exception_handler< exception_handler, HandlerT >
>::type make_exception_handler(HandlerT const& handler)
{
    typedef typename aux::make_self_contained_exception_handler< exception_handler, HandlerT >::type eh_t;
    return eh_t(handler);
}

template< typename HandlerT >
inline typename lazy_enable_if<
    aux::has_exception_types< HandlerT >,
    aux::make_self_contained_exception_handler< nothrow_exception_handler, HandlerT >
>::type make_exception_handler(HandlerT const& handler, std::nothrow_t const&)
{
    typedef typename aux::make_self_contained_exception_handler< nothrow_exception_handler, HandlerT >::type eh_t;
    return eh_t(handler);
}

#define BOOST_LOG_MAKE_EXCEPTION_HANDLER_INTERNAL(z, n, data)\
    template< BOOST_PP_ENUM_PARAMS(n, typename T), typename HandlerT >\
    inline exception_handler<\
        BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\
        HandlerT\
    > make_exception_handler(HandlerT const& handler)\
    {\
        typedef exception_handler<\
            BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\
            HandlerT\
        > eh_t;\
        return eh_t(handler);\
    }\
    template< BOOST_PP_ENUM_PARAMS(n, typename T), typename HandlerT >\
    inline nothrow_exception_handler<\
        BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\
        HandlerT\
    > make_exception_handler(HandlerT const& handler, std::nothrow_t const&)\
    {\
        typedef nothrow_exception_handler<\
            BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\
            HandlerT\
        > eh_t;\
        return eh_t(handler);\
    }

BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_EXCEPTION_TYPES, BOOST_LOG_MAKE_EXCEPTION_HANDLER_INTERNAL, ~)

#undef BOOST_LOG_MAKE_EXCEPTION_HANDLER_INTERNAL

#else // BOOST_LOG_DOXYGEN_PASS

/*!
 * The function creates an exception handler functional object. The handler will call to the
 * user-specified functional object with an exception as its argument.
 *
 * \param handler User-defined functional object that will receive exceptions.
 * \return A nullary functional object that should be called from within a \c catch statement.
 *
 * \note This form requires the user-defined functional object to have an \c exception_types
 *       nested type. This type should be an MPL sequence of all expected exception types.
 */
template< typename HandlerT >
exception_handler< typename HandlerT::exception_types, HandlerT >
make_exception_handler(HandlerT const& handler);

/*!
 * The function creates an exception handler functional object. The handler will call to the
 * user-specified functional object with an exception as its argument. If the exception type
 * cannot be identified, the handler will call the user-defined functor with no arguments,
 * instead of propagating exception to the caller.
 *
 * \overload
 *
 * \param handler User-defined functional object that will receive exceptions.
 * \return A nullary functional object that should be called from within a \c catch statement.
 *
 * \note This form requires the user-defined functional object to have an \c exception_types
 *       nested type. This type should be an MPL sequence of all expected exception types.
 */
template< typename HandlerT >
nothrow_exception_handler< typename HandlerT::exception_types, HandlerT >
make_exception_handler(HandlerT const& handler, std::nothrow_t const&);

/*!
 * The function creates an exception handler functional object. The handler will call to the
 * user-specified functional object with an exception as its argument. All expected exception
 * types should be specified as first template parameters explicitly, in the order they would
 * be specified in a corresponding <tt>try/catch</tt> statement.
 *
 * \overload
 *
 * \param handler User-defined functional object that will receive exceptions.
 * \return A nullary functional object that should be called from within a \c catch statement.
 */
template< typename... ExceptionsT, typename HandlerT >
exception_handler< MPL_sequence_of_ExceptionsT, HandlerT >
make_exception_handler(HandlerT const& handler);

/*!
 * The function creates an exception handler functional object. The handler will call to the
 * user-specified functional object with an exception as its argument. If the exception type
 * cannot be identified, the handler will call the user-defined functor with no arguments,
 * instead of propagating exception to the caller. All expected exception types should be
 * specified as first template parameters explicitly, in the order they would be specified in
 * a corresponding <tt>try/catch</tt> statement.
 *
 * \overload
 *
 * \param handler User-defined functional object that will receive exceptions.
 * \return A nullary functional object that should be called from within a \c catch statement.
 */
template< typename... ExceptionsT, typename HandlerT >
nothrow_exception_handler< MPL_sequence_of_ExceptionsT, HandlerT >
make_exception_handler(HandlerT const& handler, std::nothrow_t const&);

#endif // BOOST_LOG_DOXYGEN_PASS

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>

#endif // BOOST_LOG_UTILITY_EXCEPTION_HANDLER_HPP_INCLUDED_