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 | boost |
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 boost::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: |
49 | exception_ptr() |
50 | { |
51 | } |
52 | explicit |
53 | exception_ptr( impl const & ptr ): |
54 | ptr_(ptr) |
55 | { |
56 | } |
57 | bool |
58 | operator==( exception_ptr const & other ) const |
59 | { |
60 | return ptr_==other.ptr_; |
61 | } |
62 | bool |
63 | operator!=( exception_ptr const & other ) const |
64 | { |
65 | return ptr_!=other.ptr_; |
66 | } |
67 | operator unspecified_bool_type() const |
68 | { |
69 | return ptr_?&impl::get:0; |
70 | } |
71 | }; |
72 | |
73 | template <class T> |
74 | inline |
75 | exception_ptr |
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 |
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 | boost::exception, |
106 | std::bad_alloc |
107 | { |
108 | ~bad_alloc_() throw() { } |
109 | }; |
110 | |
111 | struct |
112 | bad_exception_: |
113 | boost::exception, |
114 | std::bad_exception |
115 | { |
116 | ~bad_exception_() throw() { } |
117 | }; |
118 | |
119 | template <class Exception> |
120 | exception_ptr |
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 boost::exception, |
156 | public std::exception |
157 | { |
158 | public: |
159 | |
160 | unknown_exception() |
161 | { |
162 | } |
163 | |
164 | explicit |
165 | unknown_exception( std::exception const & e ) |
166 | { |
167 | add_original_type(e); |
168 | } |
169 | |
170 | explicit |
171 | unknown_exception( boost::exception const & e ): |
172 | boost::exception(e) |
173 | { |
174 | add_original_type(e); |
175 | } |
176 | |
177 | ~unknown_exception() throw() |
178 | { |
179 | } |
180 | |
181 | private: |
182 | |
183 | template <class E> |
184 | void |
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 boost::exception |
206 | { |
207 | public: |
208 | |
209 | explicit |
210 | current_exception_std_exception_wrapper( T const & e1 ): |
211 | T(e1) |
212 | { |
213 | add_original_type(e1); |
214 | } |
215 | |
216 | current_exception_std_exception_wrapper( T const & e1, boost::exception const & e2 ): |
217 | T(e1), |
218 | boost::exception(e2) |
219 | { |
220 | add_original_type(e1); |
221 | } |
222 | |
223 | ~current_exception_std_exception_wrapper() throw() |
224 | { |
225 | } |
226 | |
227 | private: |
228 | |
229 | template <class E> |
230 | void |
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 | boost::exception const * |
242 | get_boost_exception( T const * ) |
243 | { |
244 | try |
245 | { |
246 | throw; |
247 | } |
248 | catch( |
249 | boost::exception & x ) |
250 | { |
251 | return &x; |
252 | } |
253 | catch(...) |
254 | { |
255 | return 0; |
256 | } |
257 | } |
258 | #else |
259 | template <class T> |
260 | boost::exception const * |
261 | get_boost_exception( T const * x ) |
262 | { |
263 | return dynamic_cast<boost::exception const *>(x); |
264 | } |
265 | #endif |
266 | |
267 | template <class T> |
268 | inline |
269 | exception_ptr |
270 | current_exception_std_exception( T const & e1 ) |
271 | { |
272 | if( boost::exception const * e2 = get_boost_exception(&e1) ) |
273 | return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1,*e2)); |
274 | else |
275 | return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1)); |
276 | } |
277 | |
278 | inline |
279 | exception_ptr |
280 | current_exception_unknown_exception() |
281 | { |
282 | return boost::copy_exception(unknown_exception()); |
283 | } |
284 | |
285 | inline |
286 | exception_ptr |
287 | current_exception_unknown_boost_exception( boost::exception const & e ) |
288 | { |
289 | return boost::copy_exception(unknown_exception(e)); |
290 | } |
291 | |
292 | inline |
293 | exception_ptr |
294 | current_exception_unknown_std_exception( std::exception const & e ) |
295 | { |
296 | if( boost::exception const * be = get_boost_exception(&e) ) |
297 | return current_exception_unknown_boost_exception(*be); |
298 | else |
299 | return boost::copy_exception(unknown_exception(e)); |
300 | } |
301 | |
302 | inline |
303 | exception_ptr |
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 | boost::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 |
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 |
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 |
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 |
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 | |