]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // |
2 | // experimental/parallel_group.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
5 | // Copyright (c) 2003-2022 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_EXPERIMENTAL_PARALLEL_GROUP_HPP | |
12 | #define BOOST_ASIO_EXPERIMENTAL_PARALLEL_GROUP_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 <utility> | |
20 | #include <boost/asio/detail/array.hpp> | |
21 | #include <boost/asio/experimental/cancellation_condition.hpp> | |
22 | ||
23 | #include <boost/asio/detail/push_options.hpp> | |
24 | ||
25 | namespace boost { | |
26 | namespace asio { | |
27 | namespace experimental { | |
28 | namespace detail { | |
29 | ||
30 | // Helper trait for getting the completion signature from an async operation. | |
31 | ||
32 | struct parallel_op_signature_probe {}; | |
33 | ||
34 | template <typename T> | |
35 | struct parallel_op_signature_probe_result | |
36 | { | |
37 | typedef T type; | |
38 | }; | |
39 | ||
40 | template <typename Op> | |
41 | struct parallel_op_signature | |
42 | { | |
43 | typedef typename decltype(declval<Op>()( | |
44 | declval<parallel_op_signature_probe>()))::type type; | |
45 | }; | |
46 | ||
47 | // Helper trait for getting a tuple from a completion signature. | |
48 | ||
49 | template <typename Signature> | |
50 | struct parallel_op_signature_as_tuple; | |
51 | ||
52 | template <typename R, typename... Args> | |
53 | struct parallel_op_signature_as_tuple<R(Args...)> | |
54 | { | |
55 | typedef std::tuple<typename decay<Args>::type...> type; | |
56 | }; | |
57 | ||
58 | // Helper trait for concatenating completion signatures. | |
59 | ||
60 | template <std::size_t N, typename Offsets, typename... Signatures> | |
61 | struct parallel_group_signature; | |
62 | ||
63 | template <std::size_t N, typename R0, typename... Args0> | |
64 | struct parallel_group_signature<N, R0(Args0...)> | |
65 | { | |
66 | typedef boost::asio::detail::array<std::size_t, N> order_type; | |
67 | typedef R0 raw_type(Args0...); | |
68 | typedef R0 type(order_type, Args0...); | |
69 | }; | |
70 | ||
71 | template <std::size_t N, | |
72 | typename R0, typename... Args0, | |
73 | typename R1, typename... Args1> | |
74 | struct parallel_group_signature<N, R0(Args0...), R1(Args1...)> | |
75 | { | |
76 | typedef boost::asio::detail::array<std::size_t, N> order_type; | |
77 | typedef R0 raw_type(Args0..., Args1...); | |
78 | typedef R0 type(order_type, Args0..., Args1...); | |
79 | }; | |
80 | ||
81 | template <std::size_t N, typename Sig0, | |
82 | typename Sig1, typename... SigN> | |
83 | struct parallel_group_signature<N, Sig0, Sig1, SigN...> | |
84 | { | |
85 | typedef boost::asio::detail::array<std::size_t, N> order_type; | |
86 | typedef typename parallel_group_signature<N, | |
87 | typename parallel_group_signature<N, Sig0, Sig1>::raw_type, | |
88 | SigN...>::raw_type raw_type; | |
89 | typedef typename parallel_group_signature<N, | |
90 | typename parallel_group_signature<N, Sig0, Sig1>::raw_type, | |
91 | SigN...>::type type; | |
92 | }; | |
93 | ||
94 | template <typename Condition, typename Handler, | |
95 | typename... Ops, std::size_t... I> | |
96 | void parallel_group_launch(Condition cancellation_condition, Handler handler, | |
97 | std::tuple<Ops...>& ops, std::index_sequence<I...>); | |
98 | ||
99 | } // namespace detail | |
100 | ||
101 | /// A group of asynchronous operations that may be launched in parallel. | |
102 | /** | |
103 | * See the documentation for boost::asio::experimental::make_parallel_group for | |
104 | * a usage example. | |
105 | */ | |
106 | template <typename... Ops> | |
107 | class parallel_group | |
108 | { | |
109 | public: | |
110 | /// Constructor. | |
111 | explicit parallel_group(Ops... ops) | |
112 | : ops_(std::move(ops)...) | |
113 | { | |
114 | } | |
115 | ||
116 | /// The completion signature for the group of operations. | |
117 | typedef typename detail::parallel_group_signature<sizeof...(Ops), | |
118 | typename detail::parallel_op_signature<Ops>::type...>::type signature; | |
119 | ||
120 | /// Initiate an asynchronous wait for the group of operations. | |
121 | /** | |
122 | * Launches the group and asynchronously waits for completion. | |
123 | * | |
124 | * @param cancellation_condition A function object, called on completion of | |
125 | * an operation within the group, that is used to determine whether to cancel | |
126 | * the remaining operations. The function object is passed the arguments of | |
127 | * the completed operation's handler. To trigger cancellation of the remaining | |
128 | * operations, it must return a boost::asio::cancellation_type value other | |
129 | * than <tt>boost::asio::cancellation_type::none</tt>. | |
130 | * | |
131 | * @param token A @ref completion_token whose signature is comprised of | |
132 | * a @c std::array<std::size_t, N> indicating the completion order of the | |
133 | * operations, followed by all operations' completion handler arguments. | |
134 | * | |
135 | * The library provides the following @c cancellation_condition types: | |
136 | * | |
137 | * @li boost::asio::experimental::wait_for_all | |
138 | * @li boost::asio::experimental::wait_for_one | |
139 | * @li boost::asio::experimental::wait_for_one_error | |
140 | * @li boost::asio::experimental::wait_for_one_success | |
141 | */ | |
142 | template <typename CancellationCondition, | |
143 | BOOST_ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken> | |
144 | auto async_wait(CancellationCondition cancellation_condition, | |
145 | CompletionToken&& token) | |
146 | { | |
147 | return boost::asio::async_initiate<CompletionToken, signature>( | |
148 | initiate_async_wait(), token, | |
149 | std::move(cancellation_condition), std::move(ops_)); | |
150 | } | |
151 | ||
152 | private: | |
153 | struct initiate_async_wait | |
154 | { | |
155 | template <typename Handler, typename Condition> | |
156 | void operator()(Handler&& h, Condition&& c, std::tuple<Ops...>&& ops) const | |
157 | { | |
158 | detail::parallel_group_launch(std::move(c), std::move(h), | |
159 | ops, std::make_index_sequence<sizeof...(Ops)>()); | |
160 | } | |
161 | }; | |
162 | ||
163 | std::tuple<Ops...> ops_; | |
164 | }; | |
165 | ||
166 | /// Create a group of operations that may be launched in parallel. | |
167 | /** | |
168 | * For example: | |
169 | * @code boost::asio::experimental::make_parallel_group( | |
170 | * [&](auto token) | |
171 | * { | |
172 | * return in.async_read_some(boost::asio::buffer(data), token); | |
173 | * }, | |
174 | * [&](auto token) | |
175 | * { | |
176 | * return timer.async_wait(token); | |
177 | * } | |
178 | * ).async_wait( | |
179 | * boost::asio::experimental::wait_for_all(), | |
180 | * []( | |
181 | * std::array<std::size_t, 2> completion_order, | |
182 | * boost::system::error_code ec1, std::size_t n1, | |
183 | * boost::system::error_code ec2 | |
184 | * ) | |
185 | * { | |
186 | * switch (completion_order[0]) | |
187 | * { | |
188 | * case 0: | |
189 | * { | |
190 | * std::cout << "descriptor finished: " << ec1 << ", " << n1 << "\n"; | |
191 | * } | |
192 | * break; | |
193 | * case 1: | |
194 | * { | |
195 | * std::cout << "timer finished: " << ec2 << "\n"; | |
196 | * } | |
197 | * break; | |
198 | * } | |
199 | * } | |
200 | * ); | |
201 | * @endcode | |
202 | */ | |
203 | template <typename... Ops> | |
204 | BOOST_ASIO_NODISCARD inline parallel_group<Ops...> | |
205 | make_parallel_group(Ops... ops) | |
206 | { | |
207 | return parallel_group<Ops...>(std::move(ops)...); | |
208 | } | |
209 | ||
210 | } // namespace experimental | |
211 | } // namespace asio | |
212 | } // namespace boost | |
213 | ||
214 | #include <boost/asio/detail/pop_options.hpp> | |
215 | ||
216 | #include <boost/asio/experimental/impl/parallel_group.hpp> | |
217 | ||
218 | #endif // BOOST_ASIO_EXPERIMENTAL_PARALLEL_GROUP_HPP |