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