exception_ptr.hpp 15 KB

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