File indexing completed on 2025-12-16 09:44:27
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_COBALT_WITH_HPP
0009 #define BOOST_COBALT_WITH_HPP
0010
0011 #include <exception>
0012 #include <utility>
0013 #include <boost/cobalt/detail/util.hpp>
0014 #include <boost/cobalt/detail/await_result_helper.hpp>
0015 #include <boost/cobalt/detail/with.hpp>
0016
0017
0018 namespace boost::cobalt
0019 {
0020
0021 namespace detail
0022 {
0023
0024 template<typename T>
0025 auto invoke_await_exit(T && t, std::exception_ptr & e)
0026 {
0027 return std::forward<T>(t).await_exit(e);
0028 }
0029
0030 }
0031
0032
0033 template<typename Arg, typename Func, typename Teardown>
0034 requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr ep)
0035 {
0036 {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
0037 {std::move(teardown)(std::move(arg), ep)} -> awaitable<detail::with_impl<void>::promise_type>;
0038 {std::declval<detail::co_await_result_t<decltype(std::move(func)(arg))>>()} -> std::same_as<void>;
0039 })
0040 auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<void>
0041 {
0042
0043 std::exception_ptr e;
0044 #if defined(BOOST_NO_EXCEPTIONS)
0045 co_await std::move(func)(arg);
0046 co_await std::move(teardown)(arg, e);
0047 #else
0048 try
0049 {
0050 co_await std::move(func)(arg);
0051 }
0052 catch (...)
0053 {
0054 e = std::current_exception();
0055 }
0056
0057 try
0058 {
0059 co_await std::move(teardown)(std::move(arg), e);
0060 }
0061 catch (...)
0062 {
0063 if (!e)
0064 e = std::current_exception();
0065 }
0066 if (e)
0067 std::rethrow_exception(e);
0068 #endif
0069 }
0070
0071
0072 template<typename Arg, typename Func, typename Teardown>
0073 requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr e)
0074 {
0075 {std::move(teardown)(std::move(arg), e)} -> awaitable<detail::with_impl<void>::promise_type>;
0076 {std::move(func)(arg)} -> std::same_as<void>;
0077 }
0078 && (!requires (Func func, Arg & arg)
0079 {
0080 {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
0081 }))
0082 auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<void>
0083 {
0084 std::exception_ptr e;
0085 #if defined(BOOST_NO_EXCEPTIONS)
0086 std::move(func)(arg);
0087 co_await std::move(teardown)(arg, e);
0088 #else
0089 try
0090 {
0091 std::move(func)(arg);
0092 }
0093 catch (...)
0094 {
0095 e = std::current_exception();
0096 }
0097
0098 try
0099 {
0100 co_await std::move(teardown)(arg, e);
0101 }
0102 catch (...)
0103 {
0104 if (!e)
0105 e = std::current_exception();
0106 }
0107 if (e)
0108 std::rethrow_exception(e);
0109 #endif
0110 }
0111
0112
0113 template<typename Arg, typename Func, typename Teardown>
0114 requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr ep)
0115 {
0116 {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
0117 {std::move(teardown)(std::move(arg), ep)} -> awaitable<detail::with_impl<void>::promise_type>;
0118 {std::declval<detail::co_await_result_t<decltype(std::move(func)(arg))>>()} -> std::move_constructible;
0119 })
0120 auto with(Arg arg, Func func, Teardown teardown)
0121 -> detail::with_impl<detail::co_await_result_t<decltype(std::move(func)(arg))>>
0122 {
0123 std::exception_ptr e;
0124 std::optional<detail::co_await_result_t<decltype(std::move(func)(arg))>> res;
0125
0126 #if defined(BOOST_NO_EXCEPTIONS)
0127 res = co_await std::move(func)(arg);
0128 co_await std::move(teardown)(std::move(arg), e);
0129 #else
0130 try
0131 {
0132 res = co_await std::move(func)(arg);
0133 }
0134 catch (...)
0135 {
0136 e = std::current_exception();
0137 }
0138
0139 try
0140 {
0141 co_await std::move(teardown)(std::move(arg), e);
0142 }
0143 catch (...)
0144 {
0145 if (!e)
0146 e = std::current_exception();
0147 }
0148 if (e)
0149 std::rethrow_exception(e);
0150 #endif
0151 co_return std::move(res);
0152 }
0153
0154
0155 template<typename Arg, typename Func, typename Teardown>
0156 requires (requires (Func func, Arg & arg, Teardown & teardown, std::exception_ptr e)
0157 {
0158 {std::move(teardown)(std::move(arg), e)} -> awaitable<detail::with_impl<void>::promise_type>;
0159 {std::move(func)(arg)} -> std::move_constructible;
0160 }
0161 && (!requires (Func func, Arg & arg)
0162 {
0163 {std::move(func)(arg)} -> awaitable<detail::with_impl<void>::promise_type>;
0164 }))
0165 auto with(Arg arg, Func func, Teardown teardown) -> detail::with_impl<decltype(std::move(func)(arg))>
0166 {
0167 std::exception_ptr e;
0168 std::optional<decltype(std::move(func)(arg))> res;
0169
0170 #if defined(BOOST_NO_EXCEPTIONS)
0171 res = std::move(func)(arg);
0172 co_await std::move(teardown)(arg, e);
0173 #else
0174 try
0175 {
0176 res = std::move(func)(arg);
0177 }
0178 catch (...)
0179 {
0180 e = std::current_exception();
0181 }
0182
0183 try
0184 {
0185 co_await std::move(teardown)(arg, e);
0186 }
0187 catch (...)
0188 {
0189 if (!e)
0190 e = std::current_exception();
0191 }
0192 if (e)
0193 std::rethrow_exception(e);
0194 #endif
0195 co_return std::move(res);
0196 }
0197
0198
0199
0200 template<typename Arg, typename Func>
0201 requires requires (Arg args, std::exception_ptr ep)
0202 {
0203 {std::move(args).await_exit(ep)} -> awaitable<detail::with_impl<void>::promise_type>;
0204 }
0205 auto with(Arg && arg, Func && func)
0206 {
0207 return with(std::forward<Arg>(arg), std::forward<Func>(func), &detail::invoke_await_exit<Arg>);
0208 }
0209
0210 }
0211
0212
0213 #endif