763 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			763 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //
 | ||
|  | // any_completion_handler.hpp
 | ||
|  | // ~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
|  | //
 | ||
|  | // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 | ||
|  | //
 | ||
|  | // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | ||
|  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | ||
|  | //
 | ||
|  | 
 | ||
|  | #ifndef ASIO_ANY_COMPLETION_HANDLER_HPP
 | ||
|  | #define ASIO_ANY_COMPLETION_HANDLER_HPP
 | ||
|  | 
 | ||
|  | #include "asio/detail/config.hpp"
 | ||
|  | 
 | ||
|  | #if (defined(ASIO_HAS_STD_TUPLE) \
 | ||
|  |     && defined(ASIO_HAS_MOVE) \ | ||
|  |     && defined(ASIO_HAS_VARIADIC_TEMPLATES)) \ | ||
|  |   || defined(GENERATING_DOCUMENTATION) | ||
|  | 
 | ||
|  | #include <cstring>
 | ||
|  | #include <functional>
 | ||
|  | #include <memory>
 | ||
|  | #include <utility>
 | ||
|  | #include "asio/any_completion_executor.hpp"
 | ||
|  | #include "asio/associated_allocator.hpp"
 | ||
|  | #include "asio/associated_cancellation_slot.hpp"
 | ||
|  | #include "asio/associated_executor.hpp"
 | ||
|  | #include "asio/cancellation_state.hpp"
 | ||
|  | #include "asio/recycling_allocator.hpp"
 | ||
|  | 
 | ||
|  | #include "asio/detail/push_options.hpp"
 | ||
|  | 
 | ||
|  | namespace asio { | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | class any_completion_handler_impl_base | ||
|  | { | ||
|  | public: | ||
|  |   template <typename S> | ||
|  |   explicit any_completion_handler_impl_base(S&& slot) | ||
|  |     : cancel_state_(ASIO_MOVE_CAST(S)(slot), enable_total_cancellation()) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   cancellation_slot get_cancellation_slot() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return cancel_state_.slot(); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   cancellation_state cancel_state_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Handler> | ||
|  | class any_completion_handler_impl : | ||
|  |   public any_completion_handler_impl_base | ||
|  | { | ||
|  | public: | ||
|  |   template <typename S, typename H> | ||
|  |   any_completion_handler_impl(S&& slot, H&& h) | ||
|  |     : any_completion_handler_impl_base(ASIO_MOVE_CAST(S)(slot)), | ||
|  |       handler_(ASIO_MOVE_CAST(H)(h)) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   struct uninit_deleter | ||
|  |   { | ||
|  |     typename std::allocator_traits< | ||
|  |       associated_allocator_t<Handler, | ||
|  |         asio::recycling_allocator<void>>>::template | ||
|  |           rebind_alloc<any_completion_handler_impl> alloc; | ||
|  | 
 | ||
|  |     void operator()(any_completion_handler_impl* ptr) | ||
|  |     { | ||
|  |       std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1); | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   struct deleter | ||
|  |   { | ||
|  |     typename std::allocator_traits< | ||
|  |       associated_allocator_t<Handler, | ||
|  |         asio::recycling_allocator<void>>>::template | ||
|  |           rebind_alloc<any_completion_handler_impl> alloc; | ||
|  | 
 | ||
|  |     void operator()(any_completion_handler_impl* ptr) | ||
|  |     { | ||
|  |       std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr); | ||
|  |       std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1); | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   template <typename S, typename H> | ||
|  |   static any_completion_handler_impl* create(S&& slot, H&& h) | ||
|  |   { | ||
|  |     uninit_deleter d{ | ||
|  |         (get_associated_allocator)(h, | ||
|  |           asio::recycling_allocator<void>())}; | ||
|  | 
 | ||
|  |     std::unique_ptr<any_completion_handler_impl, uninit_deleter> uninit_ptr( | ||
|  |         std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d); | ||
|  | 
 | ||
|  |     any_completion_handler_impl* ptr = | ||
|  |       new (uninit_ptr.get()) any_completion_handler_impl( | ||
|  |         ASIO_MOVE_CAST(S)(slot), ASIO_MOVE_CAST(H)(h)); | ||
|  | 
 | ||
|  |     uninit_ptr.release(); | ||
|  |     return ptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   void destroy() | ||
|  |   { | ||
|  |     deleter d{ | ||
|  |         (get_associated_allocator)(handler_, | ||
|  |           asio::recycling_allocator<void>())}; | ||
|  | 
 | ||
|  |     d(this); | ||
|  |   } | ||
|  | 
 | ||
|  |   any_completion_executor executor( | ||
|  |       const any_completion_executor& candidate) const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return any_completion_executor(std::nothrow, | ||
|  |         (get_associated_executor)(handler_, candidate)); | ||
|  |   } | ||
|  | 
 | ||
|  |   void* allocate(std::size_t size, std::size_t align) const | ||
|  |   { | ||
|  |     typename std::allocator_traits< | ||
|  |       associated_allocator_t<Handler, | ||
|  |         asio::recycling_allocator<void>>>::template | ||
|  |           rebind_alloc<unsigned char> alloc( | ||
|  |             (get_associated_allocator)(handler_, | ||
|  |               asio::recycling_allocator<void>())); | ||
|  | 
 | ||
|  |     std::size_t space = size + align - 1; | ||
|  |     unsigned char* base = | ||
|  |       std::allocator_traits<decltype(alloc)>::allocate( | ||
|  |         alloc, space + sizeof(std::ptrdiff_t)); | ||
|  | 
 | ||
|  |     void* p = base; | ||
|  |     if (detail::align(align, size, p, space)) | ||
|  |     { | ||
|  |       std::ptrdiff_t off = static_cast<unsigned char*>(p) - base; | ||
|  |       std::memcpy(static_cast<unsigned char*>(p) + size, &off, sizeof(off)); | ||
|  |       return p; | ||
|  |     } | ||
|  | 
 | ||
|  |     std::bad_alloc ex; | ||
|  |     asio::detail::throw_exception(ex); | ||
|  |     return nullptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   void deallocate(void* p, std::size_t size, std::size_t align) const | ||
|  |   { | ||
|  |     if (p) | ||
|  |     { | ||
|  |       typename std::allocator_traits< | ||
|  |         associated_allocator_t<Handler, | ||
|  |           asio::recycling_allocator<void>>>::template | ||
|  |             rebind_alloc<unsigned char> alloc( | ||
|  |               (get_associated_allocator)(handler_, | ||
|  |                 asio::recycling_allocator<void>())); | ||
|  | 
 | ||
|  |       std::ptrdiff_t off; | ||
|  |       std::memcpy(&off, static_cast<unsigned char*>(p) + size, sizeof(off)); | ||
|  |       unsigned char* base = static_cast<unsigned char*>(p) - off; | ||
|  | 
 | ||
|  |       std::allocator_traits<decltype(alloc)>::deallocate( | ||
|  |           alloc, base, size + align -1 + sizeof(std::ptrdiff_t)); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename... Args> | ||
|  |   void call(Args&&... args) | ||
|  |   { | ||
|  |     deleter d{ | ||
|  |         (get_associated_allocator)(handler_, | ||
|  |           asio::recycling_allocator<void>())}; | ||
|  | 
 | ||
|  |     std::unique_ptr<any_completion_handler_impl, deleter> ptr(this, d); | ||
|  |     Handler handler(ASIO_MOVE_CAST(Handler)(handler_)); | ||
|  |     ptr.reset(); | ||
|  | 
 | ||
|  |     ASIO_MOVE_CAST(Handler)(handler)( | ||
|  |         ASIO_MOVE_CAST(Args)(args)...); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   Handler handler_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Signature> | ||
|  | class any_completion_handler_call_fn; | ||
|  | 
 | ||
|  | template <typename R, typename... Args> | ||
|  | class any_completion_handler_call_fn<R(Args...)> | ||
|  | { | ||
|  | public: | ||
|  |   using type = void(*)(any_completion_handler_impl_base*, Args...); | ||
|  | 
 | ||
|  |   constexpr any_completion_handler_call_fn(type fn) | ||
|  |     : call_fn_(fn) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void call(any_completion_handler_impl_base* impl, Args... args) const | ||
|  |   { | ||
|  |     call_fn_(impl, ASIO_MOVE_CAST(Args)(args)...); | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename Handler> | ||
|  |   static void impl(any_completion_handler_impl_base* impl, Args... args) | ||
|  |   { | ||
|  |     static_cast<any_completion_handler_impl<Handler>*>(impl)->call( | ||
|  |         ASIO_MOVE_CAST(Args)(args)...); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   type call_fn_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename... Signatures> | ||
|  | class any_completion_handler_call_fns; | ||
|  | 
 | ||
|  | template <typename Signature> | ||
|  | class any_completion_handler_call_fns<Signature> : | ||
|  |   public any_completion_handler_call_fn<Signature> | ||
|  | { | ||
|  | public: | ||
|  |   using any_completion_handler_call_fn< | ||
|  |     Signature>::any_completion_handler_call_fn; | ||
|  |   using any_completion_handler_call_fn<Signature>::call; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Signature, typename... Signatures> | ||
|  | class any_completion_handler_call_fns<Signature, Signatures...> : | ||
|  |   public any_completion_handler_call_fn<Signature>, | ||
|  |   public any_completion_handler_call_fns<Signatures...> | ||
|  | { | ||
|  | public: | ||
|  |   template <typename CallFn, typename... CallFns> | ||
|  |   constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns) | ||
|  |     : any_completion_handler_call_fn<Signature>(fn), | ||
|  |       any_completion_handler_call_fns<Signatures...>(fns...) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   using any_completion_handler_call_fn<Signature>::call; | ||
|  |   using any_completion_handler_call_fns<Signatures...>::call; | ||
|  | }; | ||
|  | 
 | ||
|  | class any_completion_handler_destroy_fn | ||
|  | { | ||
|  | public: | ||
|  |   using type = void(*)(any_completion_handler_impl_base*); | ||
|  | 
 | ||
|  |   constexpr any_completion_handler_destroy_fn(type fn) | ||
|  |     : destroy_fn_(fn) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void destroy(any_completion_handler_impl_base* impl) const | ||
|  |   { | ||
|  |     destroy_fn_(impl); | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename Handler> | ||
|  |   static void impl(any_completion_handler_impl_base* impl) | ||
|  |   { | ||
|  |     static_cast<any_completion_handler_impl<Handler>*>(impl)->destroy(); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   type destroy_fn_; | ||
|  | }; | ||
|  | 
 | ||
|  | class any_completion_handler_executor_fn | ||
|  | { | ||
|  | public: | ||
|  |   using type = any_completion_executor(*)( | ||
|  |       any_completion_handler_impl_base*, const any_completion_executor&); | ||
|  | 
 | ||
|  |   constexpr any_completion_handler_executor_fn(type fn) | ||
|  |     : executor_fn_(fn) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   any_completion_executor executor(any_completion_handler_impl_base* impl, | ||
|  |       const any_completion_executor& candidate) const | ||
|  |   { | ||
|  |     return executor_fn_(impl, candidate); | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename Handler> | ||
|  |   static any_completion_executor impl(any_completion_handler_impl_base* impl, | ||
|  |       const any_completion_executor& candidate) | ||
|  |   { | ||
|  |     return static_cast<any_completion_handler_impl<Handler>*>(impl)->executor( | ||
|  |         candidate); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   type executor_fn_; | ||
|  | }; | ||
|  | 
 | ||
|  | class any_completion_handler_allocate_fn | ||
|  | { | ||
|  | public: | ||
|  |   using type = void*(*)(any_completion_handler_impl_base*, | ||
|  |       std::size_t, std::size_t); | ||
|  | 
 | ||
|  |   constexpr any_completion_handler_allocate_fn(type fn) | ||
|  |     : allocate_fn_(fn) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void* allocate(any_completion_handler_impl_base* impl, | ||
|  |       std::size_t size, std::size_t align) const | ||
|  |   { | ||
|  |     return allocate_fn_(impl, size, align); | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename Handler> | ||
|  |   static void* impl(any_completion_handler_impl_base* impl, | ||
|  |       std::size_t size, std::size_t align) | ||
|  |   { | ||
|  |     return static_cast<any_completion_handler_impl<Handler>*>(impl)->allocate( | ||
|  |         size, align); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   type allocate_fn_; | ||
|  | }; | ||
|  | 
 | ||
|  | class any_completion_handler_deallocate_fn | ||
|  | { | ||
|  | public: | ||
|  |   using type = void(*)(any_completion_handler_impl_base*, | ||
|  |       void*, std::size_t, std::size_t); | ||
|  | 
 | ||
|  |   constexpr any_completion_handler_deallocate_fn(type fn) | ||
|  |     : deallocate_fn_(fn) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void deallocate(any_completion_handler_impl_base* impl, | ||
|  |       void* p, std::size_t size, std::size_t align) const | ||
|  |   { | ||
|  |     deallocate_fn_(impl, p, size, align); | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename Handler> | ||
|  |   static void impl(any_completion_handler_impl_base* impl, | ||
|  |       void* p, std::size_t size, std::size_t align) | ||
|  |   { | ||
|  |     static_cast<any_completion_handler_impl<Handler>*>(impl)->deallocate( | ||
|  |         p, size, align); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   type deallocate_fn_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename... Signatures> | ||
|  | class any_completion_handler_fn_table | ||
|  |   : private any_completion_handler_destroy_fn, | ||
|  |     private any_completion_handler_executor_fn, | ||
|  |     private any_completion_handler_allocate_fn, | ||
|  |     private any_completion_handler_deallocate_fn, | ||
|  |     private any_completion_handler_call_fns<Signatures...> | ||
|  | { | ||
|  | public: | ||
|  |   template <typename... CallFns> | ||
|  |   constexpr any_completion_handler_fn_table( | ||
|  |       any_completion_handler_destroy_fn::type destroy_fn, | ||
|  |       any_completion_handler_executor_fn::type executor_fn, | ||
|  |       any_completion_handler_allocate_fn::type allocate_fn, | ||
|  |       any_completion_handler_deallocate_fn::type deallocate_fn, | ||
|  |       CallFns... call_fns) | ||
|  |     : any_completion_handler_destroy_fn(destroy_fn), | ||
|  |       any_completion_handler_executor_fn(executor_fn), | ||
|  |       any_completion_handler_allocate_fn(allocate_fn), | ||
|  |       any_completion_handler_deallocate_fn(deallocate_fn), | ||
|  |       any_completion_handler_call_fns<Signatures...>(call_fns...) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   using any_completion_handler_destroy_fn::destroy; | ||
|  |   using any_completion_handler_executor_fn::executor; | ||
|  |   using any_completion_handler_allocate_fn::allocate; | ||
|  |   using any_completion_handler_deallocate_fn::deallocate; | ||
|  |   using any_completion_handler_call_fns<Signatures...>::call; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Handler, typename... Signatures> | ||
|  | struct any_completion_handler_fn_table_instance | ||
|  | { | ||
|  |   static constexpr any_completion_handler_fn_table<Signatures...> | ||
|  |     value = any_completion_handler_fn_table<Signatures...>( | ||
|  |         &any_completion_handler_destroy_fn::impl<Handler>, | ||
|  |         &any_completion_handler_executor_fn::impl<Handler>, | ||
|  |         &any_completion_handler_allocate_fn::impl<Handler>, | ||
|  |         &any_completion_handler_deallocate_fn::impl<Handler>, | ||
|  |         &any_completion_handler_call_fn<Signatures>::template impl<Handler>...); | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Handler, typename... Signatures> | ||
|  | constexpr any_completion_handler_fn_table<Signatures...> | ||
|  | any_completion_handler_fn_table_instance<Handler, Signatures...>::value; | ||
|  | 
 | ||
|  | } // namespace detail
 | ||
|  | 
 | ||
|  | template <typename... Signatures> | ||
|  | class any_completion_handler; | ||
|  | 
 | ||
|  | /// An allocator type that forwards memory allocation operations through an
 | ||
|  | /// instance of @c any_completion_handler.
 | ||
|  | template <typename T, typename... Signatures> | ||
|  | class any_completion_handler_allocator | ||
|  | { | ||
|  | private: | ||
|  |   template <typename...> | ||
|  |   friend class any_completion_handler; | ||
|  | 
 | ||
|  |   template <typename, typename...> | ||
|  |   friend class any_completion_handler_allocator; | ||
|  | 
 | ||
|  |   const detail::any_completion_handler_fn_table<Signatures...>* fn_table_; | ||
|  |   detail::any_completion_handler_impl_base* impl_; | ||
|  | 
 | ||
|  |   constexpr any_completion_handler_allocator(int, | ||
|  |       const any_completion_handler<Signatures...>& h) ASIO_NOEXCEPT | ||
|  |     : fn_table_(h.fn_table_), | ||
|  |       impl_(h.impl_) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  | public: | ||
|  |   /// The type of objects that may be allocated by the allocator.
 | ||
|  |   typedef T value_type; | ||
|  | 
 | ||
|  |   /// Rebinds an allocator to another value type.
 | ||
|  |   template <typename U> | ||
|  |   struct rebind | ||
|  |   { | ||
|  |     /// Specifies the type of the rebound allocator.
 | ||
|  |     typedef any_completion_handler_allocator<U, Signatures...> other; | ||
|  |   }; | ||
|  | 
 | ||
|  |   /// Construct from another @c any_completion_handler_allocator.
 | ||
|  |   template <typename U> | ||
|  |   constexpr any_completion_handler_allocator( | ||
|  |       const any_completion_handler_allocator<U, Signatures...>& a) | ||
|  |     ASIO_NOEXCEPT | ||
|  |     : fn_table_(a.fn_table_), | ||
|  |       impl_(a.impl_) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Equality operator.
 | ||
|  |   constexpr bool operator==( | ||
|  |       const any_completion_handler_allocator& other) const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return fn_table_ == other.fn_table_ && impl_ == other.impl_; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Inequality operator.
 | ||
|  |   constexpr bool operator!=( | ||
|  |       const any_completion_handler_allocator& other) const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return fn_table_ != other.fn_table_ || impl_ != other.impl_; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Allocate space for @c n objects of the allocator's value type.
 | ||
|  |   T* allocate(std::size_t n) const | ||
|  |   { | ||
|  |     return static_cast<T*>( | ||
|  |         fn_table_->allocate( | ||
|  |           impl_, sizeof(T) * n, alignof(T))); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Deallocate space for @c n objects of the allocator's value type.
 | ||
|  |   void deallocate(T* p, std::size_t n) const | ||
|  |   { | ||
|  |     fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T)); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | /// A protoco-allocator type that may be rebound to obtain an allocator that
 | ||
|  | /// forwards memory allocation operations through an instance of
 | ||
|  | /// @c any_completion_handler.
 | ||
|  | template <typename... Signatures> | ||
|  | class any_completion_handler_allocator<void, Signatures...> | ||
|  | { | ||
|  | private: | ||
|  |   template <typename...> | ||
|  |   friend class any_completion_handler; | ||
|  | 
 | ||
|  |   template <typename, typename...> | ||
|  |   friend class any_completion_handler_allocator; | ||
|  | 
 | ||
|  |   const detail::any_completion_handler_fn_table<Signatures...>* fn_table_; | ||
|  |   detail::any_completion_handler_impl_base* impl_; | ||
|  | 
 | ||
|  |   constexpr any_completion_handler_allocator(int, | ||
|  |       const any_completion_handler<Signatures...>& h) ASIO_NOEXCEPT | ||
|  |     : fn_table_(h.fn_table_), | ||
|  |       impl_(h.impl_) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  | public: | ||
|  |   /// @c void as no objects can be allocated through a proto-allocator.
 | ||
|  |   typedef void value_type; | ||
|  | 
 | ||
|  |   /// Rebinds an allocator to another value type.
 | ||
|  |   template <typename U> | ||
|  |   struct rebind | ||
|  |   { | ||
|  |     /// Specifies the type of the rebound allocator.
 | ||
|  |     typedef any_completion_handler_allocator<U, Signatures...> other; | ||
|  |   }; | ||
|  | 
 | ||
|  |   /// Construct from another @c any_completion_handler_allocator.
 | ||
|  |   template <typename U> | ||
|  |   constexpr any_completion_handler_allocator( | ||
|  |       const any_completion_handler_allocator<U, Signatures...>& a) | ||
|  |     ASIO_NOEXCEPT | ||
|  |     : fn_table_(a.fn_table_), | ||
|  |       impl_(a.impl_) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Equality operator.
 | ||
|  |   constexpr bool operator==( | ||
|  |       const any_completion_handler_allocator& other) const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return fn_table_ == other.fn_table_ && impl_ == other.impl_; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Inequality operator.
 | ||
|  |   constexpr bool operator!=( | ||
|  |       const any_completion_handler_allocator& other) const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return fn_table_ != other.fn_table_ || impl_ != other.impl_; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | /// Polymorphic wrapper for completion handlers.
 | ||
|  | /**
 | ||
|  |  * The @c any_completion_handler class template is a polymorphic wrapper for | ||
|  |  * completion handlers that propagates the associated executor, associated | ||
|  |  * allocator, and associated cancellation slot through a type-erasing interface. | ||
|  |  * | ||
|  |  * When using @c any_completion_handler, specify one or more completion | ||
|  |  * signatures as template parameters. These will dictate the arguments that may | ||
|  |  * be passed to the handler through the polymorphic interface. | ||
|  |  * | ||
|  |  * Typical uses for @c any_completion_handler include: | ||
|  |  * | ||
|  |  * @li Separate compilation of asynchronous operation implementations. | ||
|  |  * | ||
|  |  * @li Enabling interoperability between asynchronous operations and virtual | ||
|  |  *     functions. | ||
|  |  */ | ||
|  | template <typename... Signatures> | ||
|  | class any_completion_handler | ||
|  | { | ||
|  | #if !defined(GENERATING_DOCUMENTATION)
 | ||
|  | private: | ||
|  |   template <typename, typename...> | ||
|  |   friend class any_completion_handler_allocator; | ||
|  | 
 | ||
|  |   template <typename, typename> | ||
|  |   friend struct associated_executor; | ||
|  | 
 | ||
|  |   const detail::any_completion_handler_fn_table<Signatures...>* fn_table_; | ||
|  |   detail::any_completion_handler_impl_base* impl_; | ||
|  | #endif // !defined(GENERATING_DOCUMENTATION)
 | ||
|  | 
 | ||
|  | public: | ||
|  |   /// The associated allocator type.
 | ||
|  |   using allocator_type = any_completion_handler_allocator<void, Signatures...>; | ||
|  | 
 | ||
|  |   /// The associated cancellation slot type.
 | ||
|  |   using cancellation_slot_type = cancellation_slot; | ||
|  | 
 | ||
|  |   /// Construct an @c any_completion_handler in an empty state, without a target
 | ||
|  |   /// object.
 | ||
|  |   constexpr any_completion_handler() | ||
|  |     : fn_table_(nullptr), | ||
|  |       impl_(nullptr) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Construct an @c any_completion_handler in an empty state, without a target
 | ||
|  |   /// object.
 | ||
|  |   constexpr any_completion_handler(nullptr_t) | ||
|  |     : fn_table_(nullptr), | ||
|  |       impl_(nullptr) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Construct an @c any_completion_handler to contain the specified target.
 | ||
|  |   template <typename H, typename Handler = typename decay<H>::type> | ||
|  |   any_completion_handler(H&& h, | ||
|  |       typename constraint< | ||
|  |         !is_same<typename decay<H>::type, any_completion_handler>::value | ||
|  |       >::type = 0) | ||
|  |     : fn_table_( | ||
|  |         &detail::any_completion_handler_fn_table_instance< | ||
|  |           Handler, Signatures...>::value), | ||
|  |       impl_(detail::any_completion_handler_impl<Handler>::create( | ||
|  |             (get_associated_cancellation_slot)(h), ASIO_MOVE_CAST(H)(h))) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Move-construct an @c any_completion_handler from another.
 | ||
|  |   /**
 | ||
|  |    * After the operation, the moved-from object @c other has no target. | ||
|  |    */ | ||
|  |   any_completion_handler(any_completion_handler&& other) ASIO_NOEXCEPT | ||
|  |     : fn_table_(other.fn_table_), | ||
|  |       impl_(other.impl_) | ||
|  |   { | ||
|  |     other.fn_table_ = nullptr; | ||
|  |     other.impl_ = nullptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Move-assign an @c any_completion_handler from another.
 | ||
|  |   /**
 | ||
|  |    * After the operation, the moved-from object @c other has no target. | ||
|  |    */ | ||
|  |   any_completion_handler& operator=( | ||
|  |       any_completion_handler&& other) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     any_completion_handler( | ||
|  |         ASIO_MOVE_CAST(any_completion_handler)(other)).swap(*this); | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Assignment operator that sets the polymorphic wrapper to the empty state.
 | ||
|  |   any_completion_handler& operator=(nullptr_t) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     any_completion_handler().swap(*this); | ||
|  |     return *this; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Destructor.
 | ||
|  |   ~any_completion_handler() | ||
|  |   { | ||
|  |     if (impl_) | ||
|  |       fn_table_->destroy(impl_); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Test if the polymorphic wrapper is empty.
 | ||
|  |   constexpr explicit operator bool() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return impl_ != nullptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Test if the polymorphic wrapper is non-empty.
 | ||
|  |   constexpr bool operator!() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return impl_ == nullptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Swap the content of an @c any_completion_handler with another.
 | ||
|  |   void swap(any_completion_handler& other) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     std::swap(fn_table_, other.fn_table_); | ||
|  |     std::swap(impl_, other.impl_); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Get the associated allocator.
 | ||
|  |   allocator_type get_allocator() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return allocator_type(0, *this); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Get the associated cancellation slot.
 | ||
|  |   cancellation_slot_type get_cancellation_slot() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return impl_->get_cancellation_slot(); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Function call operator.
 | ||
|  |   /**
 | ||
|  |    * Invokes target completion handler with the supplied arguments. | ||
|  |    * | ||
|  |    * This function may only be called once, as the target handler is moved from. | ||
|  |    * The polymorphic wrapper is left in an empty state. | ||
|  |    * | ||
|  |    * Throws @c std::bad_function_call if the polymorphic wrapper is empty. | ||
|  |    */ | ||
|  |   template <typename... Args> | ||
|  |   auto operator()(Args&&... args) | ||
|  |     -> decltype(fn_table_->call(impl_, ASIO_MOVE_CAST(Args)(args)...)) | ||
|  |   { | ||
|  |     if (detail::any_completion_handler_impl_base* impl = impl_) | ||
|  |     { | ||
|  |       impl_ = nullptr; | ||
|  |       return fn_table_->call(impl, ASIO_MOVE_CAST(Args)(args)...); | ||
|  |     } | ||
|  |     std::bad_function_call ex; | ||
|  |     asio::detail::throw_exception(ex); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Equality operator.
 | ||
|  |   friend constexpr bool operator==( | ||
|  |       const any_completion_handler& a, nullptr_t) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return a.impl_ == nullptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Equality operator.
 | ||
|  |   friend constexpr bool operator==( | ||
|  |       nullptr_t, const any_completion_handler& b) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return nullptr == b.impl_; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Inequality operator.
 | ||
|  |   friend constexpr bool operator!=( | ||
|  |       const any_completion_handler& a, nullptr_t) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return a.impl_ != nullptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Inequality operator.
 | ||
|  |   friend constexpr bool operator!=( | ||
|  |       nullptr_t, const any_completion_handler& b) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return nullptr != b.impl_; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename... Signatures, typename Candidate> | ||
|  | struct associated_executor<any_completion_handler<Signatures...>, Candidate> | ||
|  | { | ||
|  |   using type = any_completion_executor; | ||
|  | 
 | ||
|  |   static type get(const any_completion_handler<Signatures...>& handler, | ||
|  |       const Candidate& candidate = Candidate()) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return handler.fn_table_->executor(handler.impl_, | ||
|  |         any_completion_executor(std::nothrow, candidate)); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | } // namespace asio
 | ||
|  | 
 | ||
|  | #include "asio/detail/pop_options.hpp"
 | ||
|  | 
 | ||
|  | #endif // (defined(ASIO_HAS_STD_TUPLE)
 | ||
|  |        //     && defined(ASIO_HAS_MOVE)
 | ||
|  |        //     && defined(ASIO_HAS_VARIADIC_TEMPLATES))
 | ||
|  |        //   || defined(GENERATING_DOCUMENTATION)
 | ||
|  | 
 | ||
|  | #endif // ASIO_ANY_COMPLETION_HANDLER_HPP
 |