Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:33:38

0001 //
0002 // any_completion_handler.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 } // namespace detail
0453 
0454 template <typename... Signatures>
0455 class any_completion_handler;
0456 
0457 /// An allocator type that forwards memory allocation operations through an
0458 /// instance of @c any_completion_handler.
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   /// The type of objects that may be allocated by the allocator.
0481   typedef T value_type;
0482 
0483   /// Rebinds an allocator to another value type.
0484   template <typename U>
0485   struct rebind
0486   {
0487     /// Specifies the type of the rebound allocator.
0488     typedef any_completion_handler_allocator<U, Signatures...> other;
0489   };
0490 
0491   /// Construct from another @c any_completion_handler_allocator.
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   /// Equality operator.
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   /// Inequality operator.
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   /// Allocate space for @c n objects of the allocator's value type.
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   /// Deallocate space for @c n objects of the allocator's value type.
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 /// A protoco-allocator type that may be rebound to obtain an allocator that
0537 /// forwards memory allocation operations through an instance of
0538 /// @c any_completion_handler.
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   /// @c void as no objects can be allocated through a proto-allocator.
0561   typedef void value_type;
0562 
0563   /// Rebinds an allocator to another value type.
0564   template <typename U>
0565   struct rebind
0566   {
0567     /// Specifies the type of the rebound allocator.
0568     typedef any_completion_handler_allocator<U, Signatures...> other;
0569   };
0570 
0571   /// Construct from another @c any_completion_handler_allocator.
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   /// Equality operator.
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   /// Inequality operator.
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 /// Polymorphic wrapper for completion handlers.
0597 /**
0598  * The @c any_completion_handler class template is a polymorphic wrapper for
0599  * completion handlers that propagates the associated executor, associated
0600  * allocator, and associated cancellation slot through a type-erasing interface.
0601  *
0602  * When using @c any_completion_handler, specify one or more completion
0603  * signatures as template parameters. These will dictate the arguments that may
0604  * be passed to the handler through the polymorphic interface.
0605  *
0606  * Typical uses for @c any_completion_handler include:
0607  *
0608  * @li Separate compilation of asynchronous operation implementations.
0609  *
0610  * @li Enabling interoperability between asynchronous operations and virtual
0611  *     functions.
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 // !defined(GENERATING_DOCUMENTATION)
0630 
0631 public:
0632   /// The associated allocator type.
0633   using allocator_type = any_completion_handler_allocator<void, Signatures...>;
0634 
0635   /// The associated cancellation slot type.
0636   using cancellation_slot_type = cancellation_slot;
0637 
0638   /// Construct an @c any_completion_handler in an empty state, without a target
0639   /// object.
0640   constexpr any_completion_handler()
0641     : fn_table_(nullptr),
0642       impl_(nullptr)
0643   {
0644   }
0645 
0646   /// Construct an @c any_completion_handler in an empty state, without a target
0647   /// object.
0648   constexpr any_completion_handler(nullptr_t)
0649     : fn_table_(nullptr),
0650       impl_(nullptr)
0651   {
0652   }
0653 
0654   /// Construct an @c any_completion_handler to contain the specified target.
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   /// Move-construct an @c any_completion_handler from another.
0669   /**
0670    * After the operation, the moved-from object @c other has no target.
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   /// Move-assign an @c any_completion_handler from another.
0681   /**
0682    * After the operation, the moved-from object @c other has no target.
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   /// Assignment operator that sets the polymorphic wrapper to the empty state.
0693   any_completion_handler& operator=(nullptr_t) noexcept
0694   {
0695     any_completion_handler().swap(*this);
0696     return *this;
0697   }
0698 
0699   /// Destructor.
0700   ~any_completion_handler()
0701   {
0702     if (impl_)
0703       fn_table_->destroy(impl_);
0704   }
0705 
0706   /// Test if the polymorphic wrapper is empty.
0707   constexpr explicit operator bool() const noexcept
0708   {
0709     return impl_ != nullptr;
0710   }
0711 
0712   /// Test if the polymorphic wrapper is non-empty.
0713   constexpr bool operator!() const noexcept
0714   {
0715     return impl_ == nullptr;
0716   }
0717 
0718   /// Swap the content of an @c any_completion_handler with another.
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   /// Get the associated allocator.
0726   allocator_type get_allocator() const noexcept
0727   {
0728     return allocator_type(0, *this);
0729   }
0730 
0731   /// Get the associated cancellation slot.
0732   cancellation_slot_type get_cancellation_slot() const noexcept
0733   {
0734     return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type();
0735   }
0736 
0737   /// Function call operator.
0738   /**
0739    * Invokes target completion handler with the supplied arguments.
0740    *
0741    * This function may only be called once, as the target handler is moved from.
0742    * The polymorphic wrapper is left in an empty state.
0743    *
0744    * Throws @c std::bad_function_call if the polymorphic wrapper is empty.
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   /// Equality operator.
0760   friend constexpr bool operator==(
0761       const any_completion_handler& a, nullptr_t) noexcept
0762   {
0763     return a.impl_ == nullptr;
0764   }
0765 
0766   /// Equality operator.
0767   friend constexpr bool operator==(
0768       nullptr_t, const any_completion_handler& b) noexcept
0769   {
0770     return nullptr == b.impl_;
0771   }
0772 
0773   /// Inequality operator.
0774   friend constexpr bool operator!=(
0775       const any_completion_handler& a, nullptr_t) noexcept
0776   {
0777     return a.impl_ != nullptr;
0778   }
0779 
0780   /// Inequality operator.
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 } // namespace asio
0820 } // namespace boost
0821 
0822 #include <boost/asio/detail/pop_options.hpp>
0823 
0824 #endif // BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP