with.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. //
  2. // Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
  3. //
  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. //
  7. #ifndef BOOST_COBALT_WITH_HPP
  8. #define BOOST_COBALT_WITH_HPP
  9. #include <exception>
  10. #include <utility>
  11. #include <boost/cobalt/detail/util.hpp>
  12. #include <boost/cobalt/detail/await_result_helper.hpp>
  13. #include <boost/cobalt/detail/with.hpp>
  14. namespace boost::cobalt
  15. {
  16. namespace detail
  17. {
  18. template<typename T>
  19. auto invoke_await_exit(T && t, std::exception_ptr & e)
  20. {
  21. return std::forward<T>(t).await_exit(e);
  22. }
  23. }
  24. template<typename Arg, typename Func, typename Teardown>
  25. requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr ep)
  26. {
  27. {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
  28. {std::move(teardown)(std::move(arg), ep)} -> awaitable<detail::with_impl<void>::promise_type>;
  29. {std::declval<detail::co_await_result_t<decltype(std::move(func)(arg))>>()} -> std::same_as<void>;
  30. })
  31. auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<void>
  32. {
  33. std::exception_ptr e;
  34. #if defined(BOOST_NO_EXCEPTIONS)
  35. co_await std::move(func)(arg);
  36. co_await std::move(teardown)(arg, e);
  37. #else
  38. try
  39. {
  40. co_await std::move(func)(arg);
  41. }
  42. catch (...)
  43. {
  44. e = std::current_exception();
  45. }
  46. try
  47. {
  48. co_await std::move(teardown)(std::move(arg), e);
  49. }
  50. catch (...)
  51. {
  52. if (!e)
  53. e = std::current_exception();
  54. }
  55. if (e)
  56. std::rethrow_exception(e);
  57. #endif
  58. }
  59. template<typename Arg, typename Func, typename Teardown>
  60. requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr e)
  61. {
  62. {std::move(teardown)(std::move(arg), e)} -> awaitable<detail::with_impl<void>::promise_type>;
  63. {std::move(func)(arg)} -> std::same_as<void>;
  64. }
  65. && (!requires (Func func, Arg & arg)
  66. {
  67. {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
  68. }))
  69. auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<void>
  70. {
  71. std::exception_ptr e;
  72. #if defined(BOOST_NO_EXCEPTIONS)
  73. std::move(func)(arg);
  74. co_await std::move(teardown)(arg, e);
  75. #else
  76. try
  77. {
  78. std::move(func)(arg);
  79. }
  80. catch (...)
  81. {
  82. e = std::current_exception();
  83. }
  84. try
  85. {
  86. co_await std::move(teardown)(arg, e);
  87. }
  88. catch (...)
  89. {
  90. if (!e)
  91. e = std::current_exception();
  92. }
  93. if (e)
  94. std::rethrow_exception(e);
  95. #endif
  96. }
  97. template<typename Arg, typename Func, typename Teardown>
  98. requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr ep)
  99. {
  100. {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
  101. {std::move(teardown)(std::move(arg), ep)} -> awaitable<detail::with_impl<void>::promise_type>;
  102. {std::declval<detail::co_await_result_t<decltype(std::move(func)(arg))>>()} -> std::move_constructible;
  103. })
  104. auto with(Arg arg, Func func, Teardown teardown)
  105. -> detail::with_impl<detail::co_await_result_t<decltype(std::move(func)(arg))>>
  106. {
  107. std::exception_ptr e;
  108. std::optional<detail::co_await_result_t<decltype(std::move(func)(arg))>> res;
  109. #if defined(BOOST_NO_EXCEPTIONS)
  110. res = co_await std::move(func)(arg);
  111. co_await std::move(teardown)(std::move(arg), e);
  112. #else
  113. try
  114. {
  115. res = co_await std::move(func)(arg);
  116. }
  117. catch (...)
  118. {
  119. e = std::current_exception();
  120. }
  121. try
  122. {
  123. co_await std::move(teardown)(std::move(arg), e);
  124. }
  125. catch (...)
  126. {
  127. if (!e)
  128. e = std::current_exception();
  129. }
  130. if (e)
  131. std::rethrow_exception(e);
  132. #endif
  133. co_return std::move(res);
  134. }
  135. template<typename Arg, typename Func, typename Teardown>
  136. requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr e)
  137. {
  138. {std::move(teardown)(std::move(arg), e)} -> awaitable<detail::with_impl<void>::promise_type>;
  139. {std::move(func)(arg)} -> std::move_constructible;
  140. }
  141. && (!requires (Func func, Arg & arg)
  142. {
  143. {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
  144. }))
  145. auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<decltype(std::move(func)(arg))>
  146. {
  147. std::exception_ptr e;
  148. std::optional<decltype(std::move(func)(arg))> res;
  149. #if defined(BOOST_NO_EXCEPTIONS)
  150. res = std::move(func)(arg);
  151. co_await std::move(teardown)(arg, e);
  152. #else
  153. try
  154. {
  155. res = std::move(func)(arg);
  156. }
  157. catch (...)
  158. {
  159. e = std::current_exception();
  160. }
  161. try
  162. {
  163. co_await std::move(teardown)(arg, e);
  164. }
  165. catch (...)
  166. {
  167. if (!e)
  168. e = std::current_exception();
  169. }
  170. if (e)
  171. std::rethrow_exception(e);
  172. #endif
  173. co_return std::move(res);
  174. }
  175. template<typename Arg, typename Func>
  176. requires requires (Arg args, std::exception_ptr ep)
  177. {
  178. {std::move(args).await_exit(ep)} -> awaitable<detail::with_impl<void>::promise_type>;
  179. }
  180. auto with(Arg && arg, Func && func)
  181. {
  182. return with(std::forward<Arg>(arg), std::forward<Func>(func), &detail::invoke_await_exit<Arg>);
  183. }
  184. }
  185. #endif //BOOST_COBALT_WITH_HPP