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

source code of boost/libs/asio/test/execution/prefer_only.cpp