1 //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
2 
3 //Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef UUID_618474C2DE1511DEB74A388C56D89593
7 #define UUID_618474C2DE1511DEB74A388C56D89593
8 #if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
9 #pragma GCC system_header
10 #endif
11 #if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
12 #pragma warning(push,1)
13 #endif
14 
15 #include <boost/config.hpp>
16 #ifdef BOOST_NO_EXCEPTIONS
17 #error This header requires exception handling to be enabled.
18 #endif
19 #include <boost/exception/exception.hpp>
20 #include <boost/exception/info.hpp>
21 #include <boost/exception/diagnostic_information.hpp>
22 #include <boost/exception/detail/type_info.hpp>
23 #include <boost/exception/detail/clone_current_exception.hpp>
24 #ifndef BOOST_NO_RTTI
25 #include <boost/core/demangle.hpp>
26 #endif
27 #include <boost/shared_ptr.hpp>
28 #include <stdexcept>
29 #include <new>
30 #include <ios>
31 #include <stdlib.h>
32 
33 namespace
34 boost
35     {
36     class exception_ptr;
37     BOOST_NORETURN void rethrow_exception( exception_ptr const & );
38     exception_ptr current_exception();
39 
40     class
41     exception_ptr
42         {
43         typedef boost::shared_ptr<exception_detail::clone_base const> impl;
44         impl ptr_;
45         friend void rethrow_exception( exception_ptr const & );
46         typedef exception_detail::clone_base const * (impl::*unspecified_bool_type)() const;
47         public:
exception_ptr()48         exception_ptr()
49             {
50             }
51         explicit
exception_ptr(impl const & ptr)52         exception_ptr( impl const & ptr ):
53             ptr_(ptr)
54             {
55             }
56         bool
operator ==(exception_ptr const & other) const57         operator==( exception_ptr const & other ) const
58             {
59             return ptr_==other.ptr_;
60             }
61         bool
operator !=(exception_ptr const & other) const62         operator!=( exception_ptr const & other ) const
63             {
64             return ptr_!=other.ptr_;
65             }
operator unspecified_bool_type() const66         operator unspecified_bool_type() const
67             {
68             return ptr_?&impl::get:0;
69             }
70         };
71 
72     template <class T>
73     inline
74     exception_ptr
copy_exception(T const & e)75     copy_exception( T const & e )
76         {
77         try
78             {
79             throw enable_current_exception(e);
80             }
81         catch(
82         ... )
83             {
84             return current_exception();
85             }
86         }
87 
88 #ifndef BOOST_NO_RTTI
89     typedef error_info<struct tag_original_exception_type,std::type_info const *> original_exception_type;
90 
91     inline
92     std::string
to_string(original_exception_type const & x)93     to_string( original_exception_type const & x )
94         {
95         return core::demangle(x.value()->name());
96         }
97 #endif
98 
99     namespace
100     exception_detail
101         {
102         struct
103         bad_alloc_:
104             boost::exception,
105             std::bad_alloc
106                 {
~bad_alloc_boost::exception_detail::bad_alloc_107                 ~bad_alloc_() throw() { }
108                 };
109 
110         struct
111         bad_exception_:
112             boost::exception,
113             std::bad_exception
114                 {
~bad_exception_boost::exception_detail::bad_exception_115                 ~bad_exception_() throw() { }
116                 };
117 
118         template <class Exception>
119         exception_ptr
get_static_exception_object()120         get_static_exception_object()
121             {
122             Exception ba;
123             exception_detail::clone_impl<Exception> c(ba);
124 #ifndef BOOST_EXCEPTION_DISABLE
125             c <<
126                 throw_function(BOOST_CURRENT_FUNCTION) <<
127                 throw_file(__FILE__) <<
128                 throw_line(__LINE__);
129 #endif
130             static exception_ptr ep(shared_ptr<exception_detail::clone_base const>(new exception_detail::clone_impl<Exception>(c)));
131             return ep;
132             }
133 
134         template <class Exception>
135         struct
136         exception_ptr_static_exception_object
137             {
138             static exception_ptr const e;
139             };
140 
141         template <class Exception>
142         exception_ptr const
143         exception_ptr_static_exception_object<Exception>::
144         e = get_static_exception_object<Exception>();
145         }
146 
147 #if defined(__GNUC__)
148 # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
149 #  pragma GCC visibility push (default)
150 # endif
151 #endif
152     class
153     unknown_exception:
154         public boost::exception,
155         public std::exception
156         {
157         public:
158 
unknown_exception()159         unknown_exception()
160             {
161             }
162 
163         explicit
unknown_exception(std::exception const & e)164         unknown_exception( std::exception const & e )
165             {
166             add_original_type(e);
167             }
168 
169         explicit
unknown_exception(boost::exception const & e)170         unknown_exception( boost::exception const & e ):
171             boost::exception(e)
172             {
173             add_original_type(e);
174             }
175 
~unknown_exception()176         ~unknown_exception() throw()
177             {
178             }
179 
180         private:
181 
182         template <class E>
183         void
add_original_type(E const & e)184         add_original_type( E const & e )
185             {
186 #ifndef BOOST_NO_RTTI
187             (*this) << original_exception_type(&typeid(e));
188 #endif
189             }
190         };
191 #if defined(__GNUC__)
192 # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
193 #  pragma GCC visibility pop
194 # endif
195 #endif
196 
197     namespace
198     exception_detail
199         {
200         template <class T>
201         class
202         current_exception_std_exception_wrapper:
203             public T,
204             public boost::exception
205             {
206             public:
207 
208             explicit
current_exception_std_exception_wrapper(T const & e1)209             current_exception_std_exception_wrapper( T const & e1 ):
210                 T(e1)
211                 {
212                 add_original_type(e1);
213                 }
214 
current_exception_std_exception_wrapper(T const & e1,boost::exception const & e2)215             current_exception_std_exception_wrapper( T const & e1, boost::exception const & e2 ):
216                 T(e1),
217                 boost::exception(e2)
218                 {
219                 add_original_type(e1);
220                 }
221 
~current_exception_std_exception_wrapper()222             ~current_exception_std_exception_wrapper() throw()
223                 {
224                 }
225 
226             private:
227 
228             template <class E>
229             void
add_original_type(E const & e)230             add_original_type( E const & e )
231                 {
232 #ifndef BOOST_NO_RTTI
233                 (*this) << original_exception_type(&typeid(e));
234 #endif
235                 }
236             };
237 
238 #ifdef BOOST_NO_RTTI
239         template <class T>
240         boost::exception const *
get_boost_exception(T const *)241         get_boost_exception( T const * )
242             {
243             try
244                 {
245                 throw;
246                 }
247             catch(
248             boost::exception & x )
249                 {
250                 return &x;
251                 }
252             catch(...)
253                 {
254                 return 0;
255                 }
256             }
257 #else
258         template <class T>
259         boost::exception const *
get_boost_exception(T const * x)260         get_boost_exception( T const * x )
261             {
262             return dynamic_cast<boost::exception const *>(x);
263             }
264 #endif
265 
266         template <class T>
267         inline
268         exception_ptr
current_exception_std_exception(T const & e1)269         current_exception_std_exception( T const & e1 )
270             {
271             if( boost::exception const * e2 = get_boost_exception(&e1) )
272                 return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1,*e2));
273             else
274                 return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1));
275             }
276 
277         inline
278         exception_ptr
current_exception_unknown_exception()279         current_exception_unknown_exception()
280             {
281             return boost::copy_exception(unknown_exception());
282             }
283 
284         inline
285         exception_ptr
current_exception_unknown_boost_exception(boost::exception const & e)286         current_exception_unknown_boost_exception( boost::exception const & e )
287             {
288             return boost::copy_exception(unknown_exception(e));
289             }
290 
291         inline
292         exception_ptr
current_exception_unknown_std_exception(std::exception const & e)293         current_exception_unknown_std_exception( std::exception const & e )
294             {
295             if( boost::exception const * be = get_boost_exception(&e) )
296                 return current_exception_unknown_boost_exception(*be);
297             else
298                 return boost::copy_exception(unknown_exception(e));
299             }
300 
301         inline
302         exception_ptr
current_exception_impl()303         current_exception_impl()
304             {
305             exception_detail::clone_base const * e=0;
306             switch(
307             exception_detail::clone_current_exception(e) )
308                 {
309                 case exception_detail::clone_current_exception_result::
310                 success:
311                     {
312                     BOOST_ASSERT(e!=0);
313                     return exception_ptr(shared_ptr<exception_detail::clone_base const>(e));
314                     }
315                 case exception_detail::clone_current_exception_result::
316                 bad_alloc:
317                     {
318                     BOOST_ASSERT(!e);
319                     return exception_detail::exception_ptr_static_exception_object<bad_alloc_>::e;
320                     }
321                 case exception_detail::clone_current_exception_result::
322                 bad_exception:
323                     {
324                     BOOST_ASSERT(!e);
325                     return exception_detail::exception_ptr_static_exception_object<bad_exception_>::e;
326                     }
327                 default:
328                     BOOST_ASSERT(0);
329                 case exception_detail::clone_current_exception_result::
330                 not_supported:
331                     {
332                     BOOST_ASSERT(!e);
333                     try
334                         {
335                         throw;
336                         }
337                     catch(
338                     exception_detail::clone_base & e )
339                         {
340                         return exception_ptr(shared_ptr<exception_detail::clone_base const>(e.clone()));
341                         }
342                     catch(
343                     std::domain_error & e )
344                         {
345                         return exception_detail::current_exception_std_exception(e);
346                         }
347                     catch(
348                     std::invalid_argument & e )
349                         {
350                         return exception_detail::current_exception_std_exception(e);
351                         }
352                     catch(
353                     std::length_error & e )
354                         {
355                         return exception_detail::current_exception_std_exception(e);
356                         }
357                     catch(
358                     std::out_of_range & e )
359                         {
360                         return exception_detail::current_exception_std_exception(e);
361                         }
362                     catch(
363                     std::logic_error & e )
364                         {
365                         return exception_detail::current_exception_std_exception(e);
366                         }
367                     catch(
368                     std::range_error & e )
369                         {
370                         return exception_detail::current_exception_std_exception(e);
371                         }
372                     catch(
373                     std::overflow_error & e )
374                         {
375                         return exception_detail::current_exception_std_exception(e);
376                         }
377                     catch(
378                     std::underflow_error & e )
379                         {
380                         return exception_detail::current_exception_std_exception(e);
381                         }
382                     catch(
383                     std::ios_base::failure & e )
384                         {
385                         return exception_detail::current_exception_std_exception(e);
386                         }
387                     catch(
388                     std::runtime_error & e )
389                         {
390                         return exception_detail::current_exception_std_exception(e);
391                         }
392                     catch(
393                     std::bad_alloc & e )
394                         {
395                         return exception_detail::current_exception_std_exception(e);
396                         }
397 #ifndef BOOST_NO_TYPEID
398                     catch(
399                     std::bad_cast & e )
400                         {
401                         return exception_detail::current_exception_std_exception(e);
402                         }
403                     catch(
404                     std::bad_typeid & e )
405                         {
406                         return exception_detail::current_exception_std_exception(e);
407                         }
408 #endif
409                     catch(
410                     std::bad_exception & e )
411                         {
412                         return exception_detail::current_exception_std_exception(e);
413                         }
414                     catch(
415                     std::exception & e )
416                         {
417                         return exception_detail::current_exception_unknown_std_exception(e);
418                         }
419                     catch(
420                     boost::exception & e )
421                         {
422                         return exception_detail::current_exception_unknown_boost_exception(e);
423                         }
424                     catch(
425                     ... )
426                         {
427                         return exception_detail::current_exception_unknown_exception();
428                         }
429                     }
430                 }
431             }
432         }
433 
434     inline
435     exception_ptr
current_exception()436     current_exception()
437         {
438         exception_ptr ret;
439         try
440             {
441             ret=exception_detail::current_exception_impl();
442             }
443         catch(
444         std::bad_alloc & )
445             {
446             ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_alloc_>::e;
447             }
448         catch(
449         ... )
450             {
451             ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_exception_>::e;
452             }
453         BOOST_ASSERT(ret);
454         return ret;
455         }
456 
457     BOOST_NORETURN
458     inline
459     void
rethrow_exception(exception_ptr const & p)460     rethrow_exception( exception_ptr const & p )
461         {
462         BOOST_ASSERT(p);
463         p.ptr_->rethrow();
464         BOOST_ASSERT(0);
465         #if defined(UNDER_CE)
466             // some CE platforms don't define ::abort()
467             exit(-1);
468         #else
469             abort();
470         #endif
471         }
472 
473     inline
474     std::string
diagnostic_information(exception_ptr const & p,bool verbose=true)475     diagnostic_information( exception_ptr const & p, bool verbose=true )
476         {
477         if( p )
478             try
479                 {
480                 rethrow_exception(p);
481                 }
482             catch(
483             ... )
484                 {
485                 return current_exception_diagnostic_information(verbose);
486                 }
487         return "<empty>";
488         }
489 
490     inline
491     std::string
to_string(exception_ptr const & p)492     to_string( exception_ptr const & p )
493         {
494         std::string s='\n'+diagnostic_information(p);
495         std::string padding("  ");
496         std::string r;
497         bool f=false;
498         for( std::string::const_iterator i=s.begin(),e=s.end(); i!=e; ++i )
499             {
500             if( f )
501                 r+=padding;
502             char c=*i;
503             r+=c;
504             f=(c=='\n');
505             }
506         return r;
507         }
508     }
509 
510 #if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
511 #pragma warning(pop)
512 #endif
513 #endif
514