handle_errors.hpp 30 KB

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