summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/include/asio/experimental/basic_channel.hpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/include/asio/experimental/basic_channel.hpp')
-rw-r--r--3rdparty/asio/include/asio/experimental/basic_channel.hpp513
1 files changed, 513 insertions, 0 deletions
diff --git a/3rdparty/asio/include/asio/experimental/basic_channel.hpp b/3rdparty/asio/include/asio/experimental/basic_channel.hpp
new file mode 100644
index 00000000000..6ca1438a093
--- /dev/null
+++ b/3rdparty/asio/include/asio/experimental/basic_channel.hpp
@@ -0,0 +1,513 @@
+//
+// experimental/basic_channel.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2024 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_EXPERIMENTAL_BASIC_CHANNEL_HPP
+#define ASIO_EXPERIMENTAL_BASIC_CHANNEL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/non_const_lvalue.hpp"
+#include "asio/detail/null_mutex.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/experimental/detail/channel_send_functions.hpp"
+#include "asio/experimental/detail/channel_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace experimental {
+namespace detail {
+
+} // namespace detail
+
+/// A channel for messages.
+/**
+ * The basic_channel class template is used for sending messages between
+ * different parts of the same application. A <em>message</em> is defined as a
+ * collection of arguments to be passed to a completion handler, and the set of
+ * messages supported by a channel is specified by its @c Traits and
+ * <tt>Signatures...</tt> template parameters. Messages may be sent and received
+ * using asynchronous or non-blocking synchronous operations.
+ *
+ * Unless customising the traits, applications will typically use the @c
+ * experimental::channel alias template. For example:
+ * @code void send_loop(int i, steady_timer& timer,
+ * channel<void(error_code, int)>& ch)
+ * {
+ * if (i < 10)
+ * {
+ * timer.expires_after(chrono::seconds(1));
+ * timer.async_wait(
+ * [i, &timer, &ch](error_code error)
+ * {
+ * if (!error)
+ * {
+ * ch.async_send(error_code(), i,
+ * [i, &timer, &ch](error_code error)
+ * {
+ * if (!error)
+ * {
+ * send_loop(i + 1, timer, ch);
+ * }
+ * });
+ * }
+ * });
+ * }
+ * else
+ * {
+ * ch.close();
+ * }
+ * }
+ *
+ * void receive_loop(channel<void(error_code, int)>& ch)
+ * {
+ * ch.async_receive(
+ * [&ch](error_code error, int i)
+ * {
+ * if (!error)
+ * {
+ * std::cout << "Received " << i << "\n";
+ * receive_loop(ch);
+ * }
+ * });
+ * } @endcode
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * The basic_channel class template is not thread-safe, and would typically be
+ * used for passing messages between application code that runs on the same
+ * thread or in the same strand. Consider using @ref basic_concurrent_channel,
+ * and its alias template @c experimental::concurrent_channel, to pass messages
+ * between code running in different threads.
+ */
+template <typename Executor, typename Traits, typename... Signatures>
+class basic_channel
+#if !defined(GENERATING_DOCUMENTATION)
+ : public detail::channel_send_functions<
+ basic_channel<Executor, Traits, Signatures...>,
+ Executor, Signatures...>
+#endif // !defined(GENERATING_DOCUMENTATION)
+{
+private:
+ class initiate_async_send;
+ class initiate_async_receive;
+ typedef detail::channel_service<asio::detail::null_mutex> service_type;
+ typedef typename service_type::template implementation_type<
+ Traits, Signatures...>::payload_type payload_type;
+
+ template <typename... PayloadSignatures,
+ ASIO_COMPLETION_TOKEN_FOR(PayloadSignatures...) CompletionToken>
+ auto do_async_receive(detail::channel_payload<PayloadSignatures...>*,
+ CompletionToken&& token)
+ -> decltype(
+ async_initiate<CompletionToken, PayloadSignatures...>(
+ declval<initiate_async_receive>(), token))
+ {
+ return async_initiate<CompletionToken, PayloadSignatures...>(
+ initiate_async_receive(this), token);
+ }
+
+public:
+ /// The type of the executor associated with the channel.
+ typedef Executor executor_type;
+
+ /// Rebinds the channel type to another executor.
+ template <typename Executor1>
+ struct rebind_executor
+ {
+ /// The channel type when rebound to the specified executor.
+ typedef basic_channel<Executor1, Traits, Signatures...> other;
+ };
+
+ /// The traits type associated with the channel.
+ typedef typename Traits::template rebind<Signatures...>::other traits_type;
+
+ /// Construct a basic_channel.
+ /**
+ * This constructor creates and channel.
+ *
+ * @param ex The I/O executor that the channel will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the channel.
+ *
+ * @param max_buffer_size The maximum number of messages that may be buffered
+ * in the channel.
+ */
+ basic_channel(const executor_type& ex, std::size_t max_buffer_size = 0)
+ : service_(&asio::use_service<service_type>(
+ basic_channel::get_context(ex))),
+ impl_(),
+ executor_(ex)
+ {
+ service_->construct(impl_, max_buffer_size);
+ }
+
+ /// Construct and open a basic_channel.
+ /**
+ * This constructor creates and opens a channel.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the channel will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the channel.
+ *
+ * @param max_buffer_size The maximum number of messages that may be buffered
+ * in the channel.
+ */
+ template <typename ExecutionContext>
+ basic_channel(ExecutionContext& context, std::size_t max_buffer_size = 0,
+ constraint_t<
+ is_convertible<ExecutionContext&, execution_context&>::value,
+ defaulted_constraint
+ > = defaulted_constraint())
+ : service_(&asio::use_service<service_type>(context)),
+ impl_(),
+ executor_(context.get_executor())
+ {
+ service_->construct(impl_, max_buffer_size);
+ }
+
+ /// Move-construct a basic_channel from another.
+ /**
+ * This constructor moves a channel from one object to another.
+ *
+ * @param other The other basic_channel object from which the move will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_channel(const executor_type&) constructor.
+ */
+ basic_channel(basic_channel&& other)
+ : service_(other.service_),
+ executor_(other.executor_)
+ {
+ service_->move_construct(impl_, other.impl_);
+ }
+
+ /// Move-assign a basic_channel from another.
+ /**
+ * This assignment operator moves a channel from one object to another.
+ * Cancels any outstanding asynchronous operations associated with the target
+ * object.
+ *
+ * @param other The other basic_channel object from which the move will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_channel(const executor_type&)
+ * constructor.
+ */
+ basic_channel& operator=(basic_channel&& other)
+ {
+ if (this != &other)
+ {
+ service_->move_assign(impl_, *other.service_, other.impl_);
+ executor_.~executor_type();
+ new (&executor_) executor_type(other.executor_);
+ service_ = other.service_;
+ }
+ return *this;
+ }
+
+ // All channels have access to each other's implementations.
+ template <typename, typename, typename...>
+ friend class basic_channel;
+
+ /// Move-construct a basic_channel from another.
+ /**
+ * This constructor moves a channel from one object to another.
+ *
+ * @param other The other basic_channel object from which the move will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_channel(const executor_type&)
+ * constructor.
+ */
+ template <typename Executor1>
+ basic_channel(
+ basic_channel<Executor1, Traits, Signatures...>&& other,
+ constraint_t<
+ is_convertible<Executor1, Executor>::value
+ > = 0)
+ : service_(other.service_),
+ executor_(other.executor_)
+ {
+ service_->move_construct(impl_, other.impl_);
+ }
+
+ /// Move-assign a basic_channel from another.
+ /**
+ * This assignment operator moves a channel from one object to another.
+ * Cancels any outstanding asynchronous operations associated with the target
+ * object.
+ *
+ * @param other The other basic_channel object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_channel(const executor_type&)
+ * constructor.
+ */
+ template <typename Executor1>
+ constraint_t<
+ is_convertible<Executor1, Executor>::value,
+ basic_channel&
+ > operator=(basic_channel<Executor1, Traits, Signatures...>&& other)
+ {
+ if (this != &other)
+ {
+ service_->move_assign(impl_, *other.service_, other.impl_);
+ executor_.~executor_type();
+ new (&executor_) executor_type(other.executor_);
+ service_ = other.service_;
+ }
+ return *this;
+ }
+
+ /// Destructor.
+ ~basic_channel()
+ {
+ service_->destroy(impl_);
+ }
+
+ /// Get the executor associated with the object.
+ const executor_type& get_executor() noexcept
+ {
+ return executor_;
+ }
+
+ /// Get the capacity of the channel's buffer.
+ std::size_t capacity() noexcept
+ {
+ return service_->capacity(impl_);
+ }
+
+ /// Determine whether the channel is open.
+ bool is_open() const noexcept
+ {
+ return service_->is_open(impl_);
+ }
+
+ /// Reset the channel to its initial state.
+ void reset()
+ {
+ service_->reset(impl_);
+ }
+
+ /// Close the channel.
+ void close()
+ {
+ service_->close(impl_);
+ }
+
+ /// Cancel all asynchronous operations waiting on the channel.
+ /**
+ * All outstanding send operations will complete with the error
+ * @c asio::experimental::error::channel_cancelled. Outstanding receive
+ * operations complete with the result as determined by the channel traits.
+ */
+ void cancel()
+ {
+ service_->cancel(impl_);
+ }
+
+ /// Determine whether a message can be received without blocking.
+ bool ready() const noexcept
+ {
+ return service_->ready(impl_);
+ }
+
+#if defined(GENERATING_DOCUMENTATION)
+
+ /// Try to send a message without blocking.
+ /**
+ * Fails if the buffer is full and there are no waiting receive operations.
+ *
+ * @returns @c true on success, @c false on failure.
+ */
+ template <typename... Args>
+ bool try_send(Args&&... args);
+
+ /// Try to send a message without blocking, using dispatch semantics to call
+ /// the receive operation's completion handler.
+ /**
+ * Fails if the buffer is full and there are no waiting receive operations.
+ *
+ * The receive operation's completion handler may be called from inside this
+ * function.
+ *
+ * @returns @c true on success, @c false on failure.
+ */
+ template <typename... Args>
+ bool try_send_via_dispatch(Args&&... args);
+
+ /// Try to send a number of messages without blocking.
+ /**
+ * @returns The number of messages that were sent.
+ */
+ template <typename... Args>
+ std::size_t try_send_n(std::size_t count, Args&&... args);
+
+ /// Try to send a number of messages without blocking, using dispatch
+ /// semantics to call the receive operations' completion handlers.
+ /**
+ * The receive operations' completion handlers may be called from inside this
+ * function.
+ *
+ * @returns The number of messages that were sent.
+ */
+ template <typename... Args>
+ std::size_t try_send_n_via_dispatch(std::size_t count, Args&&... args);
+
+ /// Asynchronously send a message.
+ /**
+ * @par Completion Signature
+ * @code void(asio::error_code) @endcode
+ */
+ template <typename... Args,
+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
+ CompletionToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+ auto async_send(Args&&... args,
+ CompletionToken&& token);
+
+#endif // defined(GENERATING_DOCUMENTATION)
+
+ /// Try to receive a message without blocking.
+ /**
+ * Fails if the buffer is full and there are no waiting receive operations.
+ *
+ * @returns @c true on success, @c false on failure.
+ */
+ template <typename Handler>
+ bool try_receive(Handler&& handler)
+ {
+ return service_->try_receive(impl_, static_cast<Handler&&>(handler));
+ }
+
+ /// Asynchronously receive a message.
+ /**
+ * @par Completion Signature
+ * As determined by the <tt>Signatures...</tt> template parameter and the
+ * channel traits.
+ */
+ template <typename CompletionToken
+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
+ auto async_receive(
+ CompletionToken&& token
+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor))
+#if !defined(GENERATING_DOCUMENTATION)
+ -> decltype(
+ this->do_async_receive(static_cast<payload_type*>(0),
+ static_cast<CompletionToken&&>(token)))
+#endif // !defined(GENERATING_DOCUMENTATION)
+ {
+ return this->do_async_receive(static_cast<payload_type*>(0),
+ static_cast<CompletionToken&&>(token));
+ }
+
+private:
+ // Disallow copying and assignment.
+ basic_channel(const basic_channel&) = delete;
+ basic_channel& operator=(const basic_channel&) = delete;
+
+ template <typename, typename, typename...>
+ friend class detail::channel_send_functions;
+
+ // Helper function to get an executor's context.
+ template <typename T>
+ static execution_context& get_context(const T& t,
+ enable_if_t<execution::is_executor<T>::value>* = 0)
+ {
+ return asio::query(t, execution::context);
+ }
+
+ // Helper function to get an executor's context.
+ template <typename T>
+ static execution_context& get_context(const T& t,
+ enable_if_t<!execution::is_executor<T>::value>* = 0)
+ {
+ return t.context();
+ }
+
+ class initiate_async_send
+ {
+ public:
+ typedef Executor executor_type;
+
+ explicit initiate_async_send(basic_channel* self)
+ : self_(self)
+ {
+ }
+
+ const executor_type& get_executor() const noexcept
+ {
+ return self_->get_executor();
+ }
+
+ template <typename SendHandler>
+ void operator()(SendHandler&& handler,
+ payload_type&& payload) const
+ {
+ asio::detail::non_const_lvalue<SendHandler> handler2(handler);
+ self_->service_->async_send(self_->impl_,
+ static_cast<payload_type&&>(payload),
+ handler2.value, self_->get_executor());
+ }
+
+ private:
+ basic_channel* self_;
+ };
+
+ class initiate_async_receive
+ {
+ public:
+ typedef Executor executor_type;
+
+ explicit initiate_async_receive(basic_channel* self)
+ : self_(self)
+ {
+ }
+
+ const executor_type& get_executor() const noexcept
+ {
+ return self_->get_executor();
+ }
+
+ template <typename ReceiveHandler>
+ void operator()(ReceiveHandler&& handler) const
+ {
+ asio::detail::non_const_lvalue<ReceiveHandler> handler2(handler);
+ self_->service_->async_receive(self_->impl_,
+ handler2.value, self_->get_executor());
+ }
+
+ private:
+ basic_channel* self_;
+ };
+
+ // The service associated with the I/O object.
+ service_type* service_;
+
+ // The underlying implementation of the I/O object.
+ typename service_type::template implementation_type<
+ Traits, Signatures...> impl_;
+
+ // The associated executor.
+ Executor executor_;
+};
+
+} // namespace experimental
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_EXPERIMENTAL_BASIC_CHANNEL_HPP