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 | |
23 | using namespace boost::asio; |
24 | namespace bindns = std; |
25 | |
26 | static int possibly_blocking_count = 0; |
27 | static int never_blocking_count = 0; |
28 | |
29 | struct 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 | |
50 | namespace boost { |
51 | namespace asio { |
52 | namespace traits { |
53 | |
54 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) |
55 | |
56 | template <typename F> |
57 | struct 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 | |
68 | template <> |
69 | struct 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 | |
81 | struct 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 | |
108 | namespace boost { |
109 | namespace asio { |
110 | namespace traits { |
111 | |
112 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) |
113 | |
114 | template <typename F> |
115 | struct 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 | |
126 | template <> |
127 | struct 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 | |
137 | template <typename Param> |
138 | struct 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 | |
161 | struct 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 | |
207 | namespace boost { |
208 | namespace asio { |
209 | namespace traits { |
210 | |
211 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) |
212 | |
213 | template <typename F> |
214 | struct 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 | |
225 | template <> |
226 | struct 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 | |
236 | template <typename Param> |
237 | struct 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 | |
253 | template <typename Param> |
254 | struct 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 | |
272 | void 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 | |
449 | void do_nothing() |
450 | { |
451 | } |
452 | |
453 | void 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 | |
534 | BOOST_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 | |