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