824 lines
23 KiB
C++
824 lines
23 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/any_io_executor.hpp"
|
|
#include "asio/associated_allocator.hpp"
|
|
#include "asio/associated_cancellation_slot.hpp"
|
|
#include "asio/associated_executor.hpp"
|
|
#include "asio/associated_immediate_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));
|
|
}
|
|
|
|
any_completion_executor immediate_executor(
|
|
const any_io_executor& candidate) const ASIO_NOEXCEPT
|
|
{
|
|
return any_completion_executor(std::nothrow,
|
|
(get_associated_immediate_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_immediate_executor_fn
|
|
{
|
|
public:
|
|
using type = any_completion_executor(*)(
|
|
any_completion_handler_impl_base*, const any_io_executor&);
|
|
|
|
constexpr any_completion_handler_immediate_executor_fn(type fn)
|
|
: immediate_executor_fn_(fn)
|
|
{
|
|
}
|
|
|
|
any_completion_executor immediate_executor(
|
|
any_completion_handler_impl_base* impl,
|
|
const any_io_executor& candidate) const
|
|
{
|
|
return immediate_executor_fn_(impl, candidate);
|
|
}
|
|
|
|
template <typename Handler>
|
|
static any_completion_executor impl(any_completion_handler_impl_base* impl,
|
|
const any_io_executor& candidate)
|
|
{
|
|
return static_cast<any_completion_handler_impl<Handler>*>(
|
|
impl)->immediate_executor(candidate);
|
|
}
|
|
|
|
private:
|
|
type immediate_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_immediate_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_immediate_executor_fn::type immediate_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_immediate_executor_fn(immediate_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_immediate_executor_fn::immediate_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_immediate_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;
|
|
|
|
template <typename, typename>
|
|
friend struct associated_immediate_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));
|
|
}
|
|
};
|
|
|
|
template <typename... Signatures, typename Candidate>
|
|
struct associated_immediate_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_->immediate_executor(handler.impl_,
|
|
any_io_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
|