1//
2// Copyright (c) 2023 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_HANDLE_HPP
9#define BOOST_COBALT_HANDLE_HPP
10
11#include <boost/asio/associator.hpp>
12#include <coroutine>
13#include <memory>
14
15namespace boost::cobalt
16{
17
18template<typename T>
19struct unique_handle
20{
21 unique_handle() noexcept = default;
22#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
23 explicit unique_handle(T * promise,
24 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(promise), loc_(loc) {}
25#else
26 explicit unique_handle(T * promise) noexcept : handle_(promise) {}
27#endif
28 unique_handle(std::nullptr_t) noexcept {}
29
30 std::coroutine_handle<T> release()
31 {
32 return std::coroutine_handle<T>::from_promise(*handle_.release());
33 }
34
35 void* address() const noexcept { return get_handle_().address(); }
36
37#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
38 static unique_handle from_address(
39 void* a,
40 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
41 {
42 unique_handle res;
43 res.loc_ = loc;
44 res.handle_.reset(&std::coroutine_handle<T>::from_address(a).promise());
45 return res;
46 }
47#else
48 static unique_handle from_address(void* a) noexcept
49 {
50 unique_handle res;
51 res.handle_.reset(&std::coroutine_handle<T>::from_address(a).promise());
52 return res;
53 }
54#endif
55
56
57 bool done() const noexcept { return get_handle_().done(); }
58 explicit operator bool() const { return static_cast<bool>(handle_); }
59
60 void destroy() { handle_.reset(); }
61
62 void operator()() const &
63 {
64#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
65 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
66#endif
67 resume();
68 }
69 void resume() const & { get_handle_().resume(); }
70
71 void operator()() &&
72 {
73#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
74 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
75#endif
76 release().resume();
77 }
78 void resume() && { release().resume(); }
79
80 T & promise() {return *handle_;}
81
82#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
83 constexpr static unique_handle from_promise(
84 T &p,
85 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
86 {
87 unique_handle res;
88 res.loc_ = loc;
89 res.handle_.reset(&p);
90 return res;
91 }
92#else
93 constexpr static unique_handle from_promise(T &p) noexcept
94 {
95 unique_handle res;
96 res.handle_.reset(&p);
97 return res;
98 }
99#endif
100
101 T & operator*() {return *handle_;}
102 const T & operator*() const {return *handle_;}
103
104
105 T * operator->() {return handle_.get();}
106 const T * operator->() const {return handle_.get();}
107
108 T * get() {return handle_.get();}
109 const T * get() const {return handle_.get();}
110
111#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
112 void reset(T * handle = nullptr,
113 const boost::source_location & loc = BOOST_CURRENT_LOCATION)
114 {
115 loc_ = loc; handle_.reset(handle);
116 }
117#else
118 void reset(T * handle = nullptr) {handle_.reset(handle);}
119#endif
120
121 friend
122 auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;}
123 friend
124 auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;}
125
126 private:
127 struct deleter_
128 {
129 void operator()(T * p)
130 {
131 std::coroutine_handle<T>::from_promise(*p).destroy();
132 }
133 };
134
135 std::coroutine_handle<T> get_handle_() const
136 {
137 return std::coroutine_handle<T>::from_promise(*handle_);
138 }
139
140 std::unique_ptr<T, deleter_> handle_;
141#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
142 boost::source_location loc_;
143#endif
144};
145
146template<>
147struct unique_handle<void>
148{
149 unique_handle() noexcept = default;
150 unique_handle(std::nullptr_t) noexcept {}
151#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
152 explicit unique_handle(void * handle,
153 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(handle), loc_(loc) {}
154#else
155 explicit unique_handle(void * handle) noexcept : handle_(handle) {}
156#endif
157 std::coroutine_handle<void> release()
158 {
159 return std::coroutine_handle<void>::from_address(a: handle_.release());
160 }
161 void* address() const noexcept { return get_handle_().address(); }
162#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
163 static unique_handle<void> from_address(void* a,
164 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
165 {
166
167 unique_handle res;
168 res.loc_ = loc;
169 res.handle_.reset(std::coroutine_handle<void>::from_address(a).address());
170 return res;
171 }
172#else
173static unique_handle<void> from_address(void* a) noexcept
174 {
175
176 unique_handle res;
177 res.handle_.reset(p: std::coroutine_handle<void>::from_address(a: a).address());
178 return res;
179 }
180#endif
181
182 explicit operator bool() const { return static_cast<bool>(handle_); }
183 bool done() const noexcept { return get_handle_().done(); }
184
185 void operator()() const &
186 {
187#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
188 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
189#endif
190 resume();
191 }
192 void resume() const & { get_handle_().resume(); }
193
194 void operator()() &&
195 {
196#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
197 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
198#endif
199 release().resume();
200 }
201 void resume() && { release().resume(); }
202
203 void destroy() { handle_.reset(); }
204
205 void * get() { return handle_.get(); }
206 const void * get() const { return handle_.get(); }
207
208#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
209 void reset(void * handle = nullptr,
210 const boost::source_location & loc = BOOST_CURRENT_LOCATION)
211 {
212 loc_ = loc;
213 handle_.reset(handle);
214 }
215#else
216 void reset(void * handle = nullptr) {handle_.reset(p: handle);}
217#endif
218
219 friend
220 auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;}
221 friend
222 auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;}
223 private:
224 struct deleter_
225 {
226 void operator()(void * p)
227 {
228 std::coroutine_handle<void>::from_address(a: p).destroy();
229 }
230 };
231
232 std::coroutine_handle<void> get_handle_() const
233 {
234 return std::coroutine_handle<void>::from_address(a: handle_.get());
235 }
236
237 std::unique_ptr<void, deleter_> handle_;
238#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
239 boost::source_location loc_;
240#endif
241};
242
243template<>
244struct unique_handle<std::noop_coroutine_promise>
245{
246 unique_handle() noexcept = default;
247 unique_handle(std::nullptr_t) noexcept {}
248
249 std::coroutine_handle<void> release()
250 {
251 return std::noop_coroutine();
252 }
253 void* address() const noexcept { return std::noop_coroutine().address(); }
254 bool done() const noexcept { return true;}
255 void operator()() const {}
256 void resume() const {}
257 void destroy() {}
258 explicit operator bool() const { return true; }
259
260 struct executor_type
261 {
262 template<typename Fn>
263 void execute(Fn &&) const {}
264 };
265
266 executor_type get_executor() const {return {}; }
267
268 friend
269 auto operator==(const unique_handle &, std::nullptr_t) {return false;}
270 friend
271 auto operator!=(const unique_handle &, std::nullptr_t) {return true;}
272};
273
274}
275
276namespace boost::asio
277{
278
279template <template <typename, typename> class Associator,
280 typename Promise, typename DefaultCandidate>
281 requires (!std::is_void_v<Promise>)
282struct associator<Associator,
283 boost::cobalt::unique_handle<Promise>, DefaultCandidate>
284 : Associator<Promise, DefaultCandidate>
285{
286 static typename Associator<Promise, DefaultCandidate>::type
287 get(const boost::cobalt::unique_handle<Promise>& h) BOOST_ASIO_NOEXCEPT
288 {
289 return Associator<Promise, DefaultCandidate>::get(*h);
290 }
291
292 static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
293 typename Associator<Handler, DefaultCandidate>::type)
294 get(const boost::cobalt::unique_handle<Promise>& h,
295 const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
296 BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
297 Associator<Promise, DefaultCandidate>::get(*h, c)))
298 {
299 return Associator<Promise, DefaultCandidate>::get(*h, c);
300 }
301};
302
303}
304
305
306#endif //BOOST_COBALT_HANDLE_HPP
307

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