• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // execute.cpp
3 // ~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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 // Disable autolinking for unit tests.
12 #if !defined(BOOST_ALL_NO_LIB)
13 #define BOOST_ALL_NO_LIB 1
14 #endif // !defined(BOOST_ALL_NO_LIB)
15 
16 // Test that header file is self-contained.
17 #include <boost/asio/execution/execute.hpp>
18 #include <boost/asio/execution/sender.hpp>
19 #include <boost/asio/execution/submit.hpp>
20 
21 #include <boost/asio/execution/invocable_archetype.hpp>
22 #include "../unit_test.hpp"
23 
24 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
25 # include <boost/bind/bind.hpp>
26 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
27 # include <functional>
28 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
29 
30 namespace exec = boost::asio::execution;
31 
32 struct no_execute
33 {
34 };
35 
36 struct const_member_execute
37 {
38   template <typename F>
executeconst_member_execute39   void execute(BOOST_ASIO_MOVE_ARG(F) f) const
40   {
41     typename boost::asio::decay<F>::type tmp(BOOST_ASIO_MOVE_CAST(F)(f));
42     tmp();
43   }
44 };
45 
46 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
47 
48 namespace boost {
49 namespace asio {
50 namespace traits {
51 
52 template <typename F>
53 struct execute_member<const_member_execute, F>
54 {
55   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
56   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
57   typedef void result_type;
58 };
59 
60 } // namespace traits
61 } // namespace asio
62 } // namespace boost
63 
64 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
65 
66 struct free_execute_const_executor
67 {
68   template <typename F>
execute(const free_execute_const_executor &,BOOST_ASIO_MOVE_ARG (F)f)69   friend void execute(const free_execute_const_executor&,
70       BOOST_ASIO_MOVE_ARG(F) f)
71   {
72     typename boost::asio::decay<F>::type tmp(BOOST_ASIO_MOVE_CAST(F)(f));
73     tmp();
74   }
75 };
76 
77 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
78 
79 namespace boost {
80 namespace asio {
81 namespace traits {
82 
83 template <typename F>
84 struct execute_free<free_execute_const_executor, F>
85 {
86   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
87   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
88   typedef void result_type;
89 };
90 
91 } // namespace traits
92 } // namespace asio
93 } // namespace boost
94 
95 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
96 
97 #if defined(BOOST_ASIO_HAS_MOVE)
98 
99 // Support for rvalue references is required in order to use the execute
100 // customisation point with non-const member functions and free functions
101 // taking non-const arguments.
102 
103 struct non_const_member_execute
104 {
105   template <typename F>
executenon_const_member_execute106   void execute(BOOST_ASIO_MOVE_ARG(F) f)
107   {
108     typename boost::asio::decay<F>::type tmp(BOOST_ASIO_MOVE_CAST(F)(f));
109     tmp();
110   }
111 };
112 
113 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
114 
115 namespace boost {
116 namespace asio {
117 namespace traits {
118 
119 template <typename F>
120 struct execute_member<non_const_member_execute, F>
121 {
122   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
123   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
124   typedef void result_type;
125 };
126 
127 template <typename F>
128 struct execute_member<const non_const_member_execute, F>
129 {
130   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
131   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
132   typedef void result_type;
133 };
134 
135 template <typename F>
136 struct execute_member<const non_const_member_execute&, F>
137 {
138   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
139   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
140   typedef void result_type;
141 };
142 
143 } // namespace traits
144 } // namespace asio
145 } // namespace boost
146 
147 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
148 
149 struct free_execute_non_const_executor
150 {
151   template <typename F>
execute(free_execute_non_const_executor &,BOOST_ASIO_MOVE_ARG (F)f)152   friend void execute(free_execute_non_const_executor&,
153       BOOST_ASIO_MOVE_ARG(F) f)
154   {
155     typename boost::asio::decay<F>::type tmp(BOOST_ASIO_MOVE_CAST(F)(f));
156     tmp();
157   }
158 };
159 
160 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
161 
162 namespace boost {
163 namespace asio {
164 namespace traits {
165 
166 template <typename F>
167 struct execute_free<free_execute_non_const_executor, F>
168 {
169   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
170   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
171   typedef void result_type;
172 };
173 
174 template <typename F>
175 struct execute_free<const free_execute_non_const_executor, F>
176 {
177   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
178   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
179   typedef void result_type;
180 };
181 
182 template <typename F>
183 struct execute_free<const free_execute_non_const_executor&, F>
184 {
185   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
186   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
187   typedef void result_type;
188 };
189 
190 } // namespace traits
191 } // namespace asio
192 } // namespace boost
193 
194 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)
195 
196 #endif // defined(BOOST_ASIO_HAS_MOVE)
197 
198 struct operation_state
199 {
startoperation_state200   void start() BOOST_ASIO_NOEXCEPT
201   {
202   }
203 };
204 
205 namespace boost {
206 namespace asio {
207 namespace traits {
208 
209 #if !defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
210 
211 template <>
212 struct start_member<operation_state>
213 {
214   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
215   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
216   typedef void result_type;
217 };
218 
219 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
220 
221 } // namespace traits
222 } // namespace asio
223 } // namespace boost
224 
225 struct sender : exec::sender_base
226 {
sendersender227   sender()
228   {
229   }
230 
231   template <typename R>
connectsender232   operation_state connect(BOOST_ASIO_MOVE_ARG(R) r) const
233   {
234     (void)r;
235     return operation_state();
236   }
237 
238   template <typename R>
submitsender239   void submit(BOOST_ASIO_MOVE_ARG(R) r) const
240   {
241     exec::set_value(BOOST_ASIO_MOVE_CAST(R)(r));
242   }
243 };
244 
245 namespace boost {
246 namespace asio {
247 namespace traits {
248 
249 #if !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
250 
251 template <typename R>
252 struct connect_member<const sender, R>
253 {
254   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
255   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
256   typedef operation_state result_type;
257 };
258 
259 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
260 
261 #if !defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
262 
263 template <typename R>
264 struct submit_member<const sender, R>
265 {
266   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
267   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
268   typedef void result_type;
269 };
270 
271 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
272 
273 } // namespace traits
274 } // namespace asio
275 } // namespace boost
276 
test_can_execute()277 void test_can_execute()
278 {
279   BOOST_ASIO_CONSTEXPR bool b1 = exec::can_execute<
280       no_execute&, exec::invocable_archetype>::value;
281   BOOST_ASIO_CHECK(b1 == false);
282 
283   BOOST_ASIO_CONSTEXPR bool b2 = exec::can_execute<
284       const no_execute&, exec::invocable_archetype>::value;
285   BOOST_ASIO_CHECK(b2 == false);
286 
287   BOOST_ASIO_CONSTEXPR bool b3 = exec::can_execute<
288       const_member_execute&, exec::invocable_archetype>::value;
289   BOOST_ASIO_CHECK(b3 == true);
290 
291   BOOST_ASIO_CONSTEXPR bool b4 = exec::can_execute<
292       const const_member_execute&, exec::invocable_archetype>::value;
293   BOOST_ASIO_CHECK(b4 == true);
294 
295   BOOST_ASIO_CONSTEXPR bool b5 = exec::can_execute<
296       free_execute_const_executor&, exec::invocable_archetype>::value;
297   BOOST_ASIO_CHECK(b5 == true);
298 
299   BOOST_ASIO_CONSTEXPR bool b6 = exec::can_execute<
300       const free_execute_const_executor&, exec::invocable_archetype>::value;
301   BOOST_ASIO_CHECK(b6 == true);
302 
303 #if defined(BOOST_ASIO_HAS_MOVE)
304   BOOST_ASIO_CONSTEXPR bool b7 = exec::can_execute<
305       non_const_member_execute&, exec::invocable_archetype>::value;
306   BOOST_ASIO_CHECK(b7 == true);
307 
308   BOOST_ASIO_CONSTEXPR bool b8 = exec::can_execute<
309       const non_const_member_execute&, exec::invocable_archetype>::value;
310   BOOST_ASIO_CHECK(b8 == false);
311 
312   BOOST_ASIO_CONSTEXPR bool b9 = exec::can_execute<
313       free_execute_non_const_executor&, exec::invocable_archetype>::value;
314   BOOST_ASIO_CHECK(b9 == true);
315 
316   BOOST_ASIO_CONSTEXPR bool b10 = exec::can_execute<
317       const free_execute_non_const_executor&, exec::invocable_archetype>::value;
318   BOOST_ASIO_CHECK(b10 == false);
319 #endif // defined(BOOST_ASIO_HAS_MOVE)
320 
321   BOOST_ASIO_CONSTEXPR bool b11 = exec::can_execute<
322       sender&, exec::invocable_archetype>::value;
323   BOOST_ASIO_CHECK(b11 == true);
324 
325   BOOST_ASIO_CONSTEXPR bool b12 = exec::can_execute<
326       const sender&, exec::invocable_archetype>::value;
327   BOOST_ASIO_CHECK(b12 == true);
328 }
329 
increment(int * count)330 void increment(int* count)
331 {
332   ++(*count);
333 }
334 
test_execute()335 void test_execute()
336 {
337 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
338   namespace bindns = boost;
339 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
340   namespace bindns = std;
341 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
342 
343   int count = 0;
344   const_member_execute ex1 = {};
345   exec::execute(ex1, bindns::bind(&increment, &count));
346   BOOST_ASIO_CHECK(count == 1);
347 
348   count = 0;
349   const const_member_execute ex2 = {};
350   exec::execute(ex2, bindns::bind(&increment, &count));
351   BOOST_ASIO_CHECK(count == 1);
352 
353   count = 0;
354   exec::execute(const_member_execute(), bindns::bind(&increment, &count));
355   BOOST_ASIO_CHECK(count == 1);
356 
357   count = 0;
358   free_execute_const_executor ex3 = {};
359   exec::execute(ex3, bindns::bind(&increment, &count));
360   BOOST_ASIO_CHECK(count == 1);
361 
362   count = 0;
363   const free_execute_const_executor ex4 = {};
364   exec::execute(ex4, bindns::bind(&increment, &count));
365   BOOST_ASIO_CHECK(count == 1);
366 
367   count = 0;
368   exec::execute(free_execute_const_executor(),
369       bindns::bind(&increment, &count));
370   BOOST_ASIO_CHECK(count == 1);
371 
372 #if defined(BOOST_ASIO_HAS_MOVE)
373   count = 0;
374   non_const_member_execute ex5 = {};
375   exec::execute(ex5, bindns::bind(&increment, &count));
376   BOOST_ASIO_CHECK(count == 1);
377 
378   count = 0;
379   free_execute_non_const_executor ex6 = {};
380   exec::execute(ex6, bindns::bind(&increment, &count));
381   BOOST_ASIO_CHECK(count == 1);
382 #endif // defined(BOOST_ASIO_HAS_MOVE)
383 
384   count = 0;
385   sender ex7;
386   exec::execute(ex3, bindns::bind(&increment, &count));
387   BOOST_ASIO_CHECK(count == 1);
388 
389   count = 0;
390   const sender ex8;
391   exec::execute(ex4, bindns::bind(&increment, &count));
392   BOOST_ASIO_CHECK(count == 1);
393 }
394 
395 BOOST_ASIO_TEST_SUITE
396 (
397   "blocking",
398   BOOST_ASIO_TEST_CASE(test_can_execute)
399   BOOST_ASIO_TEST_CASE(test_execute)
400 )
401