1 //
2 // prefer_only.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 "asio/execution/prefer_only.hpp"
18
19 #include "asio/execution/any_executor.hpp"
20 #include "../unit_test.hpp"
21
22 #if defined(ASIO_HAS_BOOST_BIND)
23 # include <boost/bind/bind.hpp>
24 #else // defined(ASIO_HAS_BOOST_BIND)
25 # include <functional>
26 #endif // defined(ASIO_HAS_BOOST_BIND)
27
28 using namespace asio;
29
30 #if defined(ASIO_HAS_BOOST_BIND)
31 namespace bindns = boost;
32 #else // defined(ASIO_HAS_BOOST_BIND)
33 namespace bindns = std;
34 #endif
35
36 static int possibly_blocking_count = 0;
37 static int never_blocking_count = 0;
38
39 struct possibly_blocking_executor
40 {
41 template <typename F>
executepossibly_blocking_executor42 void execute(const F&) const
43 {
44 ++possibly_blocking_count;
45 }
46
operator ==(const possibly_blocking_executor &,const possibly_blocking_executor &)47 friend bool operator==(const possibly_blocking_executor&,
48 const possibly_blocking_executor&) ASIO_NOEXCEPT
49 {
50 return true;
51 }
52
operator !=(const possibly_blocking_executor &,const possibly_blocking_executor &)53 friend bool operator!=(const possibly_blocking_executor&,
54 const possibly_blocking_executor&) ASIO_NOEXCEPT
55 {
56 return false;
57 }
58 };
59
60 namespace asio {
61 namespace traits {
62
63 #if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
64
65 template <typename F>
66 struct execute_member<possibly_blocking_executor, F>
67 {
68 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
69 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
70 typedef void result_type;
71 };
72
73 #endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
74
75 #if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
76
77 template <>
78 struct equality_comparable<possibly_blocking_executor>
79 {
80 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
81 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
82 };
83
84 #endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
85
86 } // namespace traits
87 } // namespace asio
88
89 struct never_blocking_executor
90 {
91 static ASIO_CONSTEXPR execution::blocking_t::never_t
querynever_blocking_executor92 query(execution::blocking_t) ASIO_NOEXCEPT
93 {
94 return execution::blocking_t::never_t();
95 }
96
97 template <typename F>
executenever_blocking_executor98 void execute(const F&) const
99 {
100 ++never_blocking_count;
101 }
102
operator ==(const never_blocking_executor &,const never_blocking_executor &)103 friend bool operator==(const never_blocking_executor&,
104 const never_blocking_executor&) ASIO_NOEXCEPT
105 {
106 return true;
107 }
108
operator !=(const never_blocking_executor &,const never_blocking_executor &)109 friend bool operator!=(const never_blocking_executor&,
110 const never_blocking_executor&) ASIO_NOEXCEPT
111 {
112 return false;
113 }
114 };
115
116 namespace asio {
117 namespace traits {
118
119 #if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
120
121 template <typename F>
122 struct execute_member<never_blocking_executor, F>
123 {
124 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
125 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
126 typedef void result_type;
127 };
128
129 #endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
130
131 #if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
132
133 template <>
134 struct equality_comparable<never_blocking_executor>
135 {
136 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
137 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
138 };
139
140 #endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
141
142 #if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
143
144 template <typename Param>
145 struct query_static_constexpr_member<
146 never_blocking_executor, Param,
147 typename asio::enable_if<
148 asio::is_convertible<Param, execution::blocking_t>::value
149 >::type>
150 {
151 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
152 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
153
154 typedef execution::blocking_t::never_t result_type;
155
valueasio::traits::query_static_constexpr_member156 static ASIO_CONSTEXPR result_type value()
157 {
158 return result_type();
159 }
160 };
161
162 #endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
163
164 } // namespace traits
165 } // namespace asio
166
167 struct either_blocking_executor
168 {
169 execution::blocking_t blocking_;
170
either_blocking_executoreither_blocking_executor171 explicit either_blocking_executor(execution::blocking_t b)
172 : blocking_(b)
173 {
174 }
175
queryeither_blocking_executor176 execution::blocking_t query(execution::blocking_t) const ASIO_NOEXCEPT
177 {
178 return blocking_;
179 }
180
requireeither_blocking_executor181 either_blocking_executor require(execution::blocking_t::possibly_t) const
182 {
183 return either_blocking_executor(execution::blocking.possibly);
184 }
185
requireeither_blocking_executor186 either_blocking_executor require(execution::blocking_t::never_t) const
187 {
188 return either_blocking_executor(execution::blocking.never);
189 }
190
191 template <typename F>
executeeither_blocking_executor192 void execute(const F&) const
193 {
194 if (blocking_ == execution::blocking.never)
195 ++never_blocking_count;
196 else
197 ++possibly_blocking_count;
198 }
199
operator ==(const either_blocking_executor & a,const either_blocking_executor & b)200 friend bool operator==(const either_blocking_executor& a,
201 const either_blocking_executor& b) ASIO_NOEXCEPT
202 {
203 return a.blocking_ == b.blocking_;
204 }
205
operator !=(const either_blocking_executor & a,const either_blocking_executor & b)206 friend bool operator!=(const either_blocking_executor& a,
207 const either_blocking_executor& b) ASIO_NOEXCEPT
208 {
209 return a.blocking_ != b.blocking_;
210 }
211 };
212
213 namespace asio {
214 namespace traits {
215
216 #if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
217
218 template <typename F>
219 struct execute_member<either_blocking_executor, F>
220 {
221 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
222 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
223 typedef void result_type;
224 };
225
226 #endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
227
228 #if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
229
230 template <>
231 struct equality_comparable<either_blocking_executor>
232 {
233 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
234 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
235 };
236
237 #endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
238
239 #if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
240
241 template <typename Param>
242 struct query_member<
243 either_blocking_executor, Param,
244 typename asio::enable_if<
245 asio::is_convertible<Param, execution::blocking_t>::value
246 >::type>
247 {
248 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
249 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
250
251 typedef execution::blocking_t result_type;
252 };
253
254 #if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
255
256 #endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
257
258 template <typename Param>
259 struct require_member<
260 either_blocking_executor, Param,
261 typename asio::enable_if<
262 asio::is_convertible<Param, execution::blocking_t>::value
263 >::type>
264 {
265 ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
266 ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
267
268 typedef either_blocking_executor result_type;
269 };
270
271 #endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
272
273 } // namespace traits
274 } // namespace asio
275
prefer_only_executor_query_test()276 void prefer_only_executor_query_test()
277 {
278 typedef execution::any_executor<
279 execution::blocking_t,
280 execution::prefer_only<execution::blocking_t::possibly_t>,
281 execution::prefer_only<execution::blocking_t::never_t>
282 > executor_type;
283
284 executor_type ex1 = possibly_blocking_executor();
285
286 ASIO_CHECK(
287 asio::query(ex1, execution::blocking)
288 == execution::blocking.possibly);
289
290 ASIO_CHECK(
291 asio::query(ex1, execution::blocking.possibly)
292 == execution::blocking.possibly);
293
294 ASIO_CHECK(
295 asio::query(ex1, execution::blocking.never)
296 == execution::blocking.possibly);
297
298 executor_type ex2 = asio::prefer(ex1, execution::blocking.possibly);
299
300 ASIO_CHECK(
301 asio::query(ex2, execution::blocking)
302 == execution::blocking.possibly);
303
304 ASIO_CHECK(
305 asio::query(ex2, execution::blocking.possibly)
306 == execution::blocking.possibly);
307
308 ASIO_CHECK(
309 asio::query(ex2, execution::blocking.never)
310 == execution::blocking.possibly);
311
312 executor_type ex3 = asio::prefer(ex1, execution::blocking.never);
313
314 ASIO_CHECK(
315 asio::query(ex3, execution::blocking)
316 == execution::blocking.possibly);
317
318 ASIO_CHECK(
319 asio::query(ex3, execution::blocking.possibly)
320 == execution::blocking.possibly);
321
322 ASIO_CHECK(
323 asio::query(ex3, execution::blocking.never)
324 == execution::blocking.possibly);
325
326 executor_type ex4 = never_blocking_executor();
327
328 ASIO_CHECK(
329 asio::query(ex4, execution::blocking)
330 == execution::blocking.never);
331
332 ASIO_CHECK(
333 asio::query(ex4, execution::blocking.possibly)
334 == execution::blocking.never);
335
336 ASIO_CHECK(
337 asio::query(ex4, execution::blocking.never)
338 == execution::blocking.never);
339
340 executor_type ex5 = asio::prefer(ex4, execution::blocking.possibly);
341
342 ASIO_CHECK(
343 asio::query(ex5, execution::blocking)
344 == execution::blocking.never);
345
346 ASIO_CHECK(
347 asio::query(ex5, execution::blocking.possibly)
348 == execution::blocking.never);
349
350 ASIO_CHECK(
351 asio::query(ex5, execution::blocking.never)
352 == execution::blocking.never);
353
354 executor_type ex6 = asio::prefer(ex4, execution::blocking.never);
355
356 ASIO_CHECK(
357 asio::query(ex6, execution::blocking)
358 == execution::blocking.never);
359
360 ASIO_CHECK(
361 asio::query(ex6, execution::blocking.possibly)
362 == execution::blocking.never);
363
364 ASIO_CHECK(
365 asio::query(ex6, execution::blocking.never)
366 == execution::blocking.never);
367
368 executor_type ex7 = either_blocking_executor(execution::blocking.possibly);
369
370 ASIO_CHECK(
371 asio::query(ex7, execution::blocking)
372 == execution::blocking.possibly);
373
374 ASIO_CHECK(
375 asio::query(ex7, execution::blocking.possibly)
376 == execution::blocking.possibly);
377
378 ASIO_CHECK(
379 asio::query(ex7, execution::blocking.never)
380 == execution::blocking.possibly);
381
382 executor_type ex8 = asio::prefer(ex7, execution::blocking.possibly);
383
384 ASIO_CHECK(
385 asio::query(ex8, execution::blocking)
386 == execution::blocking.possibly);
387
388 ASIO_CHECK(
389 asio::query(ex8, execution::blocking.possibly)
390 == execution::blocking.possibly);
391
392 ASIO_CHECK(
393 asio::query(ex8, execution::blocking.never)
394 == execution::blocking.possibly);
395
396 executor_type ex9 = asio::prefer(ex7, execution::blocking.never);
397
398 ASIO_CHECK(
399 asio::query(ex9, execution::blocking)
400 == execution::blocking.never);
401
402 ASIO_CHECK(
403 asio::query(ex9, execution::blocking.possibly)
404 == execution::blocking.never);
405
406 ASIO_CHECK(
407 asio::query(ex9, execution::blocking.never)
408 == execution::blocking.never);
409
410 executor_type ex10 = either_blocking_executor(execution::blocking.never);
411
412 ASIO_CHECK(
413 asio::query(ex10, execution::blocking)
414 == execution::blocking.never);
415
416 ASIO_CHECK(
417 asio::query(ex10, execution::blocking.possibly)
418 == execution::blocking.never);
419
420 ASIO_CHECK(
421 asio::query(ex10, execution::blocking.never)
422 == execution::blocking.never);
423
424 executor_type ex11 = asio::prefer(ex7, execution::blocking.possibly);
425
426 ASIO_CHECK(
427 asio::query(ex11, execution::blocking)
428 == execution::blocking.possibly);
429
430 ASIO_CHECK(
431 asio::query(ex11, execution::blocking.possibly)
432 == execution::blocking.possibly);
433
434 ASIO_CHECK(
435 asio::query(ex11, execution::blocking.never)
436 == execution::blocking.possibly);
437
438 executor_type ex12 = asio::prefer(ex7, execution::blocking.never);
439
440 ASIO_CHECK(
441 asio::query(ex12, execution::blocking)
442 == execution::blocking.never);
443
444 ASIO_CHECK(
445 asio::query(ex12, execution::blocking.possibly)
446 == execution::blocking.never);
447
448 ASIO_CHECK(
449 asio::query(ex12, execution::blocking.never)
450 == execution::blocking.never);
451 }
452
do_nothing()453 void do_nothing()
454 {
455 }
456
prefer_only_executor_execute_test()457 void prefer_only_executor_execute_test()
458 {
459 typedef execution::any_executor<
460 execution::blocking_t,
461 execution::prefer_only<execution::blocking_t::possibly_t>,
462 execution::prefer_only<execution::blocking_t::never_t>
463 > executor_type;
464
465 executor_type ex1 = possibly_blocking_executor();
466
467 execution::execute(ex1, &do_nothing);
468 ASIO_CHECK(possibly_blocking_count == 1);
469 ASIO_CHECK(never_blocking_count == 0);
470
471 executor_type ex2 = asio::prefer(ex1, execution::blocking.possibly);
472
473 execution::execute(ex2, &do_nothing);
474 ASIO_CHECK(possibly_blocking_count == 2);
475 ASIO_CHECK(never_blocking_count == 0);
476
477 executor_type ex3 = asio::prefer(ex1, execution::blocking.never);
478
479 execution::execute(ex3, &do_nothing);
480 ASIO_CHECK(possibly_blocking_count == 3);
481 ASIO_CHECK(never_blocking_count == 0);
482
483 executor_type ex4 = never_blocking_executor();
484
485 execution::execute(ex4, &do_nothing);
486 ASIO_CHECK(possibly_blocking_count == 3);
487 ASIO_CHECK(never_blocking_count == 1);
488
489 executor_type ex5 = asio::prefer(ex4, execution::blocking.possibly);
490
491 execution::execute(ex5, &do_nothing);
492 ASIO_CHECK(possibly_blocking_count == 3);
493 ASIO_CHECK(never_blocking_count == 2);
494
495 executor_type ex6 = asio::prefer(ex4, execution::blocking.never);
496
497 execution::execute(ex6, &do_nothing);
498 ASIO_CHECK(possibly_blocking_count == 3);
499 ASIO_CHECK(never_blocking_count == 3);
500
501 executor_type ex7 = either_blocking_executor(execution::blocking.possibly);
502
503 execution::execute(ex7, &do_nothing);
504 ASIO_CHECK(possibly_blocking_count == 4);
505 ASIO_CHECK(never_blocking_count == 3);
506
507 executor_type ex8 = asio::prefer(ex7, execution::blocking.possibly);
508
509 execution::execute(ex8, &do_nothing);
510 ASIO_CHECK(possibly_blocking_count == 5);
511 ASIO_CHECK(never_blocking_count == 3);
512
513 executor_type ex9 = asio::prefer(ex7, execution::blocking.never);
514
515 execution::execute(ex9, &do_nothing);
516 ASIO_CHECK(possibly_blocking_count == 5);
517 ASIO_CHECK(never_blocking_count == 4);
518
519 executor_type ex10 = either_blocking_executor(execution::blocking.never);
520
521 execution::execute(ex10, &do_nothing);
522 ASIO_CHECK(possibly_blocking_count == 5);
523 ASIO_CHECK(never_blocking_count == 5);
524
525 executor_type ex11 = asio::prefer(ex7, execution::blocking.possibly);
526
527 execution::execute(ex11, &do_nothing);
528 ASIO_CHECK(possibly_blocking_count == 6);
529 ASIO_CHECK(never_blocking_count == 5);
530
531 executor_type ex12 = asio::prefer(ex7, execution::blocking.never);
532
533 execution::execute(ex12, &do_nothing);
534 ASIO_CHECK(possibly_blocking_count == 6);
535 ASIO_CHECK(never_blocking_count == 6);
536 }
537
538 ASIO_TEST_SUITE
539 (
540 "prefer_only",
541 ASIO_TEST_CASE(prefer_only_executor_query_test)
542 ASIO_TEST_CASE(prefer_only_executor_execute_test)
543 )
544