306 lines
8.4 KiB
C++
306 lines
8.4 KiB
C++
//
|
|
// cancellation_signal.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_CANCELLATION_SIGNAL_HPP
|
|
#define ASIO_CANCELLATION_SIGNAL_HPP
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
# pragma once
|
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
|
|
#include "asio/detail/config.hpp"
|
|
#include <cassert>
|
|
#include <new>
|
|
#include <utility>
|
|
#include "asio/cancellation_type.hpp"
|
|
#include "asio/detail/cstddef.hpp"
|
|
#include "asio/detail/type_traits.hpp"
|
|
#include "asio/detail/variadic_templates.hpp"
|
|
|
|
#include "asio/detail/push_options.hpp"
|
|
|
|
namespace asio {
|
|
namespace detail {
|
|
|
|
class cancellation_handler_base
|
|
{
|
|
public:
|
|
virtual void call(cancellation_type_t) = 0;
|
|
virtual std::pair<void*, std::size_t> destroy() ASIO_NOEXCEPT = 0;
|
|
|
|
protected:
|
|
~cancellation_handler_base() {}
|
|
};
|
|
|
|
template <typename Handler>
|
|
class cancellation_handler
|
|
: public cancellation_handler_base
|
|
{
|
|
public:
|
|
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
|
template <typename... Args>
|
|
cancellation_handler(std::size_t size, ASIO_MOVE_ARG(Args)... args)
|
|
: handler_(ASIO_MOVE_CAST(Args)(args)...),
|
|
size_(size)
|
|
{
|
|
}
|
|
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
|
cancellation_handler(std::size_t size)
|
|
: handler_(),
|
|
size_(size)
|
|
{
|
|
}
|
|
|
|
#define ASIO_PRIVATE_HANDLER_CTOR_DEF(n) \
|
|
template <ASIO_VARIADIC_TPARAMS(n)> \
|
|
cancellation_handler(std::size_t size, ASIO_VARIADIC_MOVE_PARAMS(n)) \
|
|
: handler_(ASIO_VARIADIC_MOVE_ARGS(n)), \
|
|
size_(size) \
|
|
{ \
|
|
} \
|
|
/**/
|
|
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_HANDLER_CTOR_DEF)
|
|
#undef ASIO_PRIVATE_HANDLER_CTOR_DEF
|
|
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
|
|
|
void call(cancellation_type_t type)
|
|
{
|
|
handler_(type);
|
|
}
|
|
|
|
std::pair<void*, std::size_t> destroy() ASIO_NOEXCEPT
|
|
{
|
|
std::pair<void*, std::size_t> mem(this, size_);
|
|
this->cancellation_handler::~cancellation_handler();
|
|
return mem;
|
|
}
|
|
|
|
Handler& handler() ASIO_NOEXCEPT
|
|
{
|
|
return handler_;
|
|
}
|
|
|
|
private:
|
|
~cancellation_handler()
|
|
{
|
|
}
|
|
|
|
Handler handler_;
|
|
std::size_t size_;
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
class cancellation_slot;
|
|
|
|
/// A cancellation signal with a single slot.
|
|
class cancellation_signal
|
|
{
|
|
public:
|
|
ASIO_CONSTEXPR cancellation_signal()
|
|
: handler_(0)
|
|
{
|
|
}
|
|
|
|
ASIO_DECL ~cancellation_signal();
|
|
|
|
/// Emits the signal and causes invocation of the slot's handler, if any.
|
|
void emit(cancellation_type_t type)
|
|
{
|
|
if (handler_)
|
|
handler_->call(type);
|
|
}
|
|
|
|
/// Returns the single slot associated with the signal.
|
|
/**
|
|
* The signal object must remain valid for as long the slot may be used.
|
|
* Destruction of the signal invalidates the slot.
|
|
*/
|
|
cancellation_slot slot() ASIO_NOEXCEPT;
|
|
|
|
private:
|
|
cancellation_signal(const cancellation_signal&) ASIO_DELETED;
|
|
cancellation_signal& operator=(const cancellation_signal&) ASIO_DELETED;
|
|
|
|
detail::cancellation_handler_base* handler_;
|
|
};
|
|
|
|
/// A slot associated with a cancellation signal.
|
|
class cancellation_slot
|
|
{
|
|
public:
|
|
/// Creates a slot that is not connected to any cancellation signal.
|
|
ASIO_CONSTEXPR cancellation_slot()
|
|
: handler_(0)
|
|
{
|
|
}
|
|
|
|
#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
|
|
|| defined(GENERATING_DOCUMENTATION)
|
|
/// Installs a handler into the slot, constructing the new object directly.
|
|
/**
|
|
* Destroys any existing handler in the slot, then installs the new handler,
|
|
* constructing it with the supplied @c args.
|
|
*
|
|
* The handler is a function object to be called when the signal is emitted.
|
|
* The signature of the handler must be
|
|
* @code void handler(asio::cancellation_type_t); @endcode
|
|
*
|
|
* @param args Arguments to be passed to the @c CancellationHandler object's
|
|
* constructor.
|
|
*
|
|
* @returns A reference to the newly installed handler.
|
|
*
|
|
* @note Handlers installed into the slot via @c emplace are not required to
|
|
* be copy constructible or move constructible.
|
|
*/
|
|
template <typename CancellationHandler, typename... Args>
|
|
CancellationHandler& emplace(ASIO_MOVE_ARG(Args)... args)
|
|
{
|
|
typedef detail::cancellation_handler<CancellationHandler>
|
|
cancellation_handler_type;
|
|
auto_delete_helper del = { prepare_memory(
|
|
sizeof(cancellation_handler_type),
|
|
ASIO_ALIGNOF(CancellationHandler)) };
|
|
cancellation_handler_type* handler_obj =
|
|
new (del.mem.first) cancellation_handler_type(
|
|
del.mem.second, ASIO_MOVE_CAST(Args)(args)...);
|
|
del.mem.first = 0;
|
|
*handler_ = handler_obj;
|
|
return handler_obj->handler();
|
|
}
|
|
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
|
// || defined(GENERATING_DOCUMENTATION)
|
|
template <typename CancellationHandler>
|
|
CancellationHandler& emplace()
|
|
{
|
|
typedef detail::cancellation_handler<CancellationHandler>
|
|
cancellation_handler_type;
|
|
auto_delete_helper del = { prepare_memory(
|
|
sizeof(cancellation_handler_type),
|
|
ASIO_ALIGNOF(CancellationHandler)) };
|
|
cancellation_handler_type* handler_obj =
|
|
new (del.mem.first) cancellation_handler_type(del.mem.second);
|
|
del.mem.first = 0;
|
|
*handler_ = handler_obj;
|
|
return handler_obj->handler();
|
|
}
|
|
|
|
#define ASIO_PRIVATE_HANDLER_EMPLACE_DEF(n) \
|
|
template <typename CancellationHandler, ASIO_VARIADIC_TPARAMS(n)> \
|
|
CancellationHandler& emplace(ASIO_VARIADIC_MOVE_PARAMS(n)) \
|
|
{ \
|
|
typedef detail::cancellation_handler<CancellationHandler> \
|
|
cancellation_handler_type; \
|
|
auto_delete_helper del = { prepare_memory( \
|
|
sizeof(cancellation_handler_type), \
|
|
ASIO_ALIGNOF(CancellationHandler)) }; \
|
|
cancellation_handler_type* handler_obj = \
|
|
new (del.mem.first) cancellation_handler_type( \
|
|
del.mem.second, ASIO_VARIADIC_MOVE_ARGS(n)); \
|
|
del.mem.first = 0; \
|
|
*handler_ = handler_obj; \
|
|
return handler_obj->handler(); \
|
|
} \
|
|
/**/
|
|
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_HANDLER_EMPLACE_DEF)
|
|
#undef ASIO_PRIVATE_HANDLER_EMPLACE_DEF
|
|
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
|
|
|
/// Installs a handler into the slot.
|
|
/**
|
|
* Destroys any existing handler in the slot, then installs the new handler,
|
|
* constructing it as a decay-copy of the supplied handler.
|
|
*
|
|
* The handler is a function object to be called when the signal is emitted.
|
|
* The signature of the handler must be
|
|
* @code void handler(asio::cancellation_type_t); @endcode
|
|
*
|
|
* @param handler The handler to be installed.
|
|
*
|
|
* @returns A reference to the newly installed handler.
|
|
*/
|
|
template <typename CancellationHandler>
|
|
typename decay<CancellationHandler>::type& assign(
|
|
ASIO_MOVE_ARG(CancellationHandler) handler)
|
|
{
|
|
return this->emplace<typename decay<CancellationHandler>::type>(
|
|
ASIO_MOVE_CAST(CancellationHandler)(handler));
|
|
}
|
|
|
|
/// Clears the slot.
|
|
/**
|
|
* Destroys any existing handler in the slot.
|
|
*/
|
|
ASIO_DECL void clear();
|
|
|
|
/// Returns whether the slot is connected to a signal.
|
|
ASIO_CONSTEXPR bool is_connected() const ASIO_NOEXCEPT
|
|
{
|
|
return handler_ != 0;
|
|
}
|
|
|
|
/// Returns whether the slot is connected and has an installed handler.
|
|
ASIO_CONSTEXPR bool has_handler() const ASIO_NOEXCEPT
|
|
{
|
|
return handler_ != 0 && *handler_ != 0;
|
|
}
|
|
|
|
/// Compare two slots for equality.
|
|
friend ASIO_CONSTEXPR bool operator==(const cancellation_slot& lhs,
|
|
const cancellation_slot& rhs) ASIO_NOEXCEPT
|
|
{
|
|
return lhs.handler_ == rhs.handler_;
|
|
}
|
|
|
|
/// Compare two slots for inequality.
|
|
friend ASIO_CONSTEXPR bool operator!=(const cancellation_slot& lhs,
|
|
const cancellation_slot& rhs) ASIO_NOEXCEPT
|
|
{
|
|
return lhs.handler_ != rhs.handler_;
|
|
}
|
|
|
|
private:
|
|
friend class cancellation_signal;
|
|
|
|
ASIO_CONSTEXPR cancellation_slot(int,
|
|
detail::cancellation_handler_base** handler)
|
|
: handler_(handler)
|
|
{
|
|
}
|
|
|
|
ASIO_DECL std::pair<void*, std::size_t> prepare_memory(
|
|
std::size_t size, std::size_t align);
|
|
|
|
struct auto_delete_helper
|
|
{
|
|
std::pair<void*, std::size_t> mem;
|
|
|
|
ASIO_DECL ~auto_delete_helper();
|
|
};
|
|
|
|
detail::cancellation_handler_base** handler_;
|
|
};
|
|
|
|
inline cancellation_slot cancellation_signal::slot() ASIO_NOEXCEPT
|
|
{
|
|
return cancellation_slot(0, &handler_);
|
|
}
|
|
|
|
} // namespace asio
|
|
|
|
#include "asio/detail/pop_options.hpp"
|
|
|
|
#if defined(ASIO_HEADER_ONLY)
|
|
# include "asio/impl/cancellation_signal.ipp"
|
|
#endif // defined(ASIO_HEADER_ONLY)
|
|
|
|
#endif // ASIO_CANCELLATION_SIGNAL_HPP
|