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