File indexing completed on 2025-01-30 09:33:38
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP
0012 #define BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP
0013
0014 #include <boost/asio/detail/config.hpp>
0015 #include <cstring>
0016 #include <functional>
0017 #include <memory>
0018 #include <utility>
0019 #include <boost/asio/any_completion_executor.hpp>
0020 #include <boost/asio/any_io_executor.hpp>
0021 #include <boost/asio/associated_allocator.hpp>
0022 #include <boost/asio/associated_cancellation_slot.hpp>
0023 #include <boost/asio/associated_executor.hpp>
0024 #include <boost/asio/associated_immediate_executor.hpp>
0025 #include <boost/asio/cancellation_state.hpp>
0026 #include <boost/asio/recycling_allocator.hpp>
0027
0028 #include <boost/asio/detail/push_options.hpp>
0029
0030 namespace boost {
0031 namespace asio {
0032 namespace detail {
0033
0034 class any_completion_handler_impl_base
0035 {
0036 public:
0037 template <typename S>
0038 explicit any_completion_handler_impl_base(S&& slot)
0039 : cancel_state_(static_cast<S&&>(slot), enable_total_cancellation())
0040 {
0041 }
0042
0043 cancellation_slot get_cancellation_slot() const noexcept
0044 {
0045 return cancel_state_.slot();
0046 }
0047
0048 private:
0049 cancellation_state cancel_state_;
0050 };
0051
0052 template <typename Handler>
0053 class any_completion_handler_impl :
0054 public any_completion_handler_impl_base
0055 {
0056 public:
0057 template <typename S, typename H>
0058 any_completion_handler_impl(S&& slot, H&& h)
0059 : any_completion_handler_impl_base(static_cast<S&&>(slot)),
0060 handler_(static_cast<H&&>(h))
0061 {
0062 }
0063
0064 struct uninit_deleter
0065 {
0066 typename std::allocator_traits<
0067 associated_allocator_t<Handler,
0068 boost::asio::recycling_allocator<void>>>::template
0069 rebind_alloc<any_completion_handler_impl> alloc;
0070
0071 void operator()(any_completion_handler_impl* ptr)
0072 {
0073 std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
0074 }
0075 };
0076
0077 struct deleter
0078 {
0079 typename std::allocator_traits<
0080 associated_allocator_t<Handler,
0081 boost::asio::recycling_allocator<void>>>::template
0082 rebind_alloc<any_completion_handler_impl> alloc;
0083
0084 void operator()(any_completion_handler_impl* ptr)
0085 {
0086 std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr);
0087 std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
0088 }
0089 };
0090
0091 template <typename S, typename H>
0092 static any_completion_handler_impl* create(S&& slot, H&& h)
0093 {
0094 uninit_deleter d{
0095 (get_associated_allocator)(h,
0096 boost::asio::recycling_allocator<void>())};
0097
0098 std::unique_ptr<any_completion_handler_impl, uninit_deleter> uninit_ptr(
0099 std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d);
0100
0101 any_completion_handler_impl* ptr =
0102 new (uninit_ptr.get()) any_completion_handler_impl(
0103 static_cast<S&&>(slot), static_cast<H&&>(h));
0104
0105 uninit_ptr.release();
0106 return ptr;
0107 }
0108
0109 void destroy()
0110 {
0111 deleter d{
0112 (get_associated_allocator)(handler_,
0113 boost::asio::recycling_allocator<void>())};
0114
0115 d(this);
0116 }
0117
0118 any_completion_executor executor(
0119 const any_completion_executor& candidate) const noexcept
0120 {
0121 return any_completion_executor(std::nothrow,
0122 (get_associated_executor)(handler_, candidate));
0123 }
0124
0125 any_completion_executor immediate_executor(
0126 const any_io_executor& candidate) const noexcept
0127 {
0128 return any_completion_executor(std::nothrow,
0129 (get_associated_immediate_executor)(handler_, candidate));
0130 }
0131
0132 void* allocate(std::size_t size, std::size_t align) const
0133 {
0134 typename std::allocator_traits<
0135 associated_allocator_t<Handler,
0136 boost::asio::recycling_allocator<void>>>::template
0137 rebind_alloc<unsigned char> alloc(
0138 (get_associated_allocator)(handler_,
0139 boost::asio::recycling_allocator<void>()));
0140
0141 std::size_t space = size + align - 1;
0142 unsigned char* base =
0143 std::allocator_traits<decltype(alloc)>::allocate(
0144 alloc, space + sizeof(std::ptrdiff_t));
0145
0146 void* p = base;
0147 if (detail::align(align, size, p, space))
0148 {
0149 std::ptrdiff_t off = static_cast<unsigned char*>(p) - base;
0150 std::memcpy(static_cast<unsigned char*>(p) + size, &off, sizeof(off));
0151 return p;
0152 }
0153
0154 std::bad_alloc ex;
0155 boost::asio::detail::throw_exception(ex);
0156 return nullptr;
0157 }
0158
0159 void deallocate(void* p, std::size_t size, std::size_t align) const
0160 {
0161 if (p)
0162 {
0163 typename std::allocator_traits<
0164 associated_allocator_t<Handler,
0165 boost::asio::recycling_allocator<void>>>::template
0166 rebind_alloc<unsigned char> alloc(
0167 (get_associated_allocator)(handler_,
0168 boost::asio::recycling_allocator<void>()));
0169
0170 std::ptrdiff_t off;
0171 std::memcpy(&off, static_cast<unsigned char*>(p) + size, sizeof(off));
0172 unsigned char* base = static_cast<unsigned char*>(p) - off;
0173
0174 std::allocator_traits<decltype(alloc)>::deallocate(
0175 alloc, base, size + align -1 + sizeof(std::ptrdiff_t));
0176 }
0177 }
0178
0179 template <typename... Args>
0180 void call(Args&&... args)
0181 {
0182 deleter d{
0183 (get_associated_allocator)(handler_,
0184 boost::asio::recycling_allocator<void>())};
0185
0186 std::unique_ptr<any_completion_handler_impl, deleter> ptr(this, d);
0187 Handler handler(static_cast<Handler&&>(handler_));
0188 ptr.reset();
0189
0190 static_cast<Handler&&>(handler)(
0191 static_cast<Args&&>(args)...);
0192 }
0193
0194 private:
0195 Handler handler_;
0196 };
0197
0198 template <typename Signature>
0199 class any_completion_handler_call_fn;
0200
0201 template <typename R, typename... Args>
0202 class any_completion_handler_call_fn<R(Args...)>
0203 {
0204 public:
0205 using type = void(*)(any_completion_handler_impl_base*, Args...);
0206
0207 constexpr any_completion_handler_call_fn(type fn)
0208 : call_fn_(fn)
0209 {
0210 }
0211
0212 void call(any_completion_handler_impl_base* impl, Args... args) const
0213 {
0214 call_fn_(impl, static_cast<Args&&>(args)...);
0215 }
0216
0217 template <typename Handler>
0218 static void impl(any_completion_handler_impl_base* impl, Args... args)
0219 {
0220 static_cast<any_completion_handler_impl<Handler>*>(impl)->call(
0221 static_cast<Args&&>(args)...);
0222 }
0223
0224 private:
0225 type call_fn_;
0226 };
0227
0228 template <typename... Signatures>
0229 class any_completion_handler_call_fns;
0230
0231 template <typename Signature>
0232 class any_completion_handler_call_fns<Signature> :
0233 public any_completion_handler_call_fn<Signature>
0234 {
0235 public:
0236 using any_completion_handler_call_fn<
0237 Signature>::any_completion_handler_call_fn;
0238 using any_completion_handler_call_fn<Signature>::call;
0239 };
0240
0241 template <typename Signature, typename... Signatures>
0242 class any_completion_handler_call_fns<Signature, Signatures...> :
0243 public any_completion_handler_call_fn<Signature>,
0244 public any_completion_handler_call_fns<Signatures...>
0245 {
0246 public:
0247 template <typename CallFn, typename... CallFns>
0248 constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns)
0249 : any_completion_handler_call_fn<Signature>(fn),
0250 any_completion_handler_call_fns<Signatures...>(fns...)
0251 {
0252 }
0253
0254 using any_completion_handler_call_fn<Signature>::call;
0255 using any_completion_handler_call_fns<Signatures...>::call;
0256 };
0257
0258 class any_completion_handler_destroy_fn
0259 {
0260 public:
0261 using type = void(*)(any_completion_handler_impl_base*);
0262
0263 constexpr any_completion_handler_destroy_fn(type fn)
0264 : destroy_fn_(fn)
0265 {
0266 }
0267
0268 void destroy(any_completion_handler_impl_base* impl) const
0269 {
0270 destroy_fn_(impl);
0271 }
0272
0273 template <typename Handler>
0274 static void impl(any_completion_handler_impl_base* impl)
0275 {
0276 static_cast<any_completion_handler_impl<Handler>*>(impl)->destroy();
0277 }
0278
0279 private:
0280 type destroy_fn_;
0281 };
0282
0283 class any_completion_handler_executor_fn
0284 {
0285 public:
0286 using type = any_completion_executor(*)(
0287 any_completion_handler_impl_base*, const any_completion_executor&);
0288
0289 constexpr any_completion_handler_executor_fn(type fn)
0290 : executor_fn_(fn)
0291 {
0292 }
0293
0294 any_completion_executor executor(any_completion_handler_impl_base* impl,
0295 const any_completion_executor& candidate) const
0296 {
0297 return executor_fn_(impl, candidate);
0298 }
0299
0300 template <typename Handler>
0301 static any_completion_executor impl(any_completion_handler_impl_base* impl,
0302 const any_completion_executor& candidate)
0303 {
0304 return static_cast<any_completion_handler_impl<Handler>*>(impl)->executor(
0305 candidate);
0306 }
0307
0308 private:
0309 type executor_fn_;
0310 };
0311
0312 class any_completion_handler_immediate_executor_fn
0313 {
0314 public:
0315 using type = any_completion_executor(*)(
0316 any_completion_handler_impl_base*, const any_io_executor&);
0317
0318 constexpr any_completion_handler_immediate_executor_fn(type fn)
0319 : immediate_executor_fn_(fn)
0320 {
0321 }
0322
0323 any_completion_executor immediate_executor(
0324 any_completion_handler_impl_base* impl,
0325 const any_io_executor& candidate) const
0326 {
0327 return immediate_executor_fn_(impl, candidate);
0328 }
0329
0330 template <typename Handler>
0331 static any_completion_executor impl(any_completion_handler_impl_base* impl,
0332 const any_io_executor& candidate)
0333 {
0334 return static_cast<any_completion_handler_impl<Handler>*>(
0335 impl)->immediate_executor(candidate);
0336 }
0337
0338 private:
0339 type immediate_executor_fn_;
0340 };
0341
0342 class any_completion_handler_allocate_fn
0343 {
0344 public:
0345 using type = void*(*)(any_completion_handler_impl_base*,
0346 std::size_t, std::size_t);
0347
0348 constexpr any_completion_handler_allocate_fn(type fn)
0349 : allocate_fn_(fn)
0350 {
0351 }
0352
0353 void* allocate(any_completion_handler_impl_base* impl,
0354 std::size_t size, std::size_t align) const
0355 {
0356 return allocate_fn_(impl, size, align);
0357 }
0358
0359 template <typename Handler>
0360 static void* impl(any_completion_handler_impl_base* impl,
0361 std::size_t size, std::size_t align)
0362 {
0363 return static_cast<any_completion_handler_impl<Handler>*>(impl)->allocate(
0364 size, align);
0365 }
0366
0367 private:
0368 type allocate_fn_;
0369 };
0370
0371 class any_completion_handler_deallocate_fn
0372 {
0373 public:
0374 using type = void(*)(any_completion_handler_impl_base*,
0375 void*, std::size_t, std::size_t);
0376
0377 constexpr any_completion_handler_deallocate_fn(type fn)
0378 : deallocate_fn_(fn)
0379 {
0380 }
0381
0382 void deallocate(any_completion_handler_impl_base* impl,
0383 void* p, std::size_t size, std::size_t align) const
0384 {
0385 deallocate_fn_(impl, p, size, align);
0386 }
0387
0388 template <typename Handler>
0389 static void impl(any_completion_handler_impl_base* impl,
0390 void* p, std::size_t size, std::size_t align)
0391 {
0392 static_cast<any_completion_handler_impl<Handler>*>(impl)->deallocate(
0393 p, size, align);
0394 }
0395
0396 private:
0397 type deallocate_fn_;
0398 };
0399
0400 template <typename... Signatures>
0401 class any_completion_handler_fn_table
0402 : private any_completion_handler_destroy_fn,
0403 private any_completion_handler_executor_fn,
0404 private any_completion_handler_immediate_executor_fn,
0405 private any_completion_handler_allocate_fn,
0406 private any_completion_handler_deallocate_fn,
0407 private any_completion_handler_call_fns<Signatures...>
0408 {
0409 public:
0410 template <typename... CallFns>
0411 constexpr any_completion_handler_fn_table(
0412 any_completion_handler_destroy_fn::type destroy_fn,
0413 any_completion_handler_executor_fn::type executor_fn,
0414 any_completion_handler_immediate_executor_fn::type immediate_executor_fn,
0415 any_completion_handler_allocate_fn::type allocate_fn,
0416 any_completion_handler_deallocate_fn::type deallocate_fn,
0417 CallFns... call_fns)
0418 : any_completion_handler_destroy_fn(destroy_fn),
0419 any_completion_handler_executor_fn(executor_fn),
0420 any_completion_handler_immediate_executor_fn(immediate_executor_fn),
0421 any_completion_handler_allocate_fn(allocate_fn),
0422 any_completion_handler_deallocate_fn(deallocate_fn),
0423 any_completion_handler_call_fns<Signatures...>(call_fns...)
0424 {
0425 }
0426
0427 using any_completion_handler_destroy_fn::destroy;
0428 using any_completion_handler_executor_fn::executor;
0429 using any_completion_handler_immediate_executor_fn::immediate_executor;
0430 using any_completion_handler_allocate_fn::allocate;
0431 using any_completion_handler_deallocate_fn::deallocate;
0432 using any_completion_handler_call_fns<Signatures...>::call;
0433 };
0434
0435 template <typename Handler, typename... Signatures>
0436 struct any_completion_handler_fn_table_instance
0437 {
0438 static constexpr any_completion_handler_fn_table<Signatures...>
0439 value = any_completion_handler_fn_table<Signatures...>(
0440 &any_completion_handler_destroy_fn::impl<Handler>,
0441 &any_completion_handler_executor_fn::impl<Handler>,
0442 &any_completion_handler_immediate_executor_fn::impl<Handler>,
0443 &any_completion_handler_allocate_fn::impl<Handler>,
0444 &any_completion_handler_deallocate_fn::impl<Handler>,
0445 &any_completion_handler_call_fn<Signatures>::template impl<Handler>...);
0446 };
0447
0448 template <typename Handler, typename... Signatures>
0449 constexpr any_completion_handler_fn_table<Signatures...>
0450 any_completion_handler_fn_table_instance<Handler, Signatures...>::value;
0451
0452 }
0453
0454 template <typename... Signatures>
0455 class any_completion_handler;
0456
0457
0458
0459 template <typename T, typename... Signatures>
0460 class any_completion_handler_allocator
0461 {
0462 private:
0463 template <typename...>
0464 friend class any_completion_handler;
0465
0466 template <typename, typename...>
0467 friend class any_completion_handler_allocator;
0468
0469 const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
0470 detail::any_completion_handler_impl_base* impl_;
0471
0472 constexpr any_completion_handler_allocator(int,
0473 const any_completion_handler<Signatures...>& h) noexcept
0474 : fn_table_(h.fn_table_),
0475 impl_(h.impl_)
0476 {
0477 }
0478
0479 public:
0480
0481 typedef T value_type;
0482
0483
0484 template <typename U>
0485 struct rebind
0486 {
0487
0488 typedef any_completion_handler_allocator<U, Signatures...> other;
0489 };
0490
0491
0492 template <typename U>
0493 constexpr any_completion_handler_allocator(
0494 const any_completion_handler_allocator<U, Signatures...>& a)
0495 noexcept
0496 : fn_table_(a.fn_table_),
0497 impl_(a.impl_)
0498 {
0499 }
0500
0501
0502 constexpr bool operator==(
0503 const any_completion_handler_allocator& other) const noexcept
0504 {
0505 return fn_table_ == other.fn_table_ && impl_ == other.impl_;
0506 }
0507
0508
0509 constexpr bool operator!=(
0510 const any_completion_handler_allocator& other) const noexcept
0511 {
0512 return fn_table_ != other.fn_table_ || impl_ != other.impl_;
0513 }
0514
0515
0516 T* allocate(std::size_t n) const
0517 {
0518 if (fn_table_)
0519 {
0520 return static_cast<T*>(
0521 fn_table_->allocate(
0522 impl_, sizeof(T) * n, alignof(T)));
0523 }
0524 std::bad_alloc ex;
0525 boost::asio::detail::throw_exception(ex);
0526 return nullptr;
0527 }
0528
0529
0530 void deallocate(T* p, std::size_t n) const
0531 {
0532 fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T));
0533 }
0534 };
0535
0536
0537
0538
0539 template <typename... Signatures>
0540 class any_completion_handler_allocator<void, Signatures...>
0541 {
0542 private:
0543 template <typename...>
0544 friend class any_completion_handler;
0545
0546 template <typename, typename...>
0547 friend class any_completion_handler_allocator;
0548
0549 const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
0550 detail::any_completion_handler_impl_base* impl_;
0551
0552 constexpr any_completion_handler_allocator(int,
0553 const any_completion_handler<Signatures...>& h) noexcept
0554 : fn_table_(h.fn_table_),
0555 impl_(h.impl_)
0556 {
0557 }
0558
0559 public:
0560
0561 typedef void value_type;
0562
0563
0564 template <typename U>
0565 struct rebind
0566 {
0567
0568 typedef any_completion_handler_allocator<U, Signatures...> other;
0569 };
0570
0571
0572 template <typename U>
0573 constexpr any_completion_handler_allocator(
0574 const any_completion_handler_allocator<U, Signatures...>& a)
0575 noexcept
0576 : fn_table_(a.fn_table_),
0577 impl_(a.impl_)
0578 {
0579 }
0580
0581
0582 constexpr bool operator==(
0583 const any_completion_handler_allocator& other) const noexcept
0584 {
0585 return fn_table_ == other.fn_table_ && impl_ == other.impl_;
0586 }
0587
0588
0589 constexpr bool operator!=(
0590 const any_completion_handler_allocator& other) const noexcept
0591 {
0592 return fn_table_ != other.fn_table_ || impl_ != other.impl_;
0593 }
0594 };
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613 template <typename... Signatures>
0614 class any_completion_handler
0615 {
0616 #if !defined(GENERATING_DOCUMENTATION)
0617 private:
0618 template <typename, typename...>
0619 friend class any_completion_handler_allocator;
0620
0621 template <typename, typename>
0622 friend struct associated_executor;
0623
0624 template <typename, typename>
0625 friend struct associated_immediate_executor;
0626
0627 const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
0628 detail::any_completion_handler_impl_base* impl_;
0629 #endif
0630
0631 public:
0632
0633 using allocator_type = any_completion_handler_allocator<void, Signatures...>;
0634
0635
0636 using cancellation_slot_type = cancellation_slot;
0637
0638
0639
0640 constexpr any_completion_handler()
0641 : fn_table_(nullptr),
0642 impl_(nullptr)
0643 {
0644 }
0645
0646
0647
0648 constexpr any_completion_handler(nullptr_t)
0649 : fn_table_(nullptr),
0650 impl_(nullptr)
0651 {
0652 }
0653
0654
0655 template <typename H, typename Handler = decay_t<H>>
0656 any_completion_handler(H&& h,
0657 constraint_t<
0658 !is_same<decay_t<H>, any_completion_handler>::value
0659 > = 0)
0660 : fn_table_(
0661 &detail::any_completion_handler_fn_table_instance<
0662 Handler, Signatures...>::value),
0663 impl_(detail::any_completion_handler_impl<Handler>::create(
0664 (get_associated_cancellation_slot)(h), static_cast<H&&>(h)))
0665 {
0666 }
0667
0668
0669
0670
0671
0672 any_completion_handler(any_completion_handler&& other) noexcept
0673 : fn_table_(other.fn_table_),
0674 impl_(other.impl_)
0675 {
0676 other.fn_table_ = nullptr;
0677 other.impl_ = nullptr;
0678 }
0679
0680
0681
0682
0683
0684 any_completion_handler& operator=(
0685 any_completion_handler&& other) noexcept
0686 {
0687 any_completion_handler(
0688 static_cast<any_completion_handler&&>(other)).swap(*this);
0689 return *this;
0690 }
0691
0692
0693 any_completion_handler& operator=(nullptr_t) noexcept
0694 {
0695 any_completion_handler().swap(*this);
0696 return *this;
0697 }
0698
0699
0700 ~any_completion_handler()
0701 {
0702 if (impl_)
0703 fn_table_->destroy(impl_);
0704 }
0705
0706
0707 constexpr explicit operator bool() const noexcept
0708 {
0709 return impl_ != nullptr;
0710 }
0711
0712
0713 constexpr bool operator!() const noexcept
0714 {
0715 return impl_ == nullptr;
0716 }
0717
0718
0719 void swap(any_completion_handler& other) noexcept
0720 {
0721 std::swap(fn_table_, other.fn_table_);
0722 std::swap(impl_, other.impl_);
0723 }
0724
0725
0726 allocator_type get_allocator() const noexcept
0727 {
0728 return allocator_type(0, *this);
0729 }
0730
0731
0732 cancellation_slot_type get_cancellation_slot() const noexcept
0733 {
0734 return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type();
0735 }
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746 template <typename... Args>
0747 auto operator()(Args&&... args)
0748 -> decltype(fn_table_->call(impl_, static_cast<Args&&>(args)...))
0749 {
0750 if (detail::any_completion_handler_impl_base* impl = impl_)
0751 {
0752 impl_ = nullptr;
0753 return fn_table_->call(impl, static_cast<Args&&>(args)...);
0754 }
0755 std::bad_function_call ex;
0756 boost::asio::detail::throw_exception(ex);
0757 }
0758
0759
0760 friend constexpr bool operator==(
0761 const any_completion_handler& a, nullptr_t) noexcept
0762 {
0763 return a.impl_ == nullptr;
0764 }
0765
0766
0767 friend constexpr bool operator==(
0768 nullptr_t, const any_completion_handler& b) noexcept
0769 {
0770 return nullptr == b.impl_;
0771 }
0772
0773
0774 friend constexpr bool operator!=(
0775 const any_completion_handler& a, nullptr_t) noexcept
0776 {
0777 return a.impl_ != nullptr;
0778 }
0779
0780
0781 friend constexpr bool operator!=(
0782 nullptr_t, const any_completion_handler& b) noexcept
0783 {
0784 return nullptr != b.impl_;
0785 }
0786 };
0787
0788 template <typename... Signatures, typename Candidate>
0789 struct associated_executor<any_completion_handler<Signatures...>, Candidate>
0790 {
0791 using type = any_completion_executor;
0792
0793 static type get(const any_completion_handler<Signatures...>& handler,
0794 const Candidate& candidate = Candidate()) noexcept
0795 {
0796 any_completion_executor any_candidate(std::nothrow, candidate);
0797 return handler.fn_table_
0798 ? handler.fn_table_->executor(handler.impl_, any_candidate)
0799 : any_candidate;
0800 }
0801 };
0802
0803 template <typename... Signatures, typename Candidate>
0804 struct associated_immediate_executor<
0805 any_completion_handler<Signatures...>, Candidate>
0806 {
0807 using type = any_completion_executor;
0808
0809 static type get(const any_completion_handler<Signatures...>& handler,
0810 const Candidate& candidate = Candidate()) noexcept
0811 {
0812 any_io_executor any_candidate(std::nothrow, candidate);
0813 return handler.fn_table_
0814 ? handler.fn_table_->immediate_executor(handler.impl_, any_candidate)
0815 : any_candidate;
0816 }
0817 };
0818
0819 }
0820 }
0821
0822 #include <boost/asio/detail/pop_options.hpp>
0823
0824 #endif