handle_errors.hpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. #ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
  2. #define BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
  3. // Copyright 2018-2023 Emil Dotchevski and Reverge Studios, Inc.
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #include <boost/leaf/config.hpp>
  7. #include <boost/leaf/context.hpp>
  8. namespace boost { namespace leaf {
  9. template <class T>
  10. class BOOST_LEAF_SYMBOL_VISIBLE result;
  11. ////////////////////////////////////////
  12. class BOOST_LEAF_SYMBOL_VISIBLE error_info
  13. {
  14. error_info & operator=( error_info const & ) = delete;
  15. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  16. static error_id unpack_error_id( std::exception const * ex ) noexcept
  17. {
  18. if( error_id const * err_id = dynamic_cast<error_id const *>(ex) )
  19. return *err_id;
  20. return current_error();
  21. }
  22. std::exception * const ex_;
  23. #endif
  24. error_id const err_id_;
  25. protected:
  26. error_info( error_info const & ) noexcept = default;
  27. public:
  28. BOOST_LEAF_CONSTEXPR explicit error_info( error_id id ) noexcept:
  29. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  30. ex_(nullptr),
  31. #endif
  32. err_id_(id)
  33. {
  34. }
  35. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  36. explicit error_info( std::exception * ex ) noexcept:
  37. ex_(ex),
  38. err_id_(unpack_error_id(ex_))
  39. {
  40. }
  41. #endif
  42. BOOST_LEAF_CONSTEXPR error_id error() const noexcept
  43. {
  44. return err_id_;
  45. }
  46. BOOST_LEAF_CONSTEXPR std::exception * exception() const noexcept
  47. {
  48. #ifdef BOOST_LEAF_NO_EXCEPTIONS
  49. return nullptr;
  50. #else
  51. return ex_;
  52. #endif
  53. }
  54. template <class CharT, class Traits>
  55. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, error_info const & x )
  56. {
  57. os << "Error ID: " << x.err_id_.value();
  58. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  59. if( x.ex_ )
  60. {
  61. os <<
  62. "\nException dynamic type: " << leaf_detail::demangle(typeid(*x.ex_).name()) <<
  63. "\nstd::exception::what(): " << x.ex_->what();
  64. }
  65. #endif
  66. return os << '\n';
  67. }
  68. };
  69. namespace leaf_detail
  70. {
  71. template <>
  72. struct handler_argument_traits<error_info const &>: handler_argument_always_available<void>
  73. {
  74. template <class Tup>
  75. BOOST_LEAF_CONSTEXPR static error_info const & get( Tup const &, error_info const & ei ) noexcept
  76. {
  77. return ei;
  78. }
  79. };
  80. }
  81. ////////////////////////////////////////
  82. #if BOOST_LEAF_CFG_DIAGNOSTICS
  83. class diagnostic_info: public error_info
  84. {
  85. void const * tup_;
  86. void (*print_context_content_)( std::ostream &, void const * tup, int err_id_to_print );
  87. protected:
  88. diagnostic_info( diagnostic_info const & ) noexcept = default;
  89. template <class Tup>
  90. BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei, Tup const & tup ) noexcept:
  91. error_info(ei),
  92. tup_(&tup),
  93. print_context_content_(&leaf_detail::tuple_for_each<std::tuple_size<Tup>::value, Tup>::print)
  94. {
  95. }
  96. template <class CharT, class Traits>
  97. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, diagnostic_info const & x )
  98. {
  99. os << static_cast<error_info const &>(x);
  100. x.print_context_content_(os, x.tup_, x.error().value());
  101. return os;
  102. }
  103. };
  104. namespace leaf_detail
  105. {
  106. struct diagnostic_info_: diagnostic_info
  107. {
  108. template <class Tup>
  109. BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei, Tup const & tup ) noexcept:
  110. diagnostic_info(ei, tup)
  111. {
  112. }
  113. };
  114. template <>
  115. struct handler_argument_traits<diagnostic_info const &>: handler_argument_always_available<void>
  116. {
  117. template <class Tup>
  118. BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept
  119. {
  120. return diagnostic_info_(ei, tup);
  121. }
  122. };
  123. }
  124. #else
  125. class diagnostic_info: public error_info
  126. {
  127. protected:
  128. diagnostic_info( diagnostic_info const & ) noexcept = default;
  129. BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei ) noexcept:
  130. error_info(ei)
  131. {
  132. }
  133. template <class CharT, class Traits>
  134. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, diagnostic_info const & x )
  135. {
  136. return os << "diagnostic_info not available due to BOOST_LEAF_CFG_DIAGNOSTICS=0. Basic error_info follows.\n" << static_cast<error_info const &>(x);
  137. }
  138. };
  139. namespace leaf_detail
  140. {
  141. struct diagnostic_info_: diagnostic_info
  142. {
  143. BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei ) noexcept:
  144. diagnostic_info(ei)
  145. {
  146. }
  147. };
  148. template <>
  149. struct handler_argument_traits<diagnostic_info const &>: handler_argument_always_available<void>
  150. {
  151. template <class Tup>
  152. BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Tup const &, error_info const & ei ) noexcept
  153. {
  154. return diagnostic_info_(ei);
  155. }
  156. };
  157. }
  158. #endif
  159. ////////////////////////////////////////
  160. #if BOOST_LEAF_CFG_DIAGNOSTICS
  161. #if BOOST_LEAF_CFG_CAPTURE
  162. class verbose_diagnostic_info: public diagnostic_info
  163. {
  164. leaf_detail::dynamic_allocator const * const da_;
  165. protected:
  166. verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default;
  167. template <class Tup>
  168. BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei, Tup const & tup, leaf_detail::dynamic_allocator const * da ) noexcept:
  169. diagnostic_info(ei, tup),
  170. da_(da)
  171. {
  172. }
  173. template <class CharT, class Traits>
  174. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, verbose_diagnostic_info const & x )
  175. {
  176. os << static_cast<diagnostic_info const &>(x);
  177. if( x.da_ )
  178. x.da_->print(os, "Unhandled error objects:\n", x.error().value());
  179. return os;
  180. }
  181. };
  182. namespace leaf_detail
  183. {
  184. struct verbose_diagnostic_info_: verbose_diagnostic_info
  185. {
  186. template <class Tup>
  187. BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei, Tup const & tup, dynamic_allocator const * da ) noexcept:
  188. verbose_diagnostic_info(ei, tup, da)
  189. {
  190. }
  191. };
  192. template <>
  193. struct handler_argument_traits<verbose_diagnostic_info const &>: handler_argument_always_available<dynamic_allocator>
  194. {
  195. template <class Tup>
  196. BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept
  197. {
  198. return verbose_diagnostic_info_(ei, tup, handler_argument_traits_defaults<dynamic_allocator>::check(tup, ei));
  199. }
  200. };
  201. }
  202. #else
  203. class verbose_diagnostic_info: public diagnostic_info
  204. {
  205. protected:
  206. verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default;
  207. template <class Tup>
  208. BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei, Tup const & tup ) noexcept:
  209. diagnostic_info(ei, tup)
  210. {
  211. }
  212. template <class CharT, class Traits>
  213. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, verbose_diagnostic_info const & x )
  214. {
  215. return os << "verbose_diagnostic_info not available due to BOOST_LEAF_CFG_CAPTURE=0. Basic diagnostic_info follows.\n" << static_cast<diagnostic_info const &>(x);
  216. }
  217. };
  218. namespace leaf_detail
  219. {
  220. struct verbose_diagnostic_info_: verbose_diagnostic_info
  221. {
  222. template <class Tup>
  223. BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei, Tup const & tup ) noexcept:
  224. verbose_diagnostic_info(ei, tup)
  225. {
  226. }
  227. };
  228. template <>
  229. struct handler_argument_traits<verbose_diagnostic_info const &>: handler_argument_always_available<void>
  230. {
  231. template <class Tup>
  232. BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept
  233. {
  234. return verbose_diagnostic_info_(ei, tup);
  235. }
  236. };
  237. }
  238. #endif
  239. #else
  240. class verbose_diagnostic_info: public diagnostic_info
  241. {
  242. protected:
  243. verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default;
  244. BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei ) noexcept:
  245. diagnostic_info(ei)
  246. {
  247. }
  248. template <class CharT, class Traits>
  249. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, verbose_diagnostic_info const & x )
  250. {
  251. return os << "verbose_diagnostic_info not available due to BOOST_LEAF_CFG_DIAGNOSTICS=0. Basic error_info follows.\n" << static_cast<error_info const &>(x);
  252. }
  253. };
  254. namespace leaf_detail
  255. {
  256. struct verbose_diagnostic_info_: verbose_diagnostic_info
  257. {
  258. BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei ) noexcept:
  259. verbose_diagnostic_info(ei)
  260. {
  261. }
  262. };
  263. template <>
  264. struct handler_argument_traits<verbose_diagnostic_info const &>: handler_argument_always_available<void>
  265. {
  266. template <class Tup>
  267. BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const &, error_info const & ei ) noexcept
  268. {
  269. return verbose_diagnostic_info_(ei);
  270. }
  271. };
  272. }
  273. #endif
  274. ////////////////////////////////////////
  275. namespace leaf_detail
  276. {
  277. template <class T, class... List>
  278. struct type_index;
  279. template <class T, class... Cdr>
  280. struct type_index<T, T, Cdr...>
  281. {
  282. constexpr static int value = 0;
  283. };
  284. template <class T, class Car, class... Cdr>
  285. struct type_index<T, Car, Cdr...>
  286. {
  287. constexpr static int value = 1 + type_index<T,Cdr...>::value;
  288. };
  289. template <class T, class Tuple>
  290. struct tuple_type_index;
  291. template <class T, class... TupleTypes>
  292. struct tuple_type_index<T,std::tuple<TupleTypes...>>
  293. {
  294. constexpr static int value = type_index<T,TupleTypes...>::value;
  295. };
  296. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  297. template <class E, bool = std::is_class<E>::value>
  298. struct peek_exception;
  299. template <>
  300. struct peek_exception<std::exception const, true>
  301. {
  302. BOOST_LEAF_CONSTEXPR static std::exception const * peek( error_info const & ei ) noexcept
  303. {
  304. return ei.exception();
  305. }
  306. };
  307. template <>
  308. struct peek_exception<std::exception, true>
  309. {
  310. BOOST_LEAF_CONSTEXPR static std::exception * peek( error_info const & ei ) noexcept
  311. {
  312. return ei.exception();
  313. }
  314. };
  315. #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
  316. template <>
  317. struct peek_exception<std::error_code const, true>
  318. {
  319. static std::error_code const * peek( error_info const & ei ) noexcept
  320. {
  321. auto const ex = ei.exception();
  322. if( std::system_error * se = dynamic_cast<std::system_error *>(ex) )
  323. return &se->code();
  324. else if( std::error_code * ec = dynamic_cast<std::error_code *>(ex) )
  325. return ec;
  326. else
  327. return nullptr;
  328. }
  329. };
  330. template <>
  331. struct peek_exception<std::error_code, true>
  332. {
  333. static std::error_code * peek( error_info const & ei ) noexcept
  334. {
  335. auto const ex = ei.exception();
  336. if( std::system_error * se = dynamic_cast<std::system_error *>(ex) )
  337. return const_cast<std::error_code *>(&se->code());
  338. else if( std::error_code * ec = dynamic_cast<std::error_code *>(ex) )
  339. return ec;
  340. else
  341. return nullptr;
  342. }
  343. };
  344. #endif
  345. template <class E>
  346. struct peek_exception<E, true>
  347. {
  348. static E * peek( error_info const & ei ) noexcept
  349. {
  350. return dynamic_cast<E *>(ei.exception());
  351. }
  352. };
  353. template <class E>
  354. struct peek_exception<E, false>
  355. {
  356. BOOST_LEAF_CONSTEXPR static E * peek( error_info const & ) noexcept
  357. {
  358. return nullptr;
  359. }
  360. };
  361. #endif
  362. template <class E, bool = does_not_participate_in_context_deduction<E>::value>
  363. struct peek_tuple;
  364. template <class E>
  365. struct peek_tuple<E, true>
  366. {
  367. template <class SlotsTuple>
  368. BOOST_LEAF_CONSTEXPR static E const * peek( SlotsTuple const &, error_id const & ) noexcept
  369. {
  370. return nullptr;
  371. }
  372. template <class SlotsTuple>
  373. BOOST_LEAF_CONSTEXPR static E * peek( SlotsTuple &, error_id const & ) noexcept
  374. {
  375. return nullptr;
  376. }
  377. };
  378. template <class E>
  379. struct peek_tuple<E, false>
  380. {
  381. template <class SlotsTuple>
  382. BOOST_LEAF_CONSTEXPR static E const * peek( SlotsTuple const & tup, error_id const & err ) noexcept
  383. {
  384. return std::get<tuple_type_index<slot<E>,SlotsTuple>::value>(tup).has_value(err.value());
  385. }
  386. template <class SlotsTuple>
  387. BOOST_LEAF_CONSTEXPR static E * peek( SlotsTuple & tup, error_id const & err ) noexcept
  388. {
  389. return std::get<tuple_type_index<slot<E>,SlotsTuple>::value>(tup).has_value(err.value());
  390. }
  391. };
  392. template <class E, class SlotsTuple>
  393. BOOST_LEAF_CONSTEXPR inline
  394. E const *
  395. peek( SlotsTuple const & tup, error_info const & ei ) noexcept
  396. {
  397. if( error_id err = ei.error() )
  398. {
  399. if( E const * e = peek_tuple<E>::peek(tup, err) )
  400. return e;
  401. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  402. else
  403. return peek_exception<E const>::peek(ei);
  404. #endif
  405. }
  406. return nullptr;
  407. }
  408. template <class E, class SlotsTuple>
  409. BOOST_LEAF_CONSTEXPR inline
  410. E *
  411. peek( SlotsTuple & tup, error_info const & ei ) noexcept
  412. {
  413. if( error_id err = ei.error() )
  414. {
  415. if( E * e = peek_tuple<E>::peek(tup, err) )
  416. return e;
  417. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  418. else
  419. return peek_exception<E>::peek(ei);
  420. #endif
  421. }
  422. return nullptr;
  423. }
  424. }
  425. ////////////////////////////////////////
  426. namespace leaf_detail
  427. {
  428. template <class A>
  429. template <class Tup>
  430. BOOST_LEAF_CONSTEXPR inline
  431. typename handler_argument_traits_defaults<A, false>::error_type const *
  432. handler_argument_traits_defaults<A, false>::
  433. check( Tup const & tup, error_info const & ei ) noexcept
  434. {
  435. return peek<typename std::decay<A>::type>(tup, ei);
  436. }
  437. template <class A>
  438. template <class Tup>
  439. BOOST_LEAF_CONSTEXPR inline
  440. typename handler_argument_traits_defaults<A, false>::error_type *
  441. handler_argument_traits_defaults<A, false>::
  442. check( Tup & tup, error_info const & ei ) noexcept
  443. {
  444. return peek<typename std::decay<A>::type>(tup, ei);
  445. }
  446. template <class Tup>
  447. BOOST_LEAF_CONSTEXPR inline
  448. std::exception const *
  449. handler_argument_traits<void>::
  450. check( Tup const &, error_info const & ei ) noexcept
  451. {
  452. return ei.exception();
  453. }
  454. template <class Tup, class... List>
  455. struct check_arguments;
  456. template <class Tup>
  457. struct check_arguments<Tup>
  458. {
  459. BOOST_LEAF_CONSTEXPR static bool check( Tup const &, error_info const & )
  460. {
  461. return true;
  462. }
  463. };
  464. template <class Tup, class Car, class... Cdr>
  465. struct check_arguments<Tup, Car, Cdr...>
  466. {
  467. BOOST_LEAF_CONSTEXPR static bool check( Tup & tup, error_info const & ei ) noexcept
  468. {
  469. return handler_argument_traits<Car>::check(tup, ei) && check_arguments<Tup, Cdr...>::check(tup, ei);
  470. }
  471. };
  472. }
  473. ////////////////////////////////////////
  474. namespace leaf_detail
  475. {
  476. template <class>
  477. struct handler_matches_any_error: std::false_type
  478. {
  479. };
  480. template <template<class...> class L>
  481. struct handler_matches_any_error<L<>>: std::true_type
  482. {
  483. };
  484. template <template<class...> class L, class Car, class... Cdr>
  485. struct handler_matches_any_error<L<Car, Cdr...>>
  486. {
  487. constexpr static bool value = handler_argument_traits<Car>::always_available && handler_matches_any_error<L<Cdr...>>::value;
  488. };
  489. }
  490. ////////////////////////////////////////
  491. namespace leaf_detail
  492. {
  493. template <class Tup, class... A>
  494. BOOST_LEAF_CONSTEXPR inline bool check_handler_( Tup & tup, error_info const & ei, leaf_detail_mp11::mp_list<A...> ) noexcept
  495. {
  496. return check_arguments<Tup, A...>::check(tup, ei);
  497. }
  498. template <class R, class F, bool IsResult = is_result_type<R>::value, class FReturnType = fn_return_type<F>>
  499. struct handler_caller
  500. {
  501. template <class Tup, class... A>
  502. BOOST_LEAF_CONSTEXPR static R call( Tup & tup, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> )
  503. {
  504. return std::forward<F>(f)( handler_argument_traits<A>::get(tup, ei)... );
  505. }
  506. };
  507. template <template <class...> class Result, class... E, class F>
  508. struct handler_caller<Result<void, E...>, F, true, void>
  509. {
  510. using R = Result<void, E...>;
  511. template <class Tup, class... A>
  512. BOOST_LEAF_CONSTEXPR static R call( Tup & tup, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> )
  513. {
  514. std::forward<F>(f)( handler_argument_traits<A>::get(tup, ei)... );
  515. return { };
  516. }
  517. };
  518. template <class T>
  519. struct is_tuple: std::false_type { };
  520. template <class... T>
  521. struct is_tuple<std::tuple<T...>>: std::true_type { };
  522. template <class... T>
  523. struct is_tuple<std::tuple<T...> &>: std::true_type { };
  524. template <class R, class Tup, class H>
  525. BOOST_LEAF_CONSTEXPR inline
  526. typename std::enable_if<!is_tuple<typename std::decay<H>::type>::value, R>::type
  527. handle_error_( Tup & tup, error_info const & ei, H && h )
  528. {
  529. static_assert( handler_matches_any_error<fn_mp_args<H>>::value, "The last handler passed to handle_all must match any error." );
  530. return handler_caller<R, H>::call( tup, ei, std::forward<H>(h), fn_mp_args<H>{ } );
  531. }
  532. template <class R, class Tup, class Car, class... Cdr>
  533. BOOST_LEAF_CONSTEXPR inline
  534. typename std::enable_if<!is_tuple<typename std::decay<Car>::type>::value, R>::type
  535. handle_error_( Tup & tup, error_info const & ei, Car && car, Cdr && ... cdr )
  536. {
  537. if( handler_matches_any_error<fn_mp_args<Car>>::value || check_handler_( tup, ei, fn_mp_args<Car>{ } ) )
  538. return handler_caller<R, Car>::call( tup, ei, std::forward<Car>(car), fn_mp_args<Car>{ } );
  539. else
  540. return handle_error_<R>( tup, ei, std::forward<Cdr>(cdr)...);
  541. }
  542. template <class R, class Tup, class HTup, size_t ... I>
  543. BOOST_LEAF_CONSTEXPR inline
  544. R
  545. handle_error_tuple_( Tup & tup, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup )
  546. {
  547. return handle_error_<R>(tup, ei, std::get<I>(std::forward<HTup>(htup))...);
  548. }
  549. template <class R, class Tup, class HTup, class... Cdr, size_t ... I>
  550. BOOST_LEAF_CONSTEXPR inline
  551. R
  552. handle_error_tuple_( Tup & tup, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup, Cdr && ... cdr )
  553. {
  554. return handle_error_<R>(tup, ei, std::get<I>(std::forward<HTup>(htup))..., std::forward<Cdr>(cdr)...);
  555. }
  556. template <class R, class Tup, class H>
  557. BOOST_LEAF_CONSTEXPR inline
  558. typename std::enable_if<is_tuple<typename std::decay<H>::type>::value, R>::type
  559. handle_error_( Tup & tup, error_info const & ei, H && h )
  560. {
  561. return handle_error_tuple_<R>(
  562. tup,
  563. ei,
  564. leaf_detail_mp11::make_index_sequence<std::tuple_size<typename std::decay<H>::type>::value>(),
  565. std::forward<H>(h));
  566. }
  567. template <class R, class Tup, class Car, class... Cdr>
  568. BOOST_LEAF_CONSTEXPR inline
  569. typename std::enable_if<is_tuple<typename std::decay<Car>::type>::value, R>::type
  570. handle_error_( Tup & tup, error_info const & ei, Car && car, Cdr && ... cdr )
  571. {
  572. return handle_error_tuple_<R>(
  573. tup,
  574. ei,
  575. leaf_detail_mp11::make_index_sequence<std::tuple_size<typename std::decay<Car>::type>::value>(),
  576. std::forward<Car>(car),
  577. std::forward<Cdr>(cdr)...);
  578. }
  579. }
  580. ////////////////////////////////////////
  581. template <class... E>
  582. template <class R, class... H>
  583. BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE
  584. R
  585. context<E...>::
  586. handle_error( error_id id, H && ... h ) const
  587. {
  588. BOOST_LEAF_ASSERT(!is_active());
  589. return leaf_detail::handle_error_<R>(tup(), error_info(id), std::forward<H>(h)...);
  590. }
  591. template <class... E>
  592. template <class R, class... H>
  593. BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE
  594. R
  595. context<E...>::
  596. handle_error( error_id id, H && ... h )
  597. {
  598. BOOST_LEAF_ASSERT(!is_active());
  599. return leaf_detail::handle_error_<R>(tup(), error_info(id), std::forward<H>(h)...);
  600. }
  601. ////////////////////////////////////////
  602. namespace leaf_detail
  603. {
  604. template <class T>
  605. void unload_result( result<T> * r )
  606. {
  607. (void) r->unload();
  608. }
  609. inline void unload_result( void * )
  610. {
  611. }
  612. }
  613. ////////////////////////////////////////
  614. #ifdef BOOST_LEAF_NO_EXCEPTIONS
  615. template <class TryBlock, class... H>
  616. BOOST_LEAF_CONSTEXPR inline
  617. typename std::decay<decltype(std::declval<TryBlock>()().value())>::type
  618. try_handle_all( TryBlock && try_block, H && ... h ) noexcept
  619. {
  620. static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
  621. context_type_from_handlers<H...> ctx;
  622. auto active_context = activate_context(ctx);
  623. if( auto r = std::forward<TryBlock>(try_block)() )
  624. return std::move(r).value();
  625. else
  626. {
  627. leaf_detail::unload_result(&r);
  628. error_id id = r.error();
  629. ctx.deactivate();
  630. using R = typename std::decay<decltype(std::declval<TryBlock>()().value())>::type;
  631. return ctx.template handle_error<R>(std::move(id), std::forward<H>(h)...);
  632. }
  633. }
  634. template <class TryBlock, class... H>
  635. BOOST_LEAF_ATTRIBUTE_NODISCARD BOOST_LEAF_CONSTEXPR inline
  636. typename std::decay<decltype(std::declval<TryBlock>()())>::type
  637. try_handle_some( TryBlock && try_block, H && ... h ) noexcept
  638. {
  639. static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type");
  640. context_type_from_handlers<H...> ctx;
  641. auto active_context = activate_context(ctx);
  642. if( auto r = std::forward<TryBlock>(try_block)() )
  643. return r;
  644. else
  645. {
  646. leaf_detail::unload_result(&r);
  647. error_id id = r.error();
  648. ctx.deactivate();
  649. using R = typename std::decay<decltype(std::declval<TryBlock>()())>::type;
  650. auto rr = ctx.template handle_error<R>(std::move(id), std::forward<H>(h)..., [&r]()->R { return std::move(r); });
  651. if( !rr )
  652. ctx.unload(rr.error());
  653. return rr;
  654. }
  655. }
  656. template <class TryBlock, class... H>
  657. BOOST_LEAF_CONSTEXPR inline
  658. decltype(std::declval<TryBlock>()())
  659. try_catch( TryBlock && try_block, H && ... ) noexcept
  660. {
  661. static_assert(sizeof(context_type_from_handlers<H...>) > 0,
  662. "When exceptions are disabled, try_catch can't fail and has no use for the handlers, but this ensures that the supplied H... types are compatible.");
  663. return std::forward<TryBlock>(try_block)();
  664. }
  665. #else
  666. namespace leaf_detail
  667. {
  668. template <class Ctx, class TryBlock, class... H>
  669. decltype(std::declval<TryBlock>()())
  670. try_catch_( Ctx & ctx, TryBlock && try_block, H && ... h )
  671. {
  672. using namespace leaf_detail;
  673. BOOST_LEAF_ASSERT(ctx.is_active());
  674. using R = decltype(std::declval<TryBlock>()());
  675. try
  676. {
  677. auto r = std::forward<TryBlock>(try_block)();
  678. unload_result(&r);
  679. return std::move(r);
  680. }
  681. catch( std::exception & ex )
  682. {
  683. ctx.deactivate();
  684. error_info e(&ex);
  685. return handle_error_<R>(ctx.tup(), e, std::forward<H>(h)...,
  686. [&]() -> R
  687. {
  688. ctx.unload(e.error());
  689. throw;
  690. } );
  691. }
  692. catch(...)
  693. {
  694. ctx.deactivate();
  695. error_info e(nullptr);
  696. return handle_error_<R>(ctx.tup(), e, std::forward<H>(h)...,
  697. [&]() -> R
  698. {
  699. ctx.unload(e.error());
  700. throw;
  701. } );
  702. }
  703. }
  704. }
  705. template <class TryBlock, class... H>
  706. inline
  707. typename std::decay<decltype(std::declval<TryBlock>()().value())>::type
  708. try_handle_all( TryBlock && try_block, H && ... h )
  709. {
  710. static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to try_handle_all must be registered with leaf::is_result_type");
  711. context_type_from_handlers<H...> ctx;
  712. auto active_context = activate_context(ctx);
  713. if( auto r = leaf_detail::try_catch_(ctx, std::forward<TryBlock>(try_block), std::forward<H>(h)...) )
  714. return std::move(r).value();
  715. else
  716. {
  717. BOOST_LEAF_ASSERT(ctx.is_active());
  718. leaf_detail::unload_result(&r);
  719. error_id id = r.error();
  720. ctx.deactivate();
  721. using R = typename std::decay<decltype(std::declval<TryBlock>()().value())>::type;
  722. return ctx.template handle_error<R>(std::move(id), std::forward<H>(h)...);
  723. }
  724. }
  725. template <class TryBlock, class... H>
  726. BOOST_LEAF_ATTRIBUTE_NODISCARD inline
  727. typename std::decay<decltype(std::declval<TryBlock>()())>::type
  728. try_handle_some( TryBlock && try_block, H && ... h )
  729. {
  730. static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to try_handle_some must be registered with leaf::is_result_type");
  731. context_type_from_handlers<H...> ctx;
  732. auto active_context = activate_context(ctx);
  733. if( auto r = leaf_detail::try_catch_(ctx, std::forward<TryBlock>(try_block), std::forward<H>(h)...) )
  734. return r;
  735. else if( ctx.is_active() )
  736. {
  737. leaf_detail::unload_result(&r);
  738. error_id id = r.error();
  739. ctx.deactivate();
  740. using R = typename std::decay<decltype(std::declval<TryBlock>()())>::type;
  741. auto rr = ctx.template handle_error<R>(std::move(id), std::forward<H>(h)...,
  742. [&r]()->R
  743. {
  744. return std::move(r);
  745. });
  746. if( !rr )
  747. ctx.unload(rr.error());
  748. return rr;
  749. }
  750. else
  751. {
  752. ctx.unload(r.error());
  753. return r;
  754. }
  755. }
  756. template <class TryBlock, class... H>
  757. inline
  758. decltype(std::declval<TryBlock>()())
  759. try_catch( TryBlock && try_block, H && ... h )
  760. {
  761. context_type_from_handlers<H...> ctx;
  762. auto active_context = activate_context(ctx);
  763. using R = decltype(std::declval<TryBlock>()());
  764. try
  765. {
  766. return std::forward<TryBlock>(try_block)();
  767. }
  768. catch( std::exception & ex )
  769. {
  770. ctx.deactivate();
  771. error_info e(&ex);
  772. return leaf_detail::handle_error_<R>(ctx.tup(), e, std::forward<H>(h)...,
  773. [&]() -> R
  774. {
  775. ctx.unload(e.error());
  776. throw;
  777. } );
  778. }
  779. catch(...)
  780. {
  781. ctx.deactivate();
  782. error_info e(nullptr);
  783. return leaf_detail::handle_error_<R>(ctx.tup(), e, std::forward<H>(h)...,
  784. [&]() -> R
  785. {
  786. ctx.unload(e.error());
  787. throw;
  788. } );
  789. }
  790. }
  791. #endif
  792. #if BOOST_LEAF_CFG_CAPTURE
  793. namespace leaf_detail
  794. {
  795. template <class LeafResult>
  796. struct try_capture_all_dispatch_non_void
  797. {
  798. using leaf_result = LeafResult;
  799. template <class TryBlock>
  800. inline
  801. static
  802. leaf_result
  803. try_capture_all_( TryBlock && try_block ) noexcept
  804. {
  805. leaf_detail::slot<leaf_detail::dynamic_allocator> sl;
  806. sl.activate();
  807. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  808. try
  809. #endif
  810. {
  811. if( leaf_result r = std::forward<TryBlock>(try_block)() )
  812. {
  813. sl.deactivate();
  814. return r;
  815. }
  816. else
  817. {
  818. sl.deactivate();
  819. return leaf_result(sl.value(error_id(r.error()).value()).template extract_capture_list<leaf_result>());
  820. }
  821. }
  822. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  823. catch( std::exception & ex )
  824. {
  825. sl.deactivate();
  826. return sl.value(error_info(&ex).error().value()).template extract_capture_list<leaf_result>();
  827. }
  828. catch(...)
  829. {
  830. sl.deactivate();
  831. return sl.value(error_info(nullptr).error().value()).template extract_capture_list<leaf_result>();
  832. }
  833. #endif
  834. }
  835. };
  836. template <class R, bool IsVoid = std::is_same<void, R>::value, bool IsResultType = is_result_type<R>::value>
  837. struct try_capture_all_dispatch;
  838. template <class R>
  839. struct try_capture_all_dispatch<R, false, true>:
  840. try_capture_all_dispatch_non_void<::boost::leaf::result<typename std::decay<decltype(std::declval<R>().value())>::type>>
  841. {
  842. };
  843. template <class R>
  844. struct try_capture_all_dispatch<R, false, false>:
  845. try_capture_all_dispatch_non_void<::boost::leaf::result<typename std::remove_reference<R>::type>>
  846. {
  847. };
  848. template <class R>
  849. struct try_capture_all_dispatch<R, true, false>
  850. {
  851. using leaf_result = ::boost::leaf::result<R>;
  852. template <class TryBlock>
  853. inline
  854. static
  855. leaf_result
  856. try_capture_all_( TryBlock && try_block ) noexcept
  857. {
  858. leaf_detail::slot<leaf_detail::dynamic_allocator> sl;
  859. sl.activate();
  860. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  861. try
  862. #endif
  863. {
  864. std::forward<TryBlock>(try_block)();
  865. return {};
  866. }
  867. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  868. catch( std::exception & ex )
  869. {
  870. sl.deactivate();
  871. return sl.value(error_info(&ex).error().value()).template extract_capture_list<leaf_result>();
  872. }
  873. catch(...)
  874. {
  875. sl.deactivate();
  876. return sl.value(error_info(nullptr).error().value()).template extract_capture_list<leaf_result>();
  877. }
  878. #endif
  879. }
  880. };
  881. }
  882. template <class TryBlock>
  883. inline
  884. typename leaf_detail::try_capture_all_dispatch<decltype(std::declval<TryBlock>()())>::leaf_result
  885. try_capture_all( TryBlock && try_block ) noexcept
  886. {
  887. return leaf_detail::try_capture_all_dispatch<decltype(std::declval<TryBlock>()())>::try_capture_all_(std::forward<TryBlock>(try_block));
  888. }
  889. #endif
  890. } }
  891. // Boost Exception Integration
  892. namespace boost { class exception; }
  893. namespace boost { template <class Tag,class T> class error_info; }
  894. namespace boost { namespace exception_detail { template <class ErrorInfo> struct get_info; } }
  895. namespace boost { namespace leaf {
  896. namespace leaf_detail
  897. {
  898. template <class T>
  899. struct match_enum_type;
  900. template <class Tag, class T>
  901. struct match_enum_type<boost::error_info<Tag, T>>
  902. {
  903. using type = T;
  904. };
  905. template <class Ex>
  906. BOOST_LEAF_CONSTEXPR inline Ex * get_exception( error_info const & ei )
  907. {
  908. return dynamic_cast<Ex *>(ei.exception());
  909. }
  910. template <class, class T>
  911. struct dependent_type { using type = T; };
  912. template <class Dep, class T>
  913. using dependent_type_t = typename dependent_type<Dep, T>::type;
  914. template <class Tag, class T>
  915. struct handler_argument_traits<boost::error_info<Tag, T>>
  916. {
  917. using error_type = void;
  918. constexpr static bool always_available = false;
  919. template <class Tup>
  920. BOOST_LEAF_CONSTEXPR static T * check( Tup &, error_info const & ei ) noexcept
  921. {
  922. using boost_exception = dependent_type_t<T, boost::exception>;
  923. if( auto * be = get_exception<boost_exception>(ei) )
  924. return exception_detail::get_info<boost::error_info<Tag, T>>::get(*be);
  925. else
  926. return nullptr;
  927. }
  928. template <class Tup>
  929. BOOST_LEAF_CONSTEXPR static boost::error_info<Tag, T> get( Tup const & tup, error_info const & ei ) noexcept
  930. {
  931. return boost::error_info<Tag, T>(*check(tup, ei));
  932. }
  933. };
  934. template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> const &>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
  935. template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> const *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
  936. template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> &>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
  937. template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
  938. }
  939. } }
  940. #endif