error.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. #ifndef BOOST_LEAF_ERROR_HPP_INCLUDED
  2. #define BOOST_LEAF_ERROR_HPP_INCLUDED
  3. /// Copyright (c) 2018-2021 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. #ifndef BOOST_LEAF_ENABLE_WARNINGS ///
  7. # if defined(_MSC_VER) ///
  8. # pragma warning(push,1) ///
  9. # elif defined(__clang__) ///
  10. # pragma clang system_header ///
  11. # elif (__GNUC__*100+__GNUC_MINOR__>301) ///
  12. # pragma GCC system_header ///
  13. # endif ///
  14. #endif ///
  15. #include <boost/leaf/detail/function_traits.hpp>
  16. #include <boost/leaf/detail/print.hpp>
  17. #include <system_error>
  18. #include <type_traits>
  19. #include <memory>
  20. #include <string>
  21. #if BOOST_LEAF_DIAGNOSTICS
  22. # include <sstream>
  23. # include <set>
  24. #endif
  25. #define BOOST_LEAF_TOKEN_PASTE(x, y) x ## y
  26. #define BOOST_LEAF_TOKEN_PASTE2(x, y) BOOST_LEAF_TOKEN_PASTE(x, y)
  27. #define BOOST_LEAF_TMP BOOST_LEAF_TOKEN_PASTE2(boost_leaf_tmp_, __LINE__)
  28. #define BOOST_LEAF_ASSIGN(v,r)\
  29. auto && BOOST_LEAF_TMP = r;\
  30. static_assert(::boost::leaf::is_result_type<typename std::decay<decltype(BOOST_LEAF_TMP)>::type>::value, "BOOST_LEAF_ASSIGN and BOOST_LEAF_AUTO require a result object as the second argument (see is_result_type)");\
  31. if( !BOOST_LEAF_TMP )\
  32. return BOOST_LEAF_TMP.error();\
  33. v = std::forward<decltype(BOOST_LEAF_TMP)>(BOOST_LEAF_TMP).value()
  34. #define BOOST_LEAF_AUTO(v, r)\
  35. BOOST_LEAF_ASSIGN(auto v, r)
  36. #define BOOST_LEAF_CHECK(r)\
  37. auto && BOOST_LEAF_TMP = r;\
  38. static_assert(::boost::leaf::is_result_type<typename std::decay<decltype(BOOST_LEAF_TMP)>::type>::value, "BOOST_LEAF_CHECK requires a result object (see is_result_type)");\
  39. if( BOOST_LEAF_TMP )\
  40. ;\
  41. else\
  42. return BOOST_LEAF_TMP.error()
  43. #define BOOST_LEAF_NEW_ERROR ::boost::leaf::leaf_detail::inject_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::new_error
  44. namespace boost { namespace leaf {
  45. class error_id;
  46. namespace leaf_detail
  47. {
  48. struct inject_loc
  49. {
  50. char const * const file;
  51. int const line;
  52. char const * const fn;
  53. template <class T>
  54. friend T operator+( inject_loc loc, T && x ) noexcept
  55. {
  56. x.load_source_location_(loc.file, loc.line, loc.fn);
  57. return std::move(x);
  58. }
  59. };
  60. }
  61. } }
  62. ////////////////////////////////////////
  63. #ifdef BOOST_LEAF_NO_EXCEPTIONS
  64. namespace boost
  65. {
  66. BOOST_LEAF_NORETURN void throw_exception( std::exception const & ); // user defined
  67. }
  68. namespace boost { namespace leaf {
  69. template <class T>
  70. BOOST_LEAF_NORETURN void throw_exception( T const & e )
  71. {
  72. ::boost::throw_exception(e);
  73. }
  74. } }
  75. #else
  76. namespace boost { namespace leaf {
  77. template <class T>
  78. BOOST_LEAF_NORETURN void throw_exception( T const & e )
  79. {
  80. throw e;
  81. }
  82. } }
  83. #endif
  84. ////////////////////////////////////////
  85. #ifdef BOOST_LEAF_NO_THREADS
  86. # define BOOST_LEAF_THREAD_LOCAL
  87. namespace boost { namespace leaf {
  88. namespace leaf_detail
  89. {
  90. using atomic_unsigned_int = unsigned int;
  91. }
  92. } }
  93. #else
  94. # include <atomic>
  95. # include <thread>
  96. # define BOOST_LEAF_THREAD_LOCAL BOOST_LEAF_SYMBOL_VISIBLE thread_local
  97. namespace boost { namespace leaf {
  98. namespace leaf_detail
  99. {
  100. using atomic_unsigned_int = std::atomic<unsigned int>;
  101. }
  102. } }
  103. #endif
  104. ////////////////////////////////////////
  105. namespace boost { namespace leaf {
  106. #if BOOST_LEAF_DIAGNOSTICS
  107. namespace leaf_detail
  108. {
  109. class BOOST_LEAF_SYMBOL_VISIBLE e_unexpected_count
  110. {
  111. public:
  112. char const * (*first_type)();
  113. int count;
  114. BOOST_LEAF_CONSTEXPR explicit e_unexpected_count(char const * (*first_type)()) noexcept:
  115. first_type(first_type),
  116. count(1)
  117. {
  118. }
  119. template <class CharT, class Traits>
  120. void print( std::basic_ostream<CharT, Traits> & os ) const
  121. {
  122. BOOST_LEAF_ASSERT(first_type != 0);
  123. BOOST_LEAF_ASSERT(count>0);
  124. os << "Detected ";
  125. if( count==1 )
  126. os << "1 attempt to communicate an unexpected error object";
  127. else
  128. os << count << " attempts to communicate unexpected error objects, the first one";
  129. (os << " of type " << first_type() << '\n').flush();
  130. }
  131. };
  132. template <>
  133. struct diagnostic<e_unexpected_count, false, false>
  134. {
  135. static constexpr bool is_invisible = true;
  136. BOOST_LEAF_CONSTEXPR static void print(std::ostream &, e_unexpected_count const &) noexcept { }
  137. };
  138. class BOOST_LEAF_SYMBOL_VISIBLE e_unexpected_info
  139. {
  140. std::string s_;
  141. std::set<char const *(*)()> already_;
  142. public:
  143. e_unexpected_info() noexcept
  144. {
  145. }
  146. template <class E>
  147. void add(E && e)
  148. {
  149. if( !diagnostic<E>::is_invisible && already_.insert(&type<E>).second )
  150. {
  151. std::stringstream s;
  152. diagnostic<E>::print(s,e);
  153. (s << '\n').flush();
  154. s_ += s.str();
  155. }
  156. }
  157. template <class CharT, class Traits>
  158. void print( std::basic_ostream<CharT, Traits> & os ) const
  159. {
  160. os << "Unhandled error objects:\n" << s_;
  161. }
  162. };
  163. template <>
  164. struct diagnostic<e_unexpected_info, false, false>
  165. {
  166. static constexpr bool is_invisible = true;
  167. BOOST_LEAF_CONSTEXPR static void print(std::ostream &, e_unexpected_info const &) noexcept { }
  168. };
  169. template <class=void>
  170. struct BOOST_LEAF_SYMBOL_VISIBLE tl_unexpected_enabled
  171. {
  172. static BOOST_LEAF_THREAD_LOCAL int counter;
  173. };
  174. template <class T>
  175. BOOST_LEAF_THREAD_LOCAL int tl_unexpected_enabled<T>::counter;
  176. }
  177. #endif
  178. } }
  179. ////////////////////////////////////////
  180. namespace boost { namespace leaf {
  181. struct e_source_location
  182. {
  183. char const * const file;
  184. int const line;
  185. char const * const function;
  186. template <class CharT, class Traits>
  187. friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, e_source_location const & x )
  188. {
  189. return os << leaf::type<e_source_location>() << ": " << x.file << '(' << x.line << ") in function " << x.function;
  190. }
  191. };
  192. ////////////////////////////////////////
  193. namespace leaf_detail
  194. {
  195. template <class E>
  196. class slot;
  197. template <class E>
  198. struct BOOST_LEAF_SYMBOL_VISIBLE tl_slot_ptr
  199. {
  200. static BOOST_LEAF_THREAD_LOCAL slot<E> * p;
  201. };
  202. template <class E>
  203. BOOST_LEAF_THREAD_LOCAL slot<E> * tl_slot_ptr<E>::p;
  204. template <class E>
  205. class slot:
  206. optional<E>
  207. {
  208. slot( slot const & ) = delete;
  209. slot & operator=( slot const & ) = delete;
  210. using impl = optional<E>;
  211. slot<E> * * top_;
  212. slot<E> * prev_;
  213. public:
  214. BOOST_LEAF_CONSTEXPR slot() noexcept:
  215. top_(0)
  216. {
  217. }
  218. BOOST_LEAF_CONSTEXPR slot( slot && x ) noexcept:
  219. optional<E>(std::move(x)),
  220. top_(0)
  221. {
  222. BOOST_LEAF_ASSERT(x.top_==0);
  223. }
  224. BOOST_LEAF_CONSTEXPR void activate() noexcept
  225. {
  226. BOOST_LEAF_ASSERT(top_==0 || *top_!=this);
  227. top_ = &tl_slot_ptr<E>::p;
  228. prev_ = *top_;
  229. *top_ = this;
  230. }
  231. BOOST_LEAF_CONSTEXPR void deactivate() noexcept
  232. {
  233. BOOST_LEAF_ASSERT(top_!=0 && *top_==this);
  234. *top_ = prev_;
  235. }
  236. BOOST_LEAF_CONSTEXPR void propagate() noexcept;
  237. template <class CharT, class Traits>
  238. void print( std::basic_ostream<CharT, Traits> & os, int key_to_print ) const
  239. {
  240. if( !diagnostic<E>::is_invisible )
  241. if( int k = this->key() )
  242. {
  243. if( key_to_print )
  244. {
  245. if( key_to_print!=k )
  246. return;
  247. }
  248. else
  249. os << '[' << k << ']';
  250. diagnostic<E>::print(os, value(k));
  251. (os << '\n').flush();
  252. }
  253. }
  254. using impl::put;
  255. using impl::has_value;
  256. using impl::value;
  257. };
  258. #if BOOST_LEAF_DIAGNOSTICS
  259. template <class E>
  260. BOOST_LEAF_CONSTEXPR inline void load_unexpected_count( int err_id ) noexcept
  261. {
  262. if( slot<e_unexpected_count> * sl = tl_slot_ptr<e_unexpected_count>::p )
  263. if( e_unexpected_count * unx = sl->has_value(err_id) )
  264. ++unx->count;
  265. else
  266. sl->put(err_id, e_unexpected_count(&type<E>));
  267. }
  268. template <class E>
  269. BOOST_LEAF_CONSTEXPR inline void load_unexpected_info( int err_id, E && e ) noexcept
  270. {
  271. if( slot<e_unexpected_info> * sl = tl_slot_ptr<e_unexpected_info>::p )
  272. if( e_unexpected_info * unx = sl->has_value(err_id) )
  273. unx->add(std::forward<E>(e));
  274. else
  275. sl->put(err_id, e_unexpected_info()).add(std::forward<E>(e));
  276. }
  277. template <class E>
  278. BOOST_LEAF_CONSTEXPR inline void load_unexpected( int err_id, E && e ) noexcept
  279. {
  280. load_unexpected_count<E>(err_id);
  281. load_unexpected_info(err_id, std::forward<E>(e));
  282. }
  283. #endif
  284. template <class E>
  285. BOOST_LEAF_CONSTEXPR inline void slot<E>::propagate() noexcept
  286. {
  287. BOOST_LEAF_ASSERT(top_!=0 && (*top_==prev_ || *top_==this));
  288. if( prev_ )
  289. {
  290. impl & that_ = *prev_;
  291. if( that_.empty() )
  292. {
  293. impl & this_ = *this;
  294. that_ = std::move(this_);
  295. }
  296. }
  297. #if BOOST_LEAF_DIAGNOSTICS
  298. else
  299. {
  300. int c = tl_unexpected_enabled<>::counter;
  301. BOOST_LEAF_ASSERT(c>=0);
  302. if( c )
  303. if( int err_id = impl::key() )
  304. load_unexpected(err_id, std::move(*this).value(err_id));
  305. }
  306. #endif
  307. }
  308. template <class E>
  309. BOOST_LEAF_CONSTEXPR inline int load_slot( int err_id, E && e ) noexcept
  310. {
  311. static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
  312. static_assert(!std::is_same<typename std::decay<E>::type, error_id>::value, "Error objects of type error_id are not allowed");
  313. using T = typename std::decay<E>::type;
  314. BOOST_LEAF_ASSERT((err_id&3)==1);
  315. if( slot<T> * p = tl_slot_ptr<T>::p )
  316. (void) p->put(err_id, std::forward<E>(e));
  317. #if BOOST_LEAF_DIAGNOSTICS
  318. else
  319. {
  320. int c = tl_unexpected_enabled<>::counter;
  321. BOOST_LEAF_ASSERT(c>=0);
  322. if( c )
  323. load_unexpected(err_id, std::forward<E>(e));
  324. }
  325. #endif
  326. return 0;
  327. }
  328. template <class F>
  329. BOOST_LEAF_CONSTEXPR inline int accumulate_slot( int err_id, F && f ) noexcept
  330. {
  331. static_assert(function_traits<F>::arity==1, "Lambdas passed to accumulate must take a single e-type argument by reference");
  332. using E = typename std::decay<fn_arg_type<F,0>>::type;
  333. static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
  334. BOOST_LEAF_ASSERT((err_id&3)==1);
  335. if( auto sl = tl_slot_ptr<E>::p )
  336. if( auto v = sl->has_value(err_id) )
  337. (void) std::forward<F>(f)(*v);
  338. else
  339. (void) std::forward<F>(f)(sl->put(err_id,E()));
  340. return 0;
  341. }
  342. }
  343. ////////////////////////////////////////
  344. namespace leaf_detail
  345. {
  346. template <class=void>
  347. struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
  348. {
  349. static atomic_unsigned_int counter;
  350. static BOOST_LEAF_THREAD_LOCAL unsigned current_id;
  351. BOOST_LEAF_CONSTEXPR static unsigned generate_next_id() noexcept
  352. {
  353. auto id = (counter+=4);
  354. BOOST_LEAF_ASSERT((id&3)==1);
  355. return id;
  356. }
  357. };
  358. template <class T>
  359. atomic_unsigned_int id_factory<T>::counter(-3);
  360. template <class T>
  361. BOOST_LEAF_THREAD_LOCAL unsigned id_factory<T>::current_id(0);
  362. inline int current_id() noexcept
  363. {
  364. auto id = id_factory<>::current_id;
  365. BOOST_LEAF_ASSERT(id==0 || (id&3)==1);
  366. return id;
  367. }
  368. inline int new_id() noexcept
  369. {
  370. auto id = id_factory<>::generate_next_id();
  371. return id_factory<>::current_id = id;
  372. }
  373. }
  374. ////////////////////////////////////////
  375. namespace leaf_detail
  376. {
  377. template <class T, int Arity = function_traits<T>::arity>
  378. struct load_item
  379. {
  380. static_assert(Arity==0 || Arity==1, "If a functions is passed to new_error or load, it must take zero or one argument");
  381. };
  382. template <class E>
  383. struct load_item<E, -1>
  384. {
  385. BOOST_LEAF_CONSTEXPR static int load( int err_id, E && e ) noexcept
  386. {
  387. return load_slot(err_id, std::forward<E>(e));
  388. }
  389. };
  390. template <class F>
  391. struct load_item<F, 0>
  392. {
  393. BOOST_LEAF_CONSTEXPR static int load( int err_id, F && f ) noexcept
  394. {
  395. return load_slot(err_id, std::forward<F>(f)());
  396. }
  397. };
  398. template <class F>
  399. struct load_item<F, 1>
  400. {
  401. BOOST_LEAF_CONSTEXPR static int load( int err_id, F && f ) noexcept
  402. {
  403. return accumulate_slot(err_id, std::forward<F>(f));
  404. }
  405. };
  406. }
  407. ////////////////////////////////////////
  408. namespace leaf_detail
  409. {
  410. class leaf_category final: public std::error_category
  411. {
  412. bool equivalent( int, std::error_condition const & ) const noexcept final override { return false; }
  413. bool equivalent( std::error_code const &, int ) const noexcept final override { return false; }
  414. char const * name() const noexcept final override { return "LEAF error"; }
  415. std::string message( int condition ) const final override { return name(); }
  416. public:
  417. ~leaf_category() noexcept final override { }
  418. };
  419. template <class=void>
  420. struct get_error_category
  421. {
  422. static leaf_category cat;
  423. };
  424. template <class T>
  425. leaf_category get_error_category<T>::cat;
  426. inline int import_error_code( std::error_code const & ec ) noexcept
  427. {
  428. if( int err_id = ec.value() )
  429. {
  430. std::error_category const & cat = get_error_category<>::cat;
  431. if( &ec.category()==&cat )
  432. {
  433. BOOST_LEAF_ASSERT((err_id&3)==1);
  434. return (err_id&~3)|1;
  435. }
  436. else
  437. {
  438. err_id = new_id();
  439. (void) load_slot(err_id, ec);
  440. return (err_id&~3)|1;
  441. }
  442. }
  443. else
  444. return 0;
  445. }
  446. }
  447. inline bool is_error_id( std::error_code const & ec ) noexcept
  448. {
  449. bool res = (&ec.category() == &leaf_detail::get_error_category<>::cat);
  450. BOOST_LEAF_ASSERT(!res || !ec.value() || ((ec.value()&3)==1));
  451. return res;
  452. }
  453. ////////////////////////////////////////
  454. namespace leaf_detail
  455. {
  456. BOOST_LEAF_CONSTEXPR error_id make_error_id(int) noexcept;
  457. }
  458. class BOOST_LEAF_SYMBOL_VISIBLE error_id
  459. {
  460. friend error_id BOOST_LEAF_CONSTEXPR leaf_detail::make_error_id(int) noexcept;
  461. int value_;
  462. BOOST_LEAF_CONSTEXPR explicit error_id( int value ) noexcept:
  463. value_(value)
  464. {
  465. BOOST_LEAF_ASSERT(value_==0 || ((value_&3)==1));
  466. }
  467. public:
  468. BOOST_LEAF_CONSTEXPR error_id() noexcept:
  469. value_(0)
  470. {
  471. }
  472. error_id( std::error_code const & ec ) noexcept:
  473. value_(leaf_detail::import_error_code(ec))
  474. {
  475. BOOST_LEAF_ASSERT(!value_ || ((value_&3)==1));
  476. }
  477. template <class Enum>
  478. error_id( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, Enum>::type * = 0 ) noexcept:
  479. value_(leaf_detail::import_error_code(e))
  480. {
  481. }
  482. BOOST_LEAF_CONSTEXPR error_id load() const noexcept
  483. {
  484. return *this;
  485. }
  486. template <class... Item>
  487. BOOST_LEAF_CONSTEXPR error_id load( Item && ... item ) const noexcept
  488. {
  489. if( int err_id = value() )
  490. {
  491. int const unused[ ] = { 42, leaf_detail::load_item<Item>::load(err_id, std::forward<Item>(item))... };
  492. (void) unused;
  493. }
  494. return *this;
  495. }
  496. std::error_code to_error_code() const noexcept
  497. {
  498. return std::error_code(value_, leaf_detail::get_error_category<>::cat);
  499. }
  500. BOOST_LEAF_CONSTEXPR int value() const noexcept
  501. {
  502. if( int v = value_ )
  503. {
  504. BOOST_LEAF_ASSERT((v&3)==1);
  505. return (v&~3)|1;
  506. }
  507. else
  508. return 0;
  509. }
  510. BOOST_LEAF_CONSTEXPR explicit operator bool() const noexcept
  511. {
  512. return value_ != 0;
  513. }
  514. BOOST_LEAF_CONSTEXPR friend bool operator==( error_id a, error_id b ) noexcept
  515. {
  516. return a.value_ == b.value_;
  517. }
  518. BOOST_LEAF_CONSTEXPR friend bool operator!=( error_id a, error_id b ) noexcept
  519. {
  520. return !(a == b);
  521. }
  522. BOOST_LEAF_CONSTEXPR friend bool operator<( error_id a, error_id b ) noexcept
  523. {
  524. return a.value_ < b.value_;
  525. }
  526. template <class CharT, class Traits>
  527. friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, error_id x )
  528. {
  529. return os << x.value_;
  530. }
  531. BOOST_LEAF_CONSTEXPR void load_source_location_( char const * file, int line, char const * function ) const noexcept
  532. {
  533. BOOST_LEAF_ASSERT(file&&*file);
  534. BOOST_LEAF_ASSERT(line>0);
  535. BOOST_LEAF_ASSERT(function&&*function);
  536. BOOST_LEAF_ASSERT(value_);
  537. (void) load(e_source_location {file,line,function});
  538. }
  539. };
  540. namespace leaf_detail
  541. {
  542. BOOST_LEAF_CONSTEXPR inline error_id make_error_id( int err_id ) noexcept
  543. {
  544. BOOST_LEAF_ASSERT(err_id==0 || (err_id&3)==1);
  545. return error_id((err_id&~3)|1);
  546. }
  547. }
  548. inline error_id new_error() noexcept
  549. {
  550. return leaf_detail::make_error_id(leaf_detail::new_id());
  551. }
  552. template <class... Item>
  553. inline error_id new_error( Item && ... item ) noexcept
  554. {
  555. return leaf_detail::make_error_id(leaf_detail::new_id()).load(std::forward<Item>(item)...);
  556. }
  557. inline error_id current_error() noexcept
  558. {
  559. return leaf_detail::make_error_id(leaf_detail::current_id());
  560. }
  561. ////////////////////////////////////////////
  562. class polymorphic_context
  563. {
  564. protected:
  565. polymorphic_context() noexcept = default;
  566. ~polymorphic_context() noexcept = default;
  567. public:
  568. virtual error_id propagate_captured_errors() noexcept = 0;
  569. virtual void activate() noexcept = 0;
  570. virtual void deactivate() noexcept = 0;
  571. virtual void propagate() noexcept = 0;
  572. virtual bool is_active() const noexcept = 0;
  573. virtual void print( std::ostream & ) const = 0;
  574. error_id captured_id_;
  575. };
  576. using context_ptr = std::shared_ptr<polymorphic_context>;
  577. ////////////////////////////////////////////
  578. template <class Ctx>
  579. class context_activator
  580. {
  581. context_activator( context_activator const & ) = delete;
  582. context_activator & operator=( context_activator const & ) = delete;
  583. #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
  584. int const uncaught_exceptions_;
  585. #endif
  586. Ctx * ctx_;
  587. public:
  588. explicit BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator(Ctx & ctx) noexcept:
  589. #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
  590. uncaught_exceptions_(std::uncaught_exceptions()),
  591. #endif
  592. ctx_(ctx.is_active() ? 0 : &ctx)
  593. {
  594. if( ctx_ )
  595. ctx_->activate();
  596. }
  597. BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator( context_activator && x ) noexcept:
  598. #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
  599. uncaught_exceptions_(x.uncaught_exceptions_),
  600. #endif
  601. ctx_(x.ctx_)
  602. {
  603. x.ctx_ = 0;
  604. }
  605. BOOST_LEAF_ALWAYS_INLINE ~context_activator() noexcept
  606. {
  607. if( !ctx_ )
  608. return;
  609. if( ctx_->is_active() )
  610. ctx_->deactivate();
  611. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  612. # if BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
  613. if( std::uncaught_exceptions() > uncaught_exceptions_ )
  614. # else
  615. if( std::uncaught_exception() )
  616. # endif
  617. ctx_->propagate();
  618. #endif
  619. }
  620. };
  621. template <class Ctx>
  622. BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator<Ctx> activate_context(Ctx & ctx) noexcept
  623. {
  624. return context_activator<Ctx>(ctx);
  625. }
  626. ////////////////////////////////////////////
  627. template <class R>
  628. struct is_result_type: std::false_type
  629. {
  630. };
  631. template <class R>
  632. struct is_result_type<R const>: is_result_type<R>
  633. {
  634. };
  635. } }
  636. #undef BOOST_LEAF_THREAD_LOCAL
  637. #if defined(_MSC_VER) && !defined(BOOST_LEAF_ENABLE_WARNINGS) ///
  638. #pragma warning(pop) ///
  639. #endif ///
  640. #endif