// Copyright (c) OpenMMLab. All rights reserved. // Modified from // https://github.com/brycelelbach/wg21_p2300_std_execution/blob/main/include/execution.hpp #ifndef MMDEPLOY_CSRC_EXPERIMENTAL_EXECUTION_WHEN_ALL_H_ #define MMDEPLOY_CSRC_EXPERIMENTAL_EXECUTION_WHEN_ALL_H_ #include "utility.h" namespace mmdeploy { namespace __when_all { template using __concat_t = decltype(std::tuple_cat(std::declval>()...)); template struct _Operation { struct type; }; template using Operation = typename _Operation::type; template struct _Receiver { struct type; }; template using receiver_t = typename _Receiver::type; template struct _Receiver::type { using Receiver = remove_cvref_t; Operation* op_state_; template friend void tag_invoke(set_value_t, type&& self, As&&... as) noexcept { std::get(self.op_state_->vals_).emplace((As &&) as...); self.op_state_->_Arrive(); } }; template struct _Operation::type { using Receiver = remove_cvref_t; template using _receiver_t = receiver_t; template using _ChildOpState = connect_result_t<_copy_cvref_t, _receiver_t>; using _Indices = std::index_sequence_for; // workaround for a bug in GCC7 that `Is` in a lambda is treated as unexpanded parameter pack template static auto _Connect1(Sender&& sender, Receiver&& receiver) { return __conv{[&]() mutable { return Connect((Sender &&) sender, (Receiver &&) receiver); }}; } template static auto _ConnectChildren(type* self, std::index_sequence, _Senders&&... senders) -> std::tuple<_ChildOpState...> { return {_Connect1((_Senders &&) senders, _receiver_t{self})...}; } using _ChildOpStates = decltype(_ConnectChildren( nullptr, _Indices{}, std::declval<_copy_cvref_t>()...)); using _ChildValueTuple = std::tuple>...>; void _Arrive() noexcept { if (0 == --count_) { _Complete(); } } void _Complete() noexcept { std::apply( [this](auto&... opt_vals) -> void { std::apply( [this](auto&... all_vals) -> void { SetValue((Receiver &&) receiver_, std::move(all_vals)...); }, std::tuple_cat( std::apply([](auto&... vals) { return std::tie(vals...); }, *opt_vals)...)); }, vals_); } template explicit type(Receiver&& receiver, _Senders&&... senders) : child_states_{_ConnectChildren(this, _Indices{}, (_Senders &&) senders...)}, receiver_(std::move(receiver)) {} friend void tag_invoke(start_t, type& self) noexcept { std::apply([](auto&&... child_ops) noexcept -> void { (Start(child_ops), ...); }, self.child_states_); } type(const type&) = delete; type(type&&) = delete; type& operator=(const type&) = delete; type& operator=(type&&) = delete; _ChildOpStates child_states_; Receiver receiver_; std::atomic count_{sizeof...(Senders)}; _ChildValueTuple vals_; }; template struct _Sender { struct type; }; template using Sender = typename _Sender...>::type; template struct _Sender::type { using value_types = __concat_t; template using operation_t = Operation; template = 0> friend auto tag_invoke(connect_t, Self&& self, Receiver&& receiver) -> operation_t<_copy_cvref_t>> { // cvref encoded in receiver // type return std::apply( [&](auto&&... senders) { // MSVC v142 doesn't recognize operation_t here return Operation<_copy_cvref_t>, Senders...>( (Receiver &&) receiver, (decltype(senders)&&)senders...); }, ((Self &&) self).senders_); } std::tuple senders_; }; struct when_all_t { template && ...) && (sizeof...(Senders) > 0) && tag_invocable, int> = 0> auto operator()(Senders&&... senders) const { return tag_invoke(when_all_t{}, (Senders &&) senders...); } template < typename Range, typename ValueType = typename remove_cvref_t::value_type, std::enable_if_t< _is_range_v && _is_sender && tag_invocable, int> = 0> auto operator()(Range&& range) const { return tag_invoke(when_all_t{}, (Range &&) range); } template && ...) && (sizeof...(Senders) > 0) && !tag_invocable, int> = 0> Sender operator()(Senders&&... senders) const { return {{(Senders &&) senders...}}; } }; } // namespace __when_all using __when_all::when_all_t; inline constexpr when_all_t WhenAll{}; } // namespace mmdeploy #endif // MMDEPLOY_CSRC_EXPERIMENTAL_EXECUTION_WHEN_ALL_H_