1//
2// compose.hpp
3// ~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_COMPOSE_HPP
12#define BOOST_ASIO_COMPOSE_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <boost/asio/associated_executor.hpp>
20#include <boost/asio/async_result.hpp>
21#include <boost/asio/detail/base_from_cancellation_state.hpp>
22#include <boost/asio/detail/composed_work.hpp>
23#include <boost/asio/detail/handler_cont_helpers.hpp>
24#include <boost/asio/detail/type_traits.hpp>
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace detail {
31
32template <typename Impl, typename Work, typename Handler, typename Signature>
33class composed_op;
34
35template <typename Impl, typename Work, typename Handler,
36 typename R, typename... Args>
37class composed_op<Impl, Work, Handler, R(Args...)>
38 : public base_from_cancellation_state<Handler>
39{
40public:
41 template <typename I, typename W, typename H>
42 composed_op(I&& impl,
43 W&& work,
44 H&& handler)
45 : base_from_cancellation_state<Handler>(
46 handler, enable_terminal_cancellation()),
47 impl_(static_cast<I&&>(impl)),
48 work_(static_cast<W&&>(work)),
49 handler_(static_cast<H&&>(handler)),
50 invocations_(0)
51 {
52 }
53
54 composed_op(composed_op&& other)
55 : base_from_cancellation_state<Handler>(
56 static_cast<base_from_cancellation_state<Handler>&&>(other)),
57 impl_(static_cast<Impl&&>(other.impl_)),
58 work_(static_cast<Work&&>(other.work_)),
59 handler_(static_cast<Handler&&>(other.handler_)),
60 invocations_(other.invocations_)
61 {
62 }
63
64 typedef typename composed_work_guard<
65 typename Work::head_type>::executor_type io_executor_type;
66
67 io_executor_type get_io_executor() const noexcept
68 {
69 return work_.head_.get_executor();
70 }
71
72 typedef associated_executor_t<Handler, io_executor_type> executor_type;
73
74 executor_type get_executor() const noexcept
75 {
76 return (get_associated_executor)(handler_, work_.head_.get_executor());
77 }
78
79 typedef associated_allocator_t<Handler, std::allocator<void>> allocator_type;
80
81 allocator_type get_allocator() const noexcept
82 {
83 return (get_associated_allocator)(handler_, std::allocator<void>());
84 }
85
86 template<typename... T>
87 void operator()(T&&... t)
88 {
89 if (invocations_ < ~0u)
90 ++invocations_;
91 this->get_cancellation_state().slot().clear();
92 impl_(*this, static_cast<T&&>(t)...);
93 }
94
95 void complete(Args... args)
96 {
97 this->work_.reset();
98 static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
99 }
100
101 void reset_cancellation_state()
102 {
103 base_from_cancellation_state<Handler>::reset_cancellation_state(handler_);
104 }
105
106 template <typename Filter>
107 void reset_cancellation_state(Filter&& filter)
108 {
109 base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
110 static_cast<Filter&&>(filter));
111 }
112
113 template <typename InFilter, typename OutFilter>
114 void reset_cancellation_state(InFilter&& in_filter,
115 OutFilter&& out_filter)
116 {
117 base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
118 static_cast<InFilter&&>(in_filter),
119 static_cast<OutFilter&&>(out_filter));
120 }
121
122 cancellation_type_t cancelled() const noexcept
123 {
124 return base_from_cancellation_state<Handler>::cancelled();
125 }
126
127//private:
128 Impl impl_;
129 Work work_;
130 Handler handler_;
131 unsigned invocations_;
132};
133
134template <typename Impl, typename Work, typename Handler, typename Signature>
135inline bool asio_handler_is_continuation(
136 composed_op<Impl, Work, Handler, Signature>* this_handler)
137{
138 return this_handler->invocations_ > 1 ? true
139 : boost_asio_handler_cont_helpers::is_continuation(
140 this_handler->handler_);
141}
142
143template <typename Signature, typename Executors>
144class initiate_composed_op
145{
146public:
147 typedef typename composed_io_executors<Executors>::head_type executor_type;
148
149 template <typename T>
150 explicit initiate_composed_op(int, T&& executors)
151 : executors_(static_cast<T&&>(executors))
152 {
153 }
154
155 executor_type get_executor() const noexcept
156 {
157 return executors_.head_;
158 }
159
160 template <typename Handler, typename Impl>
161 void operator()(Handler&& handler,
162 Impl&& impl) const
163 {
164 composed_op<decay_t<Impl>, composed_work<Executors>,
165 decay_t<Handler>, Signature>(
166 static_cast<Impl&&>(impl),
167 composed_work<Executors>(executors_),
168 static_cast<Handler&&>(handler))();
169 }
170
171private:
172 composed_io_executors<Executors> executors_;
173};
174
175template <typename Signature, typename Executors>
176inline initiate_composed_op<Signature, Executors> make_initiate_composed_op(
177 composed_io_executors<Executors>&& executors)
178{
179 return initiate_composed_op<Signature, Executors>(0,
180 static_cast<composed_io_executors<Executors>&&>(executors));
181}
182
183} // namespace detail
184
185#if !defined(GENERATING_DOCUMENTATION)
186
187template <template <typename, typename> class Associator,
188 typename Impl, typename Work, typename Handler,
189 typename Signature, typename DefaultCandidate>
190struct associator<Associator,
191 detail::composed_op<Impl, Work, Handler, Signature>,
192 DefaultCandidate>
193 : Associator<Handler, DefaultCandidate>
194{
195 static typename Associator<Handler, DefaultCandidate>::type get(
196 const detail::composed_op<Impl, Work, Handler, Signature>& h) noexcept
197 {
198 return Associator<Handler, DefaultCandidate>::get(h.handler_);
199 }
200
201 static auto get(const detail::composed_op<Impl, Work, Handler, Signature>& h,
202 const DefaultCandidate& c) noexcept
203 -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
204 {
205 return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
206 }
207};
208
209#endif // !defined(GENERATING_DOCUMENTATION)
210
211/// Launch an asynchronous operation with a stateful implementation.
212/**
213 * The async_compose function simplifies the implementation of composed
214 * asynchronous operations automatically wrapping a stateful function object
215 * with a conforming intermediate completion handler.
216 *
217 * @param implementation A function object that contains the implementation of
218 * the composed asynchronous operation. The first argument to the function
219 * object is a non-const reference to the enclosing intermediate completion
220 * handler. The remaining arguments are any arguments that originate from the
221 * completion handlers of any asynchronous operations performed by the
222 * implementation.
223 *
224 * @param token The completion token.
225 *
226 * @param io_objects_or_executors Zero or more I/O objects or I/O executors for
227 * which outstanding work must be maintained.
228 *
229 * @par Per-Operation Cancellation
230 * By default, terminal per-operation cancellation is enabled for
231 * composed operations that are implemented using @c async_compose. To
232 * disable cancellation for the composed operation, or to alter its
233 * supported cancellation types, call the @c self object's @c
234 * reset_cancellation_state function.
235 *
236 * @par Example:
237 *
238 * @code struct async_echo_implementation
239 * {
240 * tcp::socket& socket_;
241 * boost::asio::mutable_buffer buffer_;
242 * enum { starting, reading, writing } state_;
243 *
244 * template <typename Self>
245 * void operator()(Self& self,
246 * boost::system::error_code error = {},
247 * std::size_t n = 0)
248 * {
249 * switch (state_)
250 * {
251 * case starting:
252 * state_ = reading;
253 * socket_.async_read_some(
254 * buffer_, std::move(self));
255 * break;
256 * case reading:
257 * if (error)
258 * {
259 * self.complete(error, 0);
260 * }
261 * else
262 * {
263 * state_ = writing;
264 * boost::asio::async_write(socket_, buffer_,
265 * boost::asio::transfer_exactly(n),
266 * std::move(self));
267 * }
268 * break;
269 * case writing:
270 * self.complete(error, n);
271 * break;
272 * }
273 * }
274 * };
275 *
276 * template <typename CompletionToken>
277 * auto async_echo(tcp::socket& socket,
278 * boost::asio::mutable_buffer buffer,
279 * CompletionToken&& token) ->
280 * decltype(
281 * boost::asio::async_compose<CompletionToken,
282 * void(boost::system::error_code, std::size_t)>(
283 * std::declval<async_echo_implementation>(),
284 * token, socket))
285 * {
286 * return boost::asio::async_compose<CompletionToken,
287 * void(boost::system::error_code, std::size_t)>(
288 * async_echo_implementation{socket, buffer,
289 * async_echo_implementation::starting},
290 * token, socket);
291 * } @endcode
292 */
293template <typename CompletionToken, typename Signature,
294 typename Implementation, typename... IoObjectsOrExecutors>
295auto async_compose(Implementation&& implementation,
296 type_identity_t<CompletionToken>& token,
297 IoObjectsOrExecutors&&... io_objects_or_executors)
298 -> decltype(
299 async_initiate<CompletionToken, Signature>(
300 detail::make_initiate_composed_op<Signature>(
301 detail::make_composed_io_executors(
302 detail::get_composed_io_executor(
303 static_cast<IoObjectsOrExecutors&&>(
304 io_objects_or_executors))...)),
305 token, static_cast<Implementation&&>(implementation)))
306{
307 return async_initiate<CompletionToken, Signature>(
308 detail::make_initiate_composed_op<Signature>(
309 detail::make_composed_io_executors(
310 detail::get_composed_io_executor(
311 static_cast<IoObjectsOrExecutors&&>(
312 io_objects_or_executors))...)),
313 token, static_cast<Implementation&&>(implementation));
314}
315
316} // namespace asio
317} // namespace boost
318
319#include <boost/asio/detail/pop_options.hpp>
320
321#endif // BOOST_ASIO_COMPOSE_HPP
322

source code of boost/libs/asio/include/boost/asio/compose.hpp