1//
2// any_completion_handler.hpp
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#ifndef BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP
12#define BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP
13
14#include <boost/asio/detail/config.hpp>
15#include <cstring>
16#include <functional>
17#include <memory>
18#include <utility>
19#include <boost/asio/any_completion_executor.hpp>
20#include <boost/asio/any_io_executor.hpp>
21#include <boost/asio/associated_allocator.hpp>
22#include <boost/asio/associated_cancellation_slot.hpp>
23#include <boost/asio/associated_executor.hpp>
24#include <boost/asio/associated_immediate_executor.hpp>
25#include <boost/asio/cancellation_state.hpp>
26#include <boost/asio/recycling_allocator.hpp>
27
28#include <boost/asio/detail/push_options.hpp>
29
30namespace boost {
31namespace asio {
32namespace detail {
33
34class any_completion_handler_impl_base
35{
36public:
37 template <typename S>
38 explicit any_completion_handler_impl_base(S&& slot)
39 : cancel_state_(static_cast<S&&>(slot), enable_total_cancellation())
40 {
41 }
42
43 cancellation_slot get_cancellation_slot() const noexcept
44 {
45 return cancel_state_.slot();
46 }
47
48private:
49 cancellation_state cancel_state_;
50};
51
52template <typename Handler>
53class any_completion_handler_impl :
54 public any_completion_handler_impl_base
55{
56public:
57 template <typename S, typename H>
58 any_completion_handler_impl(S&& slot, H&& h)
59 : any_completion_handler_impl_base(static_cast<S&&>(slot)),
60 handler_(static_cast<H&&>(h))
61 {
62 }
63
64 struct uninit_deleter
65 {
66 typename std::allocator_traits<
67 associated_allocator_t<Handler,
68 boost::asio::recycling_allocator<void>>>::template
69 rebind_alloc<any_completion_handler_impl> alloc;
70
71 void operator()(any_completion_handler_impl* ptr)
72 {
73 std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
74 }
75 };
76
77 struct deleter
78 {
79 typename std::allocator_traits<
80 associated_allocator_t<Handler,
81 boost::asio::recycling_allocator<void>>>::template
82 rebind_alloc<any_completion_handler_impl> alloc;
83
84 void operator()(any_completion_handler_impl* ptr)
85 {
86 std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr);
87 std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
88 }
89 };
90
91 template <typename S, typename H>
92 static any_completion_handler_impl* create(S&& slot, H&& h)
93 {
94 uninit_deleter d{
95 (get_associated_allocator)(h,
96 boost::asio::recycling_allocator<void>())};
97
98 std::unique_ptr<any_completion_handler_impl, uninit_deleter> uninit_ptr(
99 std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d);
100
101 any_completion_handler_impl* ptr =
102 new (uninit_ptr.get()) any_completion_handler_impl(
103 static_cast<S&&>(slot), static_cast<H&&>(h));
104
105 uninit_ptr.release();
106 return ptr;
107 }
108
109 void destroy()
110 {
111 deleter d{
112 (get_associated_allocator)(handler_,
113 boost::asio::recycling_allocator<void>())};
114
115 d(this);
116 }
117
118 any_completion_executor executor(
119 const any_completion_executor& candidate) const noexcept
120 {
121 return any_completion_executor(std::nothrow,
122 (get_associated_executor)(handler_, candidate));
123 }
124
125 any_completion_executor immediate_executor(
126 const any_io_executor& candidate) const noexcept
127 {
128 return any_completion_executor(std::nothrow,
129 (get_associated_immediate_executor)(handler_, candidate));
130 }
131
132 void* allocate(std::size_t size, std::size_t align) const
133 {
134 typename std::allocator_traits<
135 associated_allocator_t<Handler,
136 boost::asio::recycling_allocator<void>>>::template
137 rebind_alloc<unsigned char> alloc(
138 (get_associated_allocator)(handler_,
139 boost::asio::recycling_allocator<void>()));
140
141 std::size_t space = size + align - 1;
142 unsigned char* base =
143 std::allocator_traits<decltype(alloc)>::allocate(
144 alloc, space + sizeof(std::ptrdiff_t));
145
146 void* p = base;
147 if (detail::align(alignment: align, size, ptr&: p, space))
148 {
149 std::ptrdiff_t off = static_cast<unsigned char*>(p) - base;
150 std::memcpy(dest: static_cast<unsigned char*>(p) + size, src: &off, n: sizeof(off));
151 return p;
152 }
153
154 std::bad_alloc ex;
155 boost::asio::detail::throw_exception(e: ex);
156 return nullptr;
157 }
158
159 void deallocate(void* p, std::size_t size, std::size_t align) const
160 {
161 if (p)
162 {
163 typename std::allocator_traits<
164 associated_allocator_t<Handler,
165 boost::asio::recycling_allocator<void>>>::template
166 rebind_alloc<unsigned char> alloc(
167 (get_associated_allocator)(handler_,
168 boost::asio::recycling_allocator<void>()));
169
170 std::ptrdiff_t off;
171 std::memcpy(dest: &off, src: static_cast<unsigned char*>(p) + size, n: sizeof(off));
172 unsigned char* base = static_cast<unsigned char*>(p) - off;
173
174 std::allocator_traits<decltype(alloc)>::deallocate(
175 alloc, base, size + align -1 + sizeof(std::ptrdiff_t));
176 }
177 }
178
179 template <typename... Args>
180 void call(Args&&... args)
181 {
182 deleter d{
183 (get_associated_allocator)(handler_,
184 boost::asio::recycling_allocator<void>())};
185
186 std::unique_ptr<any_completion_handler_impl, deleter> ptr(this, d);
187 Handler handler(static_cast<Handler&&>(handler_));
188 ptr.reset();
189
190 static_cast<Handler&&>(handler)(
191 static_cast<Args&&>(args)...);
192 }
193
194private:
195 Handler handler_;
196};
197
198template <typename Signature>
199class any_completion_handler_call_fn;
200
201template <typename R, typename... Args>
202class any_completion_handler_call_fn<R(Args...)>
203{
204public:
205 using type = void(*)(any_completion_handler_impl_base*, Args...);
206
207 constexpr any_completion_handler_call_fn(type fn)
208 : call_fn_(fn)
209 {
210 }
211
212 void call(any_completion_handler_impl_base* impl, Args... args) const
213 {
214 call_fn_(impl, static_cast<Args&&>(args)...);
215 }
216
217 template <typename Handler>
218 static void impl(any_completion_handler_impl_base* impl, Args... args)
219 {
220 static_cast<any_completion_handler_impl<Handler>*>(impl)->call(
221 static_cast<Args&&>(args)...);
222 }
223
224private:
225 type call_fn_;
226};
227
228template <typename... Signatures>
229class any_completion_handler_call_fns;
230
231template <typename Signature>
232class any_completion_handler_call_fns<Signature> :
233 public any_completion_handler_call_fn<Signature>
234{
235public:
236 using any_completion_handler_call_fn<
237 Signature>::any_completion_handler_call_fn;
238 using any_completion_handler_call_fn<Signature>::call;
239};
240
241template <typename Signature, typename... Signatures>
242class any_completion_handler_call_fns<Signature, Signatures...> :
243 public any_completion_handler_call_fn<Signature>,
244 public any_completion_handler_call_fns<Signatures...>
245{
246public:
247 template <typename CallFn, typename... CallFns>
248 constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns)
249 : any_completion_handler_call_fn<Signature>(fn),
250 any_completion_handler_call_fns<Signatures...>(fns...)
251 {
252 }
253
254 using any_completion_handler_call_fn<Signature>::call;
255 using any_completion_handler_call_fns<Signatures...>::call;
256};
257
258class any_completion_handler_destroy_fn
259{
260public:
261 using type = void(*)(any_completion_handler_impl_base*);
262
263 constexpr any_completion_handler_destroy_fn(type fn)
264 : destroy_fn_(fn)
265 {
266 }
267
268 void destroy(any_completion_handler_impl_base* impl) const
269 {
270 destroy_fn_(impl);
271 }
272
273 template <typename Handler>
274 static void impl(any_completion_handler_impl_base* impl)
275 {
276 static_cast<any_completion_handler_impl<Handler>*>(impl)->destroy();
277 }
278
279private:
280 type destroy_fn_;
281};
282
283class any_completion_handler_executor_fn
284{
285public:
286 using type = any_completion_executor(*)(
287 any_completion_handler_impl_base*, const any_completion_executor&);
288
289 constexpr any_completion_handler_executor_fn(type fn)
290 : executor_fn_(fn)
291 {
292 }
293
294 any_completion_executor executor(any_completion_handler_impl_base* impl,
295 const any_completion_executor& candidate) const
296 {
297 return executor_fn_(impl, candidate);
298 }
299
300 template <typename Handler>
301 static any_completion_executor impl(any_completion_handler_impl_base* impl,
302 const any_completion_executor& candidate)
303 {
304 return static_cast<any_completion_handler_impl<Handler>*>(impl)->executor(
305 candidate);
306 }
307
308private:
309 type executor_fn_;
310};
311
312class any_completion_handler_immediate_executor_fn
313{
314public:
315 using type = any_completion_executor(*)(
316 any_completion_handler_impl_base*, const any_io_executor&);
317
318 constexpr any_completion_handler_immediate_executor_fn(type fn)
319 : immediate_executor_fn_(fn)
320 {
321 }
322
323 any_completion_executor immediate_executor(
324 any_completion_handler_impl_base* impl,
325 const any_io_executor& candidate) const
326 {
327 return immediate_executor_fn_(impl, candidate);
328 }
329
330 template <typename Handler>
331 static any_completion_executor impl(any_completion_handler_impl_base* impl,
332 const any_io_executor& candidate)
333 {
334 return static_cast<any_completion_handler_impl<Handler>*>(
335 impl)->immediate_executor(candidate);
336 }
337
338private:
339 type immediate_executor_fn_;
340};
341
342class any_completion_handler_allocate_fn
343{
344public:
345 using type = void*(*)(any_completion_handler_impl_base*,
346 std::size_t, std::size_t);
347
348 constexpr any_completion_handler_allocate_fn(type fn)
349 : allocate_fn_(fn)
350 {
351 }
352
353 void* allocate(any_completion_handler_impl_base* impl,
354 std::size_t size, std::size_t align) const
355 {
356 return allocate_fn_(impl, size, align);
357 }
358
359 template <typename Handler>
360 static void* impl(any_completion_handler_impl_base* impl,
361 std::size_t size, std::size_t align)
362 {
363 return static_cast<any_completion_handler_impl<Handler>*>(impl)->allocate(
364 size, align);
365 }
366
367private:
368 type allocate_fn_;
369};
370
371class any_completion_handler_deallocate_fn
372{
373public:
374 using type = void(*)(any_completion_handler_impl_base*,
375 void*, std::size_t, std::size_t);
376
377 constexpr any_completion_handler_deallocate_fn(type fn)
378 : deallocate_fn_(fn)
379 {
380 }
381
382 void deallocate(any_completion_handler_impl_base* impl,
383 void* p, std::size_t size, std::size_t align) const
384 {
385 deallocate_fn_(impl, p, size, align);
386 }
387
388 template <typename Handler>
389 static void impl(any_completion_handler_impl_base* impl,
390 void* p, std::size_t size, std::size_t align)
391 {
392 static_cast<any_completion_handler_impl<Handler>*>(impl)->deallocate(
393 p, size, align);
394 }
395
396private:
397 type deallocate_fn_;
398};
399
400template <typename... Signatures>
401class any_completion_handler_fn_table
402 : private any_completion_handler_destroy_fn,
403 private any_completion_handler_executor_fn,
404 private any_completion_handler_immediate_executor_fn,
405 private any_completion_handler_allocate_fn,
406 private any_completion_handler_deallocate_fn,
407 private any_completion_handler_call_fns<Signatures...>
408{
409public:
410 template <typename... CallFns>
411 constexpr any_completion_handler_fn_table(
412 any_completion_handler_destroy_fn::type destroy_fn,
413 any_completion_handler_executor_fn::type executor_fn,
414 any_completion_handler_immediate_executor_fn::type immediate_executor_fn,
415 any_completion_handler_allocate_fn::type allocate_fn,
416 any_completion_handler_deallocate_fn::type deallocate_fn,
417 CallFns... call_fns)
418 : any_completion_handler_destroy_fn(destroy_fn),
419 any_completion_handler_executor_fn(executor_fn),
420 any_completion_handler_immediate_executor_fn(immediate_executor_fn),
421 any_completion_handler_allocate_fn(allocate_fn),
422 any_completion_handler_deallocate_fn(deallocate_fn),
423 any_completion_handler_call_fns<Signatures...>(call_fns...)
424 {
425 }
426
427 using any_completion_handler_destroy_fn::destroy;
428 using any_completion_handler_executor_fn::executor;
429 using any_completion_handler_immediate_executor_fn::immediate_executor;
430 using any_completion_handler_allocate_fn::allocate;
431 using any_completion_handler_deallocate_fn::deallocate;
432 using any_completion_handler_call_fns<Signatures...>::call;
433};
434
435template <typename Handler, typename... Signatures>
436struct any_completion_handler_fn_table_instance
437{
438 static constexpr any_completion_handler_fn_table<Signatures...>
439 value = any_completion_handler_fn_table<Signatures...>(
440 &any_completion_handler_destroy_fn::impl<Handler>,
441 &any_completion_handler_executor_fn::impl<Handler>,
442 &any_completion_handler_immediate_executor_fn::impl<Handler>,
443 &any_completion_handler_allocate_fn::impl<Handler>,
444 &any_completion_handler_deallocate_fn::impl<Handler>,
445 &any_completion_handler_call_fn<Signatures>::template impl<Handler>...);
446};
447
448template <typename Handler, typename... Signatures>
449constexpr any_completion_handler_fn_table<Signatures...>
450any_completion_handler_fn_table_instance<Handler, Signatures...>::value;
451
452} // namespace detail
453
454template <typename... Signatures>
455class any_completion_handler;
456
457/// An allocator type that forwards memory allocation operations through an
458/// instance of @c any_completion_handler.
459template <typename T, typename... Signatures>
460class any_completion_handler_allocator
461{
462private:
463 template <typename...>
464 friend class any_completion_handler;
465
466 template <typename, typename...>
467 friend class any_completion_handler_allocator;
468
469 const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
470 detail::any_completion_handler_impl_base* impl_;
471
472 constexpr any_completion_handler_allocator(int,
473 const any_completion_handler<Signatures...>& h) noexcept
474 : fn_table_(h.fn_table_),
475 impl_(h.impl_)
476 {
477 }
478
479public:
480 /// The type of objects that may be allocated by the allocator.
481 typedef T value_type;
482
483 /// Rebinds an allocator to another value type.
484 template <typename U>
485 struct rebind
486 {
487 /// Specifies the type of the rebound allocator.
488 typedef any_completion_handler_allocator<U, Signatures...> other;
489 };
490
491 /// Construct from another @c any_completion_handler_allocator.
492 template <typename U>
493 constexpr any_completion_handler_allocator(
494 const any_completion_handler_allocator<U, Signatures...>& a)
495 noexcept
496 : fn_table_(a.fn_table_),
497 impl_(a.impl_)
498 {
499 }
500
501 /// Equality operator.
502 constexpr bool operator==(
503 const any_completion_handler_allocator& other) const noexcept
504 {
505 return fn_table_ == other.fn_table_ && impl_ == other.impl_;
506 }
507
508 /// Inequality operator.
509 constexpr bool operator!=(
510 const any_completion_handler_allocator& other) const noexcept
511 {
512 return fn_table_ != other.fn_table_ || impl_ != other.impl_;
513 }
514
515 /// Allocate space for @c n objects of the allocator's value type.
516 T* allocate(std::size_t n) const
517 {
518 if (fn_table_)
519 {
520 return static_cast<T*>(
521 fn_table_->allocate(
522 impl_, sizeof(T) * n, alignof(T)));
523 }
524 std::bad_alloc ex;
525 boost::asio::detail::throw_exception(e: ex);
526 return nullptr;
527 }
528
529 /// Deallocate space for @c n objects of the allocator's value type.
530 void deallocate(T* p, std::size_t n) const
531 {
532 fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T));
533 }
534};
535
536/// A protoco-allocator type that may be rebound to obtain an allocator that
537/// forwards memory allocation operations through an instance of
538/// @c any_completion_handler.
539template <typename... Signatures>
540class any_completion_handler_allocator<void, Signatures...>
541{
542private:
543 template <typename...>
544 friend class any_completion_handler;
545
546 template <typename, typename...>
547 friend class any_completion_handler_allocator;
548
549 const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
550 detail::any_completion_handler_impl_base* impl_;
551
552 constexpr any_completion_handler_allocator(int,
553 const any_completion_handler<Signatures...>& h) noexcept
554 : fn_table_(h.fn_table_),
555 impl_(h.impl_)
556 {
557 }
558
559public:
560 /// @c void as no objects can be allocated through a proto-allocator.
561 typedef void value_type;
562
563 /// Rebinds an allocator to another value type.
564 template <typename U>
565 struct rebind
566 {
567 /// Specifies the type of the rebound allocator.
568 typedef any_completion_handler_allocator<U, Signatures...> other;
569 };
570
571 /// Construct from another @c any_completion_handler_allocator.
572 template <typename U>
573 constexpr any_completion_handler_allocator(
574 const any_completion_handler_allocator<U, Signatures...>& a)
575 noexcept
576 : fn_table_(a.fn_table_),
577 impl_(a.impl_)
578 {
579 }
580
581 /// Equality operator.
582 constexpr bool operator==(
583 const any_completion_handler_allocator& other) const noexcept
584 {
585 return fn_table_ == other.fn_table_ && impl_ == other.impl_;
586 }
587
588 /// Inequality operator.
589 constexpr bool operator!=(
590 const any_completion_handler_allocator& other) const noexcept
591 {
592 return fn_table_ != other.fn_table_ || impl_ != other.impl_;
593 }
594};
595
596/// Polymorphic wrapper for completion handlers.
597/**
598 * The @c any_completion_handler class template is a polymorphic wrapper for
599 * completion handlers that propagates the associated executor, associated
600 * allocator, and associated cancellation slot through a type-erasing interface.
601 *
602 * When using @c any_completion_handler, specify one or more completion
603 * signatures as template parameters. These will dictate the arguments that may
604 * be passed to the handler through the polymorphic interface.
605 *
606 * Typical uses for @c any_completion_handler include:
607 *
608 * @li Separate compilation of asynchronous operation implementations.
609 *
610 * @li Enabling interoperability between asynchronous operations and virtual
611 * functions.
612 */
613template <typename... Signatures>
614class any_completion_handler
615{
616#if !defined(GENERATING_DOCUMENTATION)
617private:
618 template <typename, typename...>
619 friend class any_completion_handler_allocator;
620
621 template <typename, typename>
622 friend struct associated_executor;
623
624 template <typename, typename>
625 friend struct associated_immediate_executor;
626
627 const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
628 detail::any_completion_handler_impl_base* impl_;
629#endif // !defined(GENERATING_DOCUMENTATION)
630
631public:
632 /// The associated allocator type.
633 using allocator_type = any_completion_handler_allocator<void, Signatures...>;
634
635 /// The associated cancellation slot type.
636 using cancellation_slot_type = cancellation_slot;
637
638 /// Construct an @c any_completion_handler in an empty state, without a target
639 /// object.
640 constexpr any_completion_handler()
641 : fn_table_(nullptr),
642 impl_(nullptr)
643 {
644 }
645
646 /// Construct an @c any_completion_handler in an empty state, without a target
647 /// object.
648 constexpr any_completion_handler(nullptr_t)
649 : fn_table_(nullptr),
650 impl_(nullptr)
651 {
652 }
653
654 /// Construct an @c any_completion_handler to contain the specified target.
655 template <typename H, typename Handler = decay_t<H>>
656 any_completion_handler(H&& h,
657 constraint_t<
658 !is_same<decay_t<H>, any_completion_handler>::value
659 > = 0)
660 : fn_table_(
661 &detail::any_completion_handler_fn_table_instance<
662 Handler, Signatures...>::value),
663 impl_(detail::any_completion_handler_impl<Handler>::create(
664 (get_associated_cancellation_slot)(h), static_cast<H&&>(h)))
665 {
666 }
667
668 /// Move-construct an @c any_completion_handler from another.
669 /**
670 * After the operation, the moved-from object @c other has no target.
671 */
672 any_completion_handler(any_completion_handler&& other) noexcept
673 : fn_table_(other.fn_table_),
674 impl_(other.impl_)
675 {
676 other.fn_table_ = nullptr;
677 other.impl_ = nullptr;
678 }
679
680 /// Move-assign an @c any_completion_handler from another.
681 /**
682 * After the operation, the moved-from object @c other has no target.
683 */
684 any_completion_handler& operator=(
685 any_completion_handler&& other) noexcept
686 {
687 any_completion_handler(
688 static_cast<any_completion_handler&&>(other)).swap(*this);
689 return *this;
690 }
691
692 /// Assignment operator that sets the polymorphic wrapper to the empty state.
693 any_completion_handler& operator=(nullptr_t) noexcept
694 {
695 any_completion_handler().swap(*this);
696 return *this;
697 }
698
699 /// Destructor.
700 ~any_completion_handler()
701 {
702 if (impl_)
703 fn_table_->destroy(impl_);
704 }
705
706 /// Test if the polymorphic wrapper is empty.
707 constexpr explicit operator bool() const noexcept
708 {
709 return impl_ != nullptr;
710 }
711
712 /// Test if the polymorphic wrapper is non-empty.
713 constexpr bool operator!() const noexcept
714 {
715 return impl_ == nullptr;
716 }
717
718 /// Swap the content of an @c any_completion_handler with another.
719 void swap(any_completion_handler& other) noexcept
720 {
721 std::swap(fn_table_, other.fn_table_);
722 std::swap(impl_, other.impl_);
723 }
724
725 /// Get the associated allocator.
726 allocator_type get_allocator() const noexcept
727 {
728 return allocator_type(0, *this);
729 }
730
731 /// Get the associated cancellation slot.
732 cancellation_slot_type get_cancellation_slot() const noexcept
733 {
734 return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type();
735 }
736
737 /// Function call operator.
738 /**
739 * Invokes target completion handler with the supplied arguments.
740 *
741 * This function may only be called once, as the target handler is moved from.
742 * The polymorphic wrapper is left in an empty state.
743 *
744 * Throws @c std::bad_function_call if the polymorphic wrapper is empty.
745 */
746 template <typename... Args>
747 auto operator()(Args&&... args)
748 -> decltype(fn_table_->call(impl_, static_cast<Args&&>(args)...))
749 {
750 if (detail::any_completion_handler_impl_base* impl = impl_)
751 {
752 impl_ = nullptr;
753 return fn_table_->call(impl, static_cast<Args&&>(args)...);
754 }
755 std::bad_function_call ex;
756 boost::asio::detail::throw_exception(e: ex);
757 }
758
759 /// Equality operator.
760 friend constexpr bool operator==(
761 const any_completion_handler& a, nullptr_t) noexcept
762 {
763 return a.impl_ == nullptr;
764 }
765
766 /// Equality operator.
767 friend constexpr bool operator==(
768 nullptr_t, const any_completion_handler& b) noexcept
769 {
770 return nullptr == b.impl_;
771 }
772
773 /// Inequality operator.
774 friend constexpr bool operator!=(
775 const any_completion_handler& a, nullptr_t) noexcept
776 {
777 return a.impl_ != nullptr;
778 }
779
780 /// Inequality operator.
781 friend constexpr bool operator!=(
782 nullptr_t, const any_completion_handler& b) noexcept
783 {
784 return nullptr != b.impl_;
785 }
786};
787
788template <typename... Signatures, typename Candidate>
789struct associated_executor<any_completion_handler<Signatures...>, Candidate>
790{
791 using type = any_completion_executor;
792
793 static type get(const any_completion_handler<Signatures...>& handler,
794 const Candidate& candidate = Candidate()) noexcept
795 {
796 any_completion_executor any_candidate(std::nothrow, candidate);
797 return handler.fn_table_
798 ? handler.fn_table_->executor(handler.impl_, any_candidate)
799 : any_candidate;
800 }
801};
802
803template <typename... Signatures, typename Candidate>
804struct associated_immediate_executor<
805 any_completion_handler<Signatures...>, Candidate>
806{
807 using type = any_completion_executor;
808
809 static type get(const any_completion_handler<Signatures...>& handler,
810 const Candidate& candidate = Candidate()) noexcept
811 {
812 any_io_executor any_candidate(std::nothrow, candidate);
813 return handler.fn_table_
814 ? handler.fn_table_->immediate_executor(handler.impl_, any_candidate)
815 : any_candidate;
816 }
817};
818
819} // namespace asio
820} // namespace boost
821
822#include <boost/asio/detail/pop_options.hpp>
823
824#endif // BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP
825

source code of boost/libs/asio/include/boost/asio/any_completion_handler.hpp