• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // system_executor.hpp
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 #ifndef BOOST_ASIO_SYSTEM_EXECUTOR_HPP
12 #define BOOST_ASIO_SYSTEM_EXECUTOR_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 #include <boost/asio/detail/memory.hpp>
20 #include <boost/asio/execution.hpp>
21 
22 #include <boost/asio/detail/push_options.hpp>
23 
24 namespace boost {
25 namespace asio {
26 
27 class system_context;
28 
29 /// An executor that uses arbitrary threads.
30 /**
31  * The system executor represents an execution context where functions are
32  * permitted to run on arbitrary threads. When the blocking.never property is
33  * established, the system executor will schedule the function to run on an
34  * unspecified system thread pool. When either blocking.possibly or
35  * blocking.always is established, the executor invokes the function
36  * immediately.
37  */
38 template <typename Blocking, typename Relationship, typename Allocator>
39 class basic_system_executor
40 {
41 public:
42   /// Default constructor.
basic_system_executor()43   basic_system_executor() BOOST_ASIO_NOEXCEPT
44     : allocator_(Allocator())
45   {
46   }
47 
48   /// Obtain an executor with the @c blocking.possibly property.
49   /**
50    * Do not call this function directly. It is intended for use with the
51    * boost::asio::require customisation point.
52    *
53    * For example:
54    * @code boost::asio::system_executor ex1;
55    * auto ex2 = boost::asio::require(ex1,
56    *     boost::asio::execution::blocking.possibly); @endcode
57    */
58   basic_system_executor<execution::blocking_t::possibly_t,
59       Relationship, Allocator>
require(execution::blocking_t::possibly_t) const60   require(execution::blocking_t::possibly_t) const
61   {
62     return basic_system_executor<execution::blocking_t::possibly_t,
63         Relationship, Allocator>(allocator_);
64   }
65 
66   /// Obtain an executor with the @c blocking.always property.
67   /**
68    * Do not call this function directly. It is intended for use with the
69    * boost::asio::require customisation point.
70    *
71    * For example:
72    * @code boost::asio::system_executor ex1;
73    * auto ex2 = boost::asio::require(ex1,
74    *     boost::asio::execution::blocking.always); @endcode
75    */
76   basic_system_executor<execution::blocking_t::always_t,
77       Relationship, Allocator>
require(execution::blocking_t::always_t) const78   require(execution::blocking_t::always_t) const
79   {
80     return basic_system_executor<execution::blocking_t::always_t,
81         Relationship, Allocator>(allocator_);
82   }
83 
84   /// Obtain an executor with the @c blocking.never property.
85   /**
86    * Do not call this function directly. It is intended for use with the
87    * boost::asio::require customisation point.
88    *
89    * For example:
90    * @code boost::asio::system_executor ex1;
91    * auto ex2 = boost::asio::require(ex1,
92    *     boost::asio::execution::blocking.never); @endcode
93    */
94   basic_system_executor<execution::blocking_t::never_t,
95       Relationship, Allocator>
require(execution::blocking_t::never_t) const96   require(execution::blocking_t::never_t) const
97   {
98     return basic_system_executor<execution::blocking_t::never_t,
99         Relationship, Allocator>(allocator_);
100   }
101 
102   /// Obtain an executor with the @c relationship.continuation property.
103   /**
104    * Do not call this function directly. It is intended for use with the
105    * boost::asio::require customisation point.
106    *
107    * For example:
108    * @code boost::asio::system_executor ex1;
109    * auto ex2 = boost::asio::require(ex1,
110    *     boost::asio::execution::relationship.continuation); @endcode
111    */
112   basic_system_executor<Blocking,
113       execution::relationship_t::continuation_t, Allocator>
require(execution::relationship_t::continuation_t) const114   require(execution::relationship_t::continuation_t) const
115   {
116     return basic_system_executor<Blocking,
117         execution::relationship_t::continuation_t, Allocator>(allocator_);
118   }
119 
120   /// Obtain an executor with the @c relationship.fork property.
121   /**
122    * Do not call this function directly. It is intended for use with the
123    * boost::asio::require customisation point.
124    *
125    * For example:
126    * @code boost::asio::system_executor ex1;
127    * auto ex2 = boost::asio::require(ex1,
128    *     boost::asio::execution::relationship.fork); @endcode
129    */
130   basic_system_executor<Blocking,
131       execution::relationship_t::fork_t, Allocator>
require(execution::relationship_t::fork_t) const132   require(execution::relationship_t::fork_t) const
133   {
134     return basic_system_executor<Blocking,
135         execution::relationship_t::fork_t, Allocator>(allocator_);
136   }
137 
138   /// Obtain an executor with the specified @c allocator property.
139   /**
140    * Do not call this function directly. It is intended for use with the
141    * boost::asio::require customisation point.
142    *
143    * For example:
144    * @code boost::asio::system_executor ex1;
145    * auto ex2 = boost::asio::require(ex1,
146    *     boost::asio::execution::allocator(my_allocator)); @endcode
147    */
148   template <typename OtherAllocator>
149   basic_system_executor<Blocking, Relationship, OtherAllocator>
require(execution::allocator_t<OtherAllocator> a) const150   require(execution::allocator_t<OtherAllocator> a) const
151   {
152     return basic_system_executor<Blocking,
153         Relationship, OtherAllocator>(a.value());
154   }
155 
156   /// Obtain an executor with the default @c allocator property.
157   /**
158    * Do not call this function directly. It is intended for use with the
159    * boost::asio::require customisation point.
160    *
161    * For example:
162    * @code boost::asio::system_executor ex1;
163    * auto ex2 = boost::asio::require(ex1,
164    *     boost::asio::execution::allocator); @endcode
165    */
166   basic_system_executor<Blocking, Relationship, std::allocator<void> >
require(execution::allocator_t<void>) const167   require(execution::allocator_t<void>) const
168   {
169     return basic_system_executor<Blocking,
170         Relationship, std::allocator<void> >();
171   }
172 
173   /// Query the current value of the @c mapping property.
174   /**
175    * Do not call this function directly. It is intended for use with the
176    * boost::asio::query customisation point.
177    *
178    * For example:
179    * @code boost::asio::system_executor ex;
180    * if (boost::asio::query(ex, boost::asio::execution::mapping)
181    *       == boost::asio::execution::mapping.thread)
182    *   ... @endcode
183    */
query(execution::mapping_t)184   static BOOST_ASIO_CONSTEXPR execution::mapping_t query(
185       execution::mapping_t) BOOST_ASIO_NOEXCEPT
186   {
187     return execution::mapping.thread;
188   }
189 
190   /// Query the current value of the @c context property.
191   /**
192    * Do not call this function directly. It is intended for use with the
193    * boost::asio::query customisation point.
194    *
195    * For example:
196    * @code boost::asio::system_executor ex;
197    * boost::asio::system_context& pool = boost::asio::query(
198    *     ex, boost::asio::execution::context); @endcode
199    */
200   static system_context& query(execution::context_t) BOOST_ASIO_NOEXCEPT;
201 
202   /// Query the current value of the @c blocking property.
203   /**
204    * Do not call this function directly. It is intended for use with the
205    * boost::asio::query customisation point.
206    *
207    * For example:
208    * @code boost::asio::system_executor ex;
209    * if (boost::asio::query(ex, boost::asio::execution::blocking)
210    *       == boost::asio::execution::blocking.always)
211    *   ... @endcode
212    */
query(execution::blocking_t)213   static BOOST_ASIO_CONSTEXPR execution::blocking_t query(
214       execution::blocking_t) BOOST_ASIO_NOEXCEPT
215   {
216     return Blocking();
217   }
218 
219   /// Query the current value of the @c relationship property.
220   /**
221    * Do not call this function directly. It is intended for use with the
222    * boost::asio::query customisation point.
223    *
224    * For example:
225    * @code boost::asio::system_executor ex;
226    * if (boost::asio::query(ex, boost::asio::execution::relationship)
227    *       == boost::asio::execution::relationship.continuation)
228    *   ... @endcode
229    */
query(execution::relationship_t)230   static BOOST_ASIO_CONSTEXPR execution::relationship_t query(
231       execution::relationship_t) BOOST_ASIO_NOEXCEPT
232   {
233     return Relationship();
234   }
235 
236   /// Query the current value of the @c allocator property.
237   /**
238    * Do not call this function directly. It is intended for use with the
239    * boost::asio::query customisation point.
240    *
241    * For example:
242    * @code boost::asio::system_executor ex;
243    * auto alloc = boost::asio::query(ex,
244    *     boost::asio::execution::allocator); @endcode
245    */
246   template <typename OtherAllocator>
query(execution::allocator_t<OtherAllocator>) const247   BOOST_ASIO_CONSTEXPR Allocator query(
248       execution::allocator_t<OtherAllocator>) const BOOST_ASIO_NOEXCEPT
249   {
250     return allocator_;
251   }
252 
253   /// Query the current value of the @c allocator property.
254   /**
255    * Do not call this function directly. It is intended for use with the
256    * boost::asio::query customisation point.
257    *
258    * For example:
259    * @code boost::asio::system_executor ex;
260    * auto alloc = boost::asio::query(ex,
261    *     boost::asio::execution::allocator); @endcode
262    */
query(execution::allocator_t<void>) const263   BOOST_ASIO_CONSTEXPR Allocator query(
264       execution::allocator_t<void>) const BOOST_ASIO_NOEXCEPT
265   {
266     return allocator_;
267   }
268 
269   /// Query the occupancy (recommended number of work items) for the system
270   /// context.
271   /**
272    * Do not call this function directly. It is intended for use with the
273    * boost::asio::query customisation point.
274    *
275    * For example:
276    * @code boost::asio::system_executor ex;
277    * std::size_t occupancy = boost::asio::query(
278    *     ex, boost::asio::execution::occupancy); @endcode
279    */
280   std::size_t query(execution::occupancy_t) const BOOST_ASIO_NOEXCEPT;
281 
282   /// Compare two executors for equality.
283   /**
284    * Two executors are equal if they refer to the same underlying io_context.
285    */
operator ==(const basic_system_executor &,const basic_system_executor &)286   friend bool operator==(const basic_system_executor&,
287       const basic_system_executor&) BOOST_ASIO_NOEXCEPT
288   {
289     return true;
290   }
291 
292   /// Compare two executors for inequality.
293   /**
294    * Two executors are equal if they refer to the same underlying io_context.
295    */
operator !=(const basic_system_executor &,const basic_system_executor &)296   friend bool operator!=(const basic_system_executor&,
297       const basic_system_executor&) BOOST_ASIO_NOEXCEPT
298   {
299     return false;
300   }
301 
302   /// Execution function.
303   /**
304    * Do not call this function directly. It is intended for use with the
305    * execution::execute customisation point.
306    *
307    * For example:
308    * @code boost::asio::system_executor ex;
309    * execution::execute(ex, my_function_object); @endcode
310    */
311   template <typename Function>
execute(BOOST_ASIO_MOVE_ARG (Function)f) const312   void execute(BOOST_ASIO_MOVE_ARG(Function) f) const
313   {
314     this->do_execute(BOOST_ASIO_MOVE_CAST(Function)(f), Blocking());
315   }
316 
317 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
318   /// Obtain the underlying execution context.
319   system_context& context() const BOOST_ASIO_NOEXCEPT;
320 
321   /// Inform the executor that it has some outstanding work to do.
322   /**
323    * For the system executor, this is a no-op.
324    */
on_work_started() const325   void on_work_started() const BOOST_ASIO_NOEXCEPT
326   {
327   }
328 
329   /// Inform the executor that some work is no longer outstanding.
330   /**
331    * For the system executor, this is a no-op.
332    */
on_work_finished() const333   void on_work_finished() const BOOST_ASIO_NOEXCEPT
334   {
335   }
336 
337   /// Request the system executor to invoke the given function object.
338   /**
339    * This function is used to ask the executor to execute the given function
340    * object. The function object will always be executed inside this function.
341    *
342    * @param f The function object to be called. The executor will make
343    * a copy of the handler object as required. The function signature of the
344    * function object must be: @code void function(); @endcode
345    *
346    * @param a An allocator that may be used by the executor to allocate the
347    * internal storage needed for function invocation.
348    */
349   template <typename Function, typename OtherAllocator>
350   void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;
351 
352   /// Request the system executor to invoke the given function object.
353   /**
354    * This function is used to ask the executor to execute the given function
355    * object. The function object will never be executed inside this function.
356    * Instead, it will be scheduled to run on an unspecified system thread pool.
357    *
358    * @param f The function object to be called. The executor will make
359    * a copy of the handler object as required. The function signature of the
360    * function object must be: @code void function(); @endcode
361    *
362    * @param a An allocator that may be used by the executor to allocate the
363    * internal storage needed for function invocation.
364    */
365   template <typename Function, typename OtherAllocator>
366   void post(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;
367 
368   /// Request the system executor to invoke the given function object.
369   /**
370    * This function is used to ask the executor to execute the given function
371    * object. The function object will never be executed inside this function.
372    * Instead, it will be scheduled to run on an unspecified system thread pool.
373    *
374    * @param f The function object to be called. The executor will make
375    * a copy of the handler object as required. The function signature of the
376    * function object must be: @code void function(); @endcode
377    *
378    * @param a An allocator that may be used by the executor to allocate the
379    * internal storage needed for function invocation.
380    */
381   template <typename Function, typename OtherAllocator>
382   void defer(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;
383 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
384 
385 private:
386   template <typename, typename, typename> friend class basic_system_executor;
387 
388   // Constructor used by require().
basic_system_executor(const Allocator & a)389   basic_system_executor(const Allocator& a)
390     : allocator_(a)
391   {
392   }
393 
394   /// Execution helper implementation for the possibly blocking property.
395   template <typename Function>
396   void do_execute(BOOST_ASIO_MOVE_ARG(Function) f,
397       execution::blocking_t::possibly_t) const;
398 
399   /// Execution helper implementation for the always blocking property.
400   template <typename Function>
401   void do_execute(BOOST_ASIO_MOVE_ARG(Function) f,
402       execution::blocking_t::always_t) const;
403 
404   /// Execution helper implementation for the never blocking property.
405   template <typename Function>
406   void do_execute(BOOST_ASIO_MOVE_ARG(Function) f,
407       execution::blocking_t::never_t) const;
408 
409   // The allocator used for execution functions.
410   Allocator allocator_;
411 };
412 
413 /// An executor that uses arbitrary threads.
414 /**
415  * The system executor represents an execution context where functions are
416  * permitted to run on arbitrary threads. When the blocking.never property is
417  * established, the system executor will schedule the function to run on an
418  * unspecified system thread pool. When either blocking.possibly or
419  * blocking.always is established, the executor invokes the function
420  * immediately.
421  */
422 typedef basic_system_executor<execution::blocking_t::possibly_t,
423     execution::relationship_t::fork_t, std::allocator<void> >
424   system_executor;
425 
426 #if !defined(GENERATING_DOCUMENTATION)
427 
428 namespace traits {
429 
430 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
431 
432 template <typename Blocking, typename Relationship, typename Allocator>
433 struct equality_comparable<
434     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>
435   >
436 {
437   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
438   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
439 };
440 
441 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
442 
443 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
444 
445 template <typename Blocking, typename Relationship,
446     typename Allocator, typename Function>
447 struct execute_member<
448     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
449     Function
450   >
451 {
452   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
453   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
454   typedef void result_type;
455 };
456 
457 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
458 
459 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
460 
461 template <typename Blocking, typename Relationship, typename Allocator>
462 struct require_member<
463     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
464     boost::asio::execution::blocking_t::possibly_t
465   >
466 {
467   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
468   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
469   typedef boost::asio::basic_system_executor<
470       boost::asio::execution::blocking_t::possibly_t,
471       Relationship, Allocator> result_type;
472 };
473 
474 template <typename Blocking, typename Relationship, typename Allocator>
475 struct require_member<
476     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
477     boost::asio::execution::blocking_t::always_t
478   >
479 {
480   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
481   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
482   typedef boost::asio::basic_system_executor<
483       boost::asio::execution::blocking_t::always_t,
484       Relationship, Allocator> result_type;
485 };
486 
487 template <typename Blocking, typename Relationship, typename Allocator>
488 struct require_member<
489     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
490     boost::asio::execution::blocking_t::never_t
491   >
492 {
493   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
494   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
495   typedef boost::asio::basic_system_executor<
496       boost::asio::execution::blocking_t::never_t,
497       Relationship, Allocator> result_type;
498 };
499 
500 template <typename Blocking, typename Relationship, typename Allocator>
501 struct require_member<
502     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
503     boost::asio::execution::relationship_t::fork_t
504   >
505 {
506   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
507   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
508   typedef boost::asio::basic_system_executor<Blocking,
509       boost::asio::execution::relationship_t::fork_t,
510       Allocator> result_type;
511 };
512 
513 template <typename Blocking, typename Relationship, typename Allocator>
514 struct require_member<
515     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
516     boost::asio::execution::relationship_t::continuation_t
517   >
518 {
519   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
520   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
521   typedef boost::asio::basic_system_executor<Blocking,
522       boost::asio::execution::relationship_t::continuation_t,
523       Allocator> result_type;
524 };
525 
526 template <typename Blocking, typename Relationship, typename Allocator>
527 struct require_member<
528     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
529     boost::asio::execution::allocator_t<void>
530   >
531 {
532   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
533   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
534   typedef boost::asio::basic_system_executor<Blocking,
535       Relationship, std::allocator<void> > result_type;
536 };
537 
538 template <typename Blocking, typename Relationship,
539     typename Allocator, typename OtherAllocator>
540 struct require_member<
541     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
542     boost::asio::execution::allocator_t<OtherAllocator>
543   >
544 {
545   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
546   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
547   typedef boost::asio::basic_system_executor<Blocking,
548       Relationship, OtherAllocator> result_type;
549 };
550 
551 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
552 
553 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
554 
555 template <typename Blocking, typename Relationship,
556     typename Allocator, typename Property>
557 struct query_static_constexpr_member<
558     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
559     Property,
560     typename boost::asio::enable_if<
561       boost::asio::is_convertible<
562         Property,
563         boost::asio::execution::mapping_t
564       >::value
565     >::type
566   >
567 {
568   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
569   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
570   typedef boost::asio::execution::mapping_t::thread_t result_type;
571 
valueboost::asio::traits::query_static_constexpr_member572   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
573   {
574     return result_type();
575   }
576 };
577 
578 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
579 
580 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
581 
582 template <typename Blocking, typename Relationship,
583     typename Allocator, typename Property>
584 struct query_member<
585     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
586     Property,
587     typename boost::asio::enable_if<
588       boost::asio::is_convertible<
589         Property,
590         boost::asio::execution::blocking_t
591       >::value
592     >::type
593   >
594 {
595   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
596   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
597   typedef boost::asio::execution::blocking_t result_type;
598 };
599 
600 template <typename Blocking, typename Relationship,
601     typename Allocator, typename Property>
602 struct query_member<
603     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
604     Property,
605     typename boost::asio::enable_if<
606       boost::asio::is_convertible<
607         Property,
608         boost::asio::execution::relationship_t
609       >::value
610     >::type
611   >
612 {
613   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
614   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
615   typedef boost::asio::execution::relationship_t result_type;
616 };
617 
618 template <typename Blocking, typename Relationship, typename Allocator>
619 struct query_member<
620     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
621     boost::asio::execution::context_t
622   >
623 {
624   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
625   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
626   typedef boost::asio::system_context& result_type;
627 };
628 
629 template <typename Blocking, typename Relationship, typename Allocator>
630 struct query_member<
631     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
632     boost::asio::execution::allocator_t<void>
633   >
634 {
635   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
636   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
637   typedef Allocator result_type;
638 };
639 
640 template <typename Blocking, typename Relationship, typename Allocator>
641 struct query_member<
642     boost::asio::basic_system_executor<Blocking, Relationship, Allocator>,
643     boost::asio::execution::allocator_t<Allocator>
644   >
645 {
646   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
647   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
648   typedef Allocator result_type;
649 };
650 
651 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
652 
653 } // namespace traits
654 
655 #endif // !defined(GENERATING_DOCUMENTATION)
656 
657 } // namespace asio
658 } // namespace boost
659 
660 #include <boost/asio/detail/pop_options.hpp>
661 
662 #include <boost/asio/impl/system_executor.hpp>
663 
664 #endif // BOOST_ASIO_SYSTEM_EXECUTOR_HPP
665