with.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. try
  35. {
  36. co_await std::move(func)(arg);
  37. }
  38. catch (...)
  39. {
  40. e = std::current_exception();
  41. }
  42. try
  43. {
  44. co_await std::move(teardown)(std::move(arg), e);
  45. }
  46. catch (...)
  47. {
  48. if (!e)
  49. e = std::current_exception();
  50. }
  51. if (e)
  52. std::rethrow_exception(e);
  53. }
  54. template<typename Arg, typename Func, typename Teardown>
  55. requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr e)
  56. {
  57. {std::move(teardown)(std::move(arg), e)} -> awaitable<detail::with_impl<void>::promise_type>;
  58. {std::move(func)(arg)} -> std::same_as<void>;
  59. }
  60. && (!requires (Func func, Arg & arg)
  61. {
  62. {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
  63. }))
  64. auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<void>
  65. {
  66. std::exception_ptr e;
  67. try
  68. {
  69. std::move(func)(arg);
  70. }
  71. catch (...)
  72. {
  73. e = std::current_exception();
  74. }
  75. try
  76. {
  77. co_await std::move(teardown)(arg, e);
  78. }
  79. catch (...)
  80. {
  81. if (!e)
  82. e = std::current_exception();
  83. }
  84. if (e)
  85. std::rethrow_exception(e);
  86. }
  87. template<typename Arg, typename Func, typename Teardown>
  88. requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr ep)
  89. {
  90. {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
  91. {std::move(teardown)(std::move(arg), ep)} -> awaitable<detail::with_impl<void>::promise_type>;
  92. {std::declval<detail::co_await_result_t<decltype(std::move(func)(arg))>>()} -> std::move_constructible;
  93. })
  94. auto with(Arg arg, Func func, Teardown teardown)
  95. -> detail::with_impl<detail::co_await_result_t<decltype(std::move(func)(arg))>>
  96. {
  97. std::exception_ptr e;
  98. std::optional<detail::co_await_result_t<decltype(std::move(func)(arg))>> res;
  99. try
  100. {
  101. res = co_await std::move(func)(arg);
  102. }
  103. catch (...)
  104. {
  105. e = std::current_exception();
  106. }
  107. try
  108. {
  109. co_await std::move(teardown)(std::move(arg), e);
  110. }
  111. catch (...)
  112. {
  113. if (!e)
  114. e = std::current_exception();
  115. }
  116. if (e)
  117. std::rethrow_exception(e);
  118. co_return std::move(res);
  119. }
  120. template<typename Arg, typename Func, typename Teardown>
  121. requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr e)
  122. {
  123. {std::move(teardown)(std::move(arg), e)} -> awaitable<detail::with_impl<void>::promise_type>;
  124. {std::move(func)(arg)} -> std::move_constructible;
  125. }
  126. && (!requires (Func func, Arg & arg)
  127. {
  128. {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
  129. }))
  130. auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<decltype(std::move(func)(arg))>
  131. {
  132. std::exception_ptr e;
  133. std::optional<decltype(std::move(func)(arg))> res;
  134. try
  135. {
  136. res = std::move(func)(arg);
  137. }
  138. catch (...)
  139. {
  140. e = std::current_exception();
  141. }
  142. try
  143. {
  144. co_await std::move(teardown)(arg, e);
  145. }
  146. catch (...)
  147. {
  148. if (!e)
  149. e = std::current_exception();
  150. }
  151. if (e)
  152. std::rethrow_exception(e);
  153. co_return std::move(res);
  154. }
  155. template<typename Arg, typename Func>
  156. requires requires (Arg args, std::exception_ptr ep)
  157. {
  158. {std::move(args).await_exit(ep)} -> awaitable<detail::with_impl<void>::promise_type>;
  159. }
  160. auto with(Arg && arg, Func && func)
  161. {
  162. return with(std::forward<Arg>(arg), std::forward<Func>(func), &detail::invoke_await_exit<Arg>);
  163. }
  164. }
  165. #endif //BOOST_COBALT_WITH_HPP