#pragma once /* * Copyright 2018-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include namespace pushmi { #if __cpp_lib_apply >= 201603 using std::apply; #else namespace detail { PUSHMI_TEMPLATE(class F, class Tuple, std::size_t... Is) (requires requires(pushmi::invoke( std::declval(), std::get(std::declval())...))) constexpr decltype(auto) apply_impl( F&& f, Tuple&& t, std::index_sequence) { return pushmi::invoke((F &&) f, std::get((Tuple &&) t)...); } template > using tupidxs = std::make_index_sequence::value>; } // namespace detail PUSHMI_TEMPLATE(class F, class Tuple) (requires requires(detail::apply_impl( std::declval(), std::declval(), detail::tupidxs{}))) constexpr decltype(auto) apply(F&& f, Tuple&& t) { return detail::apply_impl((F &&) f, (Tuple &&) t, detail::tupidxs{}); } #endif namespace detail { template struct make_receiver; template <> struct make_receiver> : construct_deduced {}; template <> struct make_receiver> : construct_deduced {}; template <> struct make_receiver, true> : construct_deduced {}; template <> struct make_receiver, true> : construct_deduced {}; template struct receiver_from_impl { using MakeReceiver = make_receiver; template using receiver_type = pushmi::invoke_result_t; PUSHMI_TEMPLATE(class... Ts) (requires Invocable) auto operator()( std::tuple args) const { return pushmi::apply(MakeReceiver(), std::move(args)); } PUSHMI_TEMPLATE( class... Ts, class... Fns, class This = std::enable_if_t) (requires And...>&& Invocable&& Invocable< This, pushmi::invoke_result_t, Fns...>) auto operator()(std::tuple args, Fns... fns) const { return This()(This()(std::move(args)), std::move(fns)...); } PUSHMI_TEMPLATE(class Out, class... Fns) (requires Receiver&& And...>) auto operator()( Out out, Fns... fns) const { return MakeReceiver()(std::move(out), std::move(fns)...); } }; template using receiver_from_fn = receiver_from_impl< property_set_index_t, is_single<>>, property_query_v, is_flow<>>>; template using receiver_type_t = typename receiver_from_fn::template receiver_type; template struct submit_transform_out_1 { FN fn_; PUSHMI_TEMPLATE(class Out) (requires Receiver&& Invocable&& SenderTo>) void operator()(In& in, Out out) const { ::pushmi::submit(in, fn_(std::move(out))); } }; template struct submit_transform_out_2 { FN fn_; PUSHMI_TEMPLATE(class CV, class Out) (requires Receiver&& Invocable&& ConstrainedSenderTo>) void operator()(In& in, CV cv, Out out) const { ::pushmi::submit(in, cv, fn_(std::move(out))); } }; template struct submit_transform_out_3 { SDSF sdsf_; PUSHMI_TEMPLATE(class Out) (requires Receiver&& Invocable) void operator()(In& in, Out out) const { sdsf_(in, std::move(out)); } }; template struct submit_transform_out_4 { TSDSF tsdsf_; PUSHMI_TEMPLATE(class CV, class Out) (requires Receiver&& Invocable) void operator()(In& in, CV cv, Out out) const { tsdsf_(in, cv, std::move(out)); } }; PUSHMI_TEMPLATE(class In, class FN) (requires Sender&& SemiMovable PUSHMI_BROKEN_SUBSUMPTION( &¬ ConstrainedSender)) auto submit_transform_out(FN fn) { return on_submit(submit_transform_out_1{std::move(fn)}); } PUSHMI_TEMPLATE(class In, class FN) (requires ConstrainedSender&& SemiMovable) auto submit_transform_out( FN fn) { return submit_transform_out_2{std::move(fn)}; } PUSHMI_TEMPLATE(class In, class SDSF, class TSDSF) (requires Sender&& SemiMovable&& SemiMovable PUSHMI_BROKEN_SUBSUMPTION( &¬ ConstrainedSender< In>)) auto submit_transform_out(SDSF sdsf, TSDSF) { return submit_transform_out_3{std::move(sdsf)}; } PUSHMI_TEMPLATE(class In, class SDSF, class TSDSF) (requires ConstrainedSender&& SemiMovable&& SemiMovable) auto submit_transform_out(SDSF, TSDSF tsdsf) { return submit_transform_out_4{std::move(tsdsf)}; } template < class Cardinality, bool IsConstrained = false, bool IsTime = false, bool IsFlow = false> struct make_sender; template <> struct make_sender> : construct_deduced {}; template <> struct make_sender> : construct_deduced {}; template <> struct make_sender, false, false, true> : construct_deduced {}; template <> struct make_sender, false, false, true> : construct_deduced {}; template <> struct make_sender, true, true, false> : construct_deduced {}; template <> struct make_sender, true, false, false> : construct_deduced {}; PUSHMI_INLINE_VAR constexpr struct sender_from_fn { PUSHMI_TEMPLATE(class In, class... FN) (requires Sender) auto operator()(In in, FN&&... fn) const { using MakeSender = make_sender< property_set_index_t, is_single<>>, property_query_v, is_constrained<>>, property_query_v, is_time<>>, property_query_v, is_flow<>>>; return MakeSender{}(std::move(in), (FN &&) fn...); } } const sender_from{}; PUSHMI_TEMPLATE( class In, class Out, bool SenderRequires, bool SingleSenderRequires, bool TimeSingleSenderRequires) (requires Sender&& Receiver)constexpr bool sender_requires_from() { PUSHMI_IF_CONSTEXPR_RETURN(((bool)TimeSenderTo)( return TimeSingleSenderRequires; ) else ( PUSHMI_IF_CONSTEXPR_RETURN(((bool)SenderTo)( return SingleSenderRequires; ) else ( PUSHMI_IF_CONSTEXPR_RETURN(((bool) SenderTo)( return SenderRequires; ) else ( )) )) )) } struct set_value_fn { private: template struct impl { std::tuple vn_; PUSHMI_TEMPLATE(class Out) (requires ReceiveValue) void operator()(Out out) { ::pushmi::apply( ::pushmi::set_value, std::tuple_cat(std::tuple{std::move(out)}, std::move(vn_))); } }; public: template auto operator()(VN&&... vn) const { return impl...>{(VN &&) vn...}; } }; struct set_error_fn { private: template struct impl { E e_; PUSHMI_TEMPLATE(class Out) (requires ReceiveError) void operator()(Out out) { ::pushmi::set_error(out, std::move(e_)); } }; public: PUSHMI_TEMPLATE(class E) (requires SemiMovable) auto operator()(E e) const { return impl{std::move(e)}; } }; struct set_done_fn { private: struct impl { PUSHMI_TEMPLATE(class Out) (requires Receiver) void operator()(Out out) { ::pushmi::set_done(out); } }; public: auto operator()() const { return impl{}; } }; struct set_starting_fn { private: template struct impl { Up up_; PUSHMI_TEMPLATE(class Out) (requires Receiver) void operator()(Out out) { ::pushmi::set_starting(out, std::move(up_)); } }; public: PUSHMI_TEMPLATE(class Up) (requires Receiver) auto operator()(Up up) const { return impl{std::move(up)}; } }; struct executor_fn { private: struct impl { PUSHMI_TEMPLATE(class In) (requires Sender) auto operator()(In& in) const { return ::pushmi::executor(in); } }; public: auto operator()() const { return impl{}; } }; struct do_submit_fn { private: template struct impl { Out out_; PUSHMI_TEMPLATE(class In) (requires SenderTo) void operator()(In& in) { ::pushmi::submit(in, std::move(out_)); } }; template struct time_impl { TP tp_; Out out_; PUSHMI_TEMPLATE(class In) (requires TimeSenderTo) void operator()(In& in) { ::pushmi::submit(in, std::move(tp_), std::move(out_)); } }; public: PUSHMI_TEMPLATE(class Out) (requires Receiver) auto operator()(Out out) const { return impl{std::move(out)}; } PUSHMI_TEMPLATE(class TP, class Out) (requires Receiver) auto operator()(TP tp, Out out) const { return time_impl{std::move(tp), std::move(out)}; } }; struct top_fn { private: struct impl { PUSHMI_TEMPLATE(class In) (requires ConstrainedSender) auto operator()(In& in) const { return ::pushmi::top(in); } }; public: auto operator()() const { return impl{}; } }; struct now_fn { private: struct impl { PUSHMI_TEMPLATE(class In) (requires TimeSender) auto operator()(In& in) const { return ::pushmi::now(in); } }; public: auto operator()() const { return impl{}; } }; } // namespace detail namespace extension_operators { PUSHMI_INLINE_VAR constexpr detail::set_done_fn set_done{}; PUSHMI_INLINE_VAR constexpr detail::set_error_fn set_error{}; PUSHMI_INLINE_VAR constexpr detail::set_value_fn set_value{}; PUSHMI_INLINE_VAR constexpr detail::set_starting_fn set_starting{}; PUSHMI_INLINE_VAR constexpr detail::executor_fn executor{}; PUSHMI_INLINE_VAR constexpr detail::do_submit_fn submit{}; PUSHMI_INLINE_VAR constexpr detail::now_fn now{}; PUSHMI_INLINE_VAR constexpr detail::top_fn top{}; } // namespace extension_operators } // namespace pushmi