// // experimental/parallel_group.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_EXPERIMENTAL_PARALLEL_GROUP_HPP #define ASIO_EXPERIMENTAL_PARALLEL_GROUP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/array.hpp" #include "asio/experimental/cancellation_condition.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace experimental { namespace detail { // Helper trait for getting the completion signature from an async operation. struct parallel_op_signature_probe {}; template struct parallel_op_signature_probe_result { typedef T type; }; template struct parallel_op_signature { typedef typename decltype(declval()( declval()))::type type; }; // Helper trait for getting a tuple from a completion signature. template struct parallel_op_signature_as_tuple; template struct parallel_op_signature_as_tuple { typedef std::tuple::type...> type; }; // Helper trait for concatenating completion signatures. template struct parallel_group_signature; template struct parallel_group_signature { typedef asio::detail::array order_type; typedef R0 raw_type(Args0...); typedef R0 type(order_type, Args0...); }; template struct parallel_group_signature { typedef asio::detail::array order_type; typedef R0 raw_type(Args0..., Args1...); typedef R0 type(order_type, Args0..., Args1...); }; template struct parallel_group_signature { typedef asio::detail::array order_type; typedef typename parallel_group_signature::raw_type, SigN...>::raw_type raw_type; typedef typename parallel_group_signature::raw_type, SigN...>::type type; }; template void parallel_group_launch(Condition cancellation_condition, Handler handler, std::tuple& ops, std::index_sequence); } // namespace detail /// A group of asynchronous operations that may be launched in parallel. /** * See the documentation for asio::experimental::make_parallel_group for * a usage example. */ template class parallel_group { public: /// Constructor. explicit parallel_group(Ops... ops) : ops_(std::move(ops)...) { } /// The completion signature for the group of operations. typedef typename detail::parallel_group_signature::type...>::type signature; /// Initiate an asynchronous wait for the group of operations. /** * Launches the group and asynchronously waits for completion. * * @param cancellation_condition A function object, called on completion of * an operation within the group, that is used to determine whether to cancel * the remaining operations. The function object is passed the arguments of * the completed operation's handler. To trigger cancellation of the remaining * operations, it must return a asio::cancellation_type value other * than asio::cancellation_type::none. * * @param token A completion token whose signature is comprised of * a @c std::array indicating the completion order of the * operations, followed by all operations' completion handler arguments. * * The library provides the following @c cancellation_condition types: * * @li asio::experimental::wait_for_all * @li asio::experimental::wait_for_one * @li asio::experimental::wait_for_one_error * @li asio::experimental::wait_for_one_success */ template auto async_wait(CancellationCondition cancellation_condition, CompletionToken&& token) { return asio::async_initiate( initiate_async_wait(), token, std::move(cancellation_condition), std::move(ops_)); } private: struct initiate_async_wait { template void operator()(Handler&& h, Condition&& c, std::tuple&& ops) const { detail::parallel_group_launch(std::move(c), std::move(h), ops, std::make_index_sequence()); } }; std::tuple ops_; }; /// Create a group of operations that may be launched in parallel. /** * For example: * @code asio::experimental::make_parallel_group( * [&](auto token) * { * return in.async_read_some(asio::buffer(data), token); * }, * [&](auto token) * { * return timer.async_wait(token); * } * ).async_wait( * asio::experimental::wait_for_all(), * []( * std::array completion_order, * std::error_code ec1, std::size_t n1, * std::error_code ec2 * ) * { * switch (completion_order[0]) * { * case 0: * { * std::cout << "descriptor finished: " << ec1 << ", " << n1 << "\n"; * } * break; * case 1: * { * std::cout << "timer finished: " << ec2 << "\n"; * } * break; * } * } * ); * @endcode */ template ASIO_NODISCARD inline parallel_group make_parallel_group(Ops... ops) { return parallel_group(std::move(ops)...); } } // namespace experimental } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/experimental/impl/parallel_group.hpp" #endif // ASIO_EXPERIMENTAL_PARALLEL_GROUP_HPP