handle_errors.hpp 27 KB

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