// // cancellation_signal.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2022 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 #include #include #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 destroy() ASIO_NOEXCEPT = 0; protected: ~cancellation_handler_base() {} }; template class cancellation_handler : public cancellation_handler_base { public: #if defined(ASIO_HAS_VARIADIC_TEMPLATES) template 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 \ 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 destroy() ASIO_NOEXCEPT { std::pair 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 CancellationHandler& emplace(ASIO_MOVE_ARG(Args)... args) { typedef detail::cancellation_handler 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 CancellationHandler& emplace() { typedef detail::cancellation_handler 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 \ CancellationHandler& emplace(ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ typedef detail::cancellation_handler \ 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 decay::type& assign( ASIO_MOVE_ARG(CancellationHandler) handler) { return this->emplace::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 prepare_memory( std::size_t size, std::size_t align); struct auto_delete_helper { std::pair 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