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

source code of boost/libs/cobalt/include/boost/cobalt/with.hpp