Commit 2d2aabcd authored by Kirk Shoop's avatar Kirk Shoop Committed by Facebook Github Bot

make transform work with move-only functions

Summary: Fixes bug in transform reported by rhodo

Reviewed By: ericniebler

Differential Revision: D14814574

fbshipit-source-id: fdc3866ad56ced11e858869a24ca95b08295477d
parent 4ee0d411
...@@ -469,6 +469,32 @@ PUSHMI_PP_IGNORE_CXX2A_COMPAT_BEGIN ...@@ -469,6 +469,32 @@ PUSHMI_PP_IGNORE_CXX2A_COMPAT_BEGIN
/**/ /**/
#endif #endif
////////////////////////////////////////////////////////////////////////////////
// PUSHMI_TEMPLATE_DEBUG
// templates declared with this macro can have the concepts compiled out
// by adding -DPUSHMI_DEBUG_CONCEPTS=1 in build.
// This is applied to templates that
// a - have no overloads disambiguated by the concepts checks
// b - obscure concept checks that provide more information about a compile
// error
// Usage:
// PUSHMI_TEMPLATE_DEBUG (class A, class B)
// (requires Concept1<A> && Concept2<B>)
// void foo(A a, B b)
// {}
// or
// PUSHMI_TEMPLATE_DEBUG (class A, class B)
// (requires requires (expr1, expr2, expr3) && Concept1<A> && Concept2<B>)
// void foo(A a, B b)
// {}
#if PUSHMI_DEBUG_CONCEPTS
#define PUSHMI_TEMPLATE_DEBUG(...) \
template<__VA_ARGS__> PUSHMI_PP_EAT
#else
#define PUSHMI_TEMPLATE_DEBUG(...) \
PUSHMI_TEMPLATE(PUSHMI_PP_EXPAND(__VA_ARGS__)) \
/**/
#endif
#if __cpp_concepts #if __cpp_concepts
#define PUSHMI_BROKEN_SUBSUMPTION(...) #define PUSHMI_BROKEN_SUBSUMPTION(...)
......
...@@ -88,6 +88,10 @@ struct overload_fn<Fn> : Fn { ...@@ -88,6 +88,10 @@ struct overload_fn<Fn> : Fn {
constexpr overload_fn() = default; constexpr overload_fn() = default;
constexpr explicit overload_fn(Fn fn) constexpr explicit overload_fn(Fn fn)
: Fn(std::move(fn)) {} : Fn(std::move(fn)) {}
constexpr overload_fn(overload_fn&&) = default;
constexpr overload_fn& operator=(overload_fn&&) = default;
constexpr overload_fn(const overload_fn&) = default;
constexpr overload_fn& operator=(const overload_fn&) = default;
using Fn::operator(); using Fn::operator();
}; };
#if !defined(__GNUC__) || __GNUC__ >= 8 #if !defined(__GNUC__) || __GNUC__ >= 8
...@@ -96,6 +100,10 @@ struct overload_fn<Fn, Fns...> : Fn, overload_fn<Fns...> { ...@@ -96,6 +100,10 @@ struct overload_fn<Fn, Fns...> : Fn, overload_fn<Fns...> {
constexpr overload_fn() = default; constexpr overload_fn() = default;
constexpr overload_fn(Fn fn, Fns... fns) constexpr overload_fn(Fn fn, Fns... fns)
: Fn(std::move(fn)), overload_fn<Fns...>{std::move(fns)...} {} : Fn(std::move(fn)), overload_fn<Fns...>{std::move(fns)...} {}
constexpr overload_fn(overload_fn&&) = default;
constexpr overload_fn& operator=(overload_fn&&) = default;
constexpr overload_fn(const overload_fn&) = default;
constexpr overload_fn& operator=(const overload_fn&) = default;
using Fn::operator(); using Fn::operator();
using overload_fn<Fns...>::operator(); using overload_fn<Fns...>::operator();
}; };
...@@ -110,6 +118,10 @@ public: ...@@ -110,6 +118,10 @@ public:
constexpr overload_fn() = default; constexpr overload_fn() = default;
constexpr overload_fn(Fn fn, Fns... fns) constexpr overload_fn(Fn fn, Fns... fns)
: fns_{std::move(fn), overload_fn<Fns...>{std::move(fns)...}} {} : fns_{std::move(fn), overload_fn<Fns...>{std::move(fns)...}} {}
constexpr overload_fn(overload_fn&&) = default;
constexpr overload_fn& operator=(overload_fn&&) = default;
constexpr overload_fn(const overload_fn&) = default;
constexpr overload_fn& operator=(const overload_fn&) = default;
PUSHMI_TEMPLATE (class... Args) PUSHMI_TEMPLATE (class... Args)
(requires lazy::Invocable<Fn&, Args...> || (requires lazy::Invocable<Fn&, Args...> ||
lazy::Invocable<overload_fn<Fns...>&, Args...>) lazy::Invocable<overload_fn<Fns...>&, Args...>)
......
...@@ -34,7 +34,7 @@ struct for_each_fn { ...@@ -34,7 +34,7 @@ struct for_each_fn {
::folly::pushmi::set_value(up_, requested); ::folly::pushmi::set_value(up_, requested);
} }
}; };
template <class In, class Out> template <class Out>
struct Pull { struct Pull {
Out out_; Out out_;
explicit Pull(Out out) : out_(std::move(out)) {} explicit Pull(Out out) : out_(std::move(out)) {}
...@@ -67,27 +67,39 @@ struct for_each_fn { ...@@ -67,27 +67,39 @@ struct for_each_fn {
void starting(Up) {} void starting(Up) {}
}; };
template <class... AN> template <class... AN>
struct fn { struct adapt_impl {
std::tuple<AN...> args_; std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In) PUSHMI_TEMPLATE(class In)
(requires FlowSender<In>) (requires FlowSender<In> && Constructible<std::tuple<AN...>, const std::tuple<AN...>&>)
In operator()(In in) { void operator()(In&& in) & {
// Strip flow:
using C =
std::conditional_t<SingleSender<In>, single_sender_tag, sender_tag>;
// copy args to allow adapt to be called multiple times
auto out{receiver_from_fn<C>()(args_)};
using Out = decltype(out);
::folly::pushmi::submit(
(In &&) in,
receiver_from_fn<In>()(Pull<Out>{std::move(out)}));
}
PUSHMI_TEMPLATE(class In)
(requires FlowSender<In> && Constructible<std::tuple<AN...>, std::tuple<AN...>&&>)
void operator()(In&& in) && {
// Strip flow: // Strip flow:
using C = using C =
std::conditional_t<SingleSender<In>, single_sender_tag, sender_tag>; std::conditional_t<SingleSender<In>, single_sender_tag, sender_tag>;
auto out{receiver_from_fn<C>()(std::move(args_))}; auto out{receiver_from_fn<C>()(std::move(args_))};
using Out = decltype(out); using Out = decltype(out);
::folly::pushmi::submit( ::folly::pushmi::submit(
in, (In &&) in,
receiver_from_fn<In>()(Pull<In, Out>{std::move(out)})); receiver_from_fn<In>()(Pull<Out>{std::move(out)}));
return in;
} }
}; };
public: public:
template <class... AN> template <class... AN>
auto operator()(AN&&... an) const { auto operator()(AN&&... an) const {
return for_each_fn::fn<AN...>{std::tuple<AN...>{(AN &&) an...}}; return for_each_fn::adapt_impl<AN...>{std::tuple<AN...>{(AN &&) an...}};
} }
}; };
......
...@@ -38,7 +38,7 @@ namespace operators { ...@@ -38,7 +38,7 @@ namespace operators {
PUSHMI_INLINE_VAR constexpr struct from_fn { PUSHMI_INLINE_VAR constexpr struct from_fn {
private: private:
template <class I, class S> template <class I, class S>
struct task struct sender_impl
: sender_tag::with_values<typename std::iterator_traits<I>::value_type> : sender_tag::with_values<typename std::iterator_traits<I>::value_type>
::no_error { ::no_error {
private: private:
...@@ -46,16 +46,16 @@ PUSHMI_INLINE_VAR constexpr struct from_fn { ...@@ -46,16 +46,16 @@ PUSHMI_INLINE_VAR constexpr struct from_fn {
S end_; S end_;
public: public:
using properties = property_set<is_always_blocking<>>; using properties = property_set<is_always_blocking<>>;
task() = default; sender_impl() = default;
task(I begin, S end) : begin_(begin), end_(end) {} sender_impl(I begin, S end) : begin_(begin), end_(end) {}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires ReceiveValue< (requires ReceiveValue<
Out, Out,
typename std::iterator_traits<I>::value_type>) // typename std::iterator_traits<I>::value_type>) //
void submit(Out&& out) const { void submit(Out&& out) {
for (auto c = begin_; c != end_; ++c) { for (auto c = begin_; c != end_; ++c) {
set_value(out, *c); set_value(out, folly::as_const(*c));
} }
set_done(out); set_done(out);
} }
...@@ -67,7 +67,7 @@ PUSHMI_INLINE_VAR constexpr struct from_fn { ...@@ -67,7 +67,7 @@ PUSHMI_INLINE_VAR constexpr struct from_fn {
typename std::iterator_traits<I>::iterator_category, typename std::iterator_traits<I>::iterator_category,
std::forward_iterator_tag>) // std::forward_iterator_tag>) //
auto operator()(I begin, S end) const { auto operator()(I begin, S end) const {
return task<I, S>{begin, end}; return sender_impl<I, S>{begin, end};
} }
PUSHMI_TEMPLATE(class R) PUSHMI_TEMPLATE(class R)
...@@ -199,7 +199,7 @@ PUSHMI_INLINE_VAR constexpr struct flow_from_fn { ...@@ -199,7 +199,7 @@ PUSHMI_INLINE_VAR constexpr struct flow_from_fn {
(requires ReceiveValue< (requires ReceiveValue<
Out&, Out&,
typename std::iterator_traits<I>::value_type>) // typename std::iterator_traits<I>::value_type>) //
void submit(Out out) { void submit(Out out) & {
auto exec = ::folly::pushmi::make_strand(ef_); auto exec = ::folly::pushmi::make_strand(ef_);
using Exec = decltype(exec); using Exec = decltype(exec);
using Producer = flow_from_producer<I, S, Out, Exec>; using Producer = flow_from_producer<I, S, Out, Exec>;
...@@ -209,6 +209,20 @@ PUSHMI_INLINE_VAR constexpr struct flow_from_fn { ...@@ -209,6 +209,20 @@ PUSHMI_INLINE_VAR constexpr struct flow_from_fn {
::folly::pushmi::submit( ::folly::pushmi::submit(
::folly::pushmi::schedule(p->exec), receiver_impl<Producer>{p}); ::folly::pushmi::schedule(p->exec), receiver_impl<Producer>{p});
} }
PUSHMI_TEMPLATE(class Out)
(requires ReceiveValue<
Out&,
typename std::iterator_traits<I>::value_type>) //
void submit(Out out) && {
auto exec = ::folly::pushmi::make_strand(ef_);
using Exec = decltype(exec);
using Producer = flow_from_producer<I, S, Out, Exec>;
auto p = std::make_shared<Producer>(
std::move(begin_), std::move(end_), std::move(out), std::move(exec), false);
::folly::pushmi::submit(
::folly::pushmi::schedule(p->exec), receiver_impl<Producer>{p});
}
}; };
public: public:
......
...@@ -50,8 +50,8 @@ struct submit_fn { ...@@ -50,8 +50,8 @@ struct submit_fn {
struct fn : pipeorigin { struct fn : pipeorigin {
explicit fn(AN&&... an) : args_((AN &&) an...) {} explicit fn(AN&&... an) : args_((AN &&) an...) {}
std::tuple<AN...> args_; std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In)( // PUSHMI_TEMPLATE_DEBUG(class In)
requires submit_detail::AutoSenderTo<In&&, AN...>) // (requires submit_detail::AutoSenderTo<In&&, AN...>) //
void operator()(In&& in) { void operator()(In&& in) {
using maker_t = receiver_from_fn<std::decay_t<In>>; using maker_t = receiver_from_fn<std::decay_t<In>>;
using receiver_t = invoke_result_t<maker_t, std::tuple<AN...>&&>; using receiver_t = invoke_result_t<maker_t, std::tuple<AN...>&&>;
......
...@@ -29,95 +29,20 @@ template <class F, class SenderCategory> ...@@ -29,95 +29,20 @@ template <class F, class SenderCategory>
struct transform_on; struct transform_on;
template <class F> template <class F>
struct transform_on<F, single_sender_tag> { struct value_fn {
F f_; F f_;
transform_on() = default; value_fn() = default;
constexpr explicit transform_on(F f) : f_(std::move(f)) {} constexpr explicit value_fn(F f) : f_(std::move(f)) {}
struct value_fn { template<class Out, class... VN>
F f_; auto operator()(Out& out, VN&&... vn) {
value_fn() = default; using Result = ::folly::pushmi::invoke_result_t<F&, VN...>;
constexpr explicit value_fn(F f) : f_(std::move(f)) {}
template <class Out, class V0, class... VN>
auto operator()(Out& out, V0&& v0, VN&&... vn) {
using Result = ::folly::pushmi::invoke_result_t<F, V0, VN...>;
static_assert(
::folly::pushmi::SemiMovable<Result>,
"none of the functions supplied to transform can convert this value");
static_assert(
::folly::pushmi::ReceiveValue<Out, Result>,
"Result of value transform cannot be delivered to Out");
set_value(out, f_((V0 &&) v0, (VN &&) vn...));
}
};
template <class Out>
auto operator()(Out out) const {
return ::folly::pushmi::make_receiver(std::move(out), value_fn{f_});
}
};
template <class F>
struct transform_on<F, flow_single_sender_tag> {
F f_;
transform_on() = default;
constexpr explicit transform_on(F f) : f_(std::move(f)) {}
template <class Out>
auto operator()(Out out) const {
return make_flow_receiver(std::move(out), on_value(*this));
}
template <class Out, class V0, class... VN>
auto operator()(Out& out, V0&& v0, VN&&... vn) {
using Result = ::folly::pushmi::invoke_result_t<F, V0, VN...>;
static_assert(
::folly::pushmi::SemiMovable<Result>,
"none of the functions supplied to transform can convert this value");
static_assert(
::folly::pushmi::FlowReceiveValue<Out, Result>,
"Result of value transform cannot be delivered to Out");
set_value(out, f_((V0 &&) v0, (VN &&) vn...));
}
};
template <class F>
struct transform_on<F, sender_tag> {
F f_;
transform_on() = default;
constexpr explicit transform_on(F f) : f_(std::move(f)) {}
template <class Out>
auto operator()(Out out) const {
return ::folly::pushmi::make_receiver(std::move(out), on_value(*this));
}
template <class Out, class V0, class... VN>
auto operator()(Out& out, V0&& v0, VN&&... vn) {
using Result = ::folly::pushmi::invoke_result_t<F, V0, VN...>;
static_assert( static_assert(
::folly::pushmi::SemiMovable<Result>, ::folly::pushmi::SemiMovable<Result>,
"none of the functions supplied to transform can convert this value"); "none of the functions supplied to transform can convert this value");
static_assert( static_assert(
::folly::pushmi::ReceiveValue<Out, Result>, ::folly::pushmi::ReceiveValue<Out&, Result>,
"Result of value transform cannot be delivered to Out"); "Result of value transform cannot be delivered to Out");
set_value(out, f_((V0 &&) v0, (VN &&) vn...)); set_value(out, ::folly::pushmi::invoke(f_, (VN &&) vn...));
}
};
template <class F>
struct transform_on<F, flow_sender_tag> {
F f_;
transform_on() = default;
constexpr explicit transform_on(F f) : f_(std::move(f)) {}
template <class Out>
auto operator()(Out out) const {
return make_flow_receiver(std::move(out), on_value(*this));
}
template <class Out, class V0, class... VN>
void operator()(Out& out, V0&& v0, VN&&... vn) {
using Result = ::folly::pushmi::invoke_result_t<F, V0, VN...>;
static_assert(
::folly::pushmi::SemiMovable<Result>,
"none of the functions supplied to transform can convert this value");
static_assert(
::folly::pushmi::FlowReceiveValue<Out, Result>,
"Result of value transform cannot be delivered to Out");
set_value(out, f_((V0 &&) v0, (VN &&) vn...));
} }
}; };
...@@ -127,12 +52,21 @@ struct transform_fn { ...@@ -127,12 +52,21 @@ struct transform_fn {
struct submit_impl { struct submit_impl {
F f_; F f_;
PUSHMI_TEMPLATE(class SIn, class Out) PUSHMI_TEMPLATE(class SIn, class Out)
(requires Receiver<std::decay_t<Out>>) // (requires Receiver<Out> && Constructible<F, const F&>) //
auto operator()(SIn&& in, Out&& out) const { auto operator()(SIn&& in, Out&& out) & {
// copy 'f_' to allow multiple calls to connect to multiple 'in' // copy 'f_' to allow multiple calls to connect to multiple 'in'
using maker_t = receiver_from_fn<std::decay_t<In>>;
::folly::pushmi::submit(
(In &&) in,
maker_t{}((Out &&) out, value_fn<F>{std::move(f_)}));
}
PUSHMI_TEMPLATE(class SIn, class Out)
(requires Receiver<Out> && Constructible<F, F&&>) //
auto operator()(SIn&& in, Out&& out) && {
using maker_t = receiver_from_fn<std::decay_t<In>>;
::folly::pushmi::submit( ::folly::pushmi::submit(
(In &&) in, (In &&) in,
transform_on<F, sender_category_t<In>>{f_}((Out &&) out)); maker_t{}((Out &&) out, value_fn<F>{std::move(f_)}));
} }
}; };
...@@ -141,10 +75,17 @@ struct transform_fn { ...@@ -141,10 +75,17 @@ struct transform_fn {
F f_; F f_;
PUSHMI_TEMPLATE(class In) PUSHMI_TEMPLATE(class In)
(requires Sender<In>) // (requires Sender<In>) //
auto operator()(In&& in) const { auto operator()(In&& in) & {
// copy 'f_' to allow multiple calls to connect to multiple 'in' // copy 'f_' to allow multiple calls to connect to multiple 'in'
return ::folly::pushmi::detail::sender_from( return ::folly::pushmi::detail::sender_from(
(In &&) in, submit_impl<F, In&&>{f_}); (In &&) in, submit_impl<F, In>{f_});
}
PUSHMI_TEMPLATE(class In)
(requires Sender<In>) //
auto
operator()(In&& in) && {
return ::folly::pushmi::detail::sender_from(
(In &&) in, submit_impl<F, In>{std::move(f_)});
} }
}; };
......
...@@ -20,11 +20,11 @@ ...@@ -20,11 +20,11 @@
namespace folly { namespace folly {
namespace pushmi { namespace pushmi {
PUSHMI_TEMPLATE(class In, class Op) PUSHMI_TEMPLATE_DEBUG(class In, class Op)
(requires PUSHMI_EXP(lazy::Invocable<Op&, In>)) // (requires PUSHMI_EXP(lazy::Invocable<Op, In>)) //
decltype(auto) decltype(auto)
operator|(In&& in, Op&& op) { operator|(In&& in, Op&& op) {
return op((In &&) in); return ((Op &&)op)((In &&) in);
} }
PUSHMI_INLINE_VAR constexpr struct pipe_fn { PUSHMI_INLINE_VAR constexpr struct pipe_fn {
......
...@@ -291,9 +291,9 @@ class flow_receiver<Data, DVF, DEF, DDF, DStrtF> { ...@@ -291,9 +291,9 @@ class flow_receiver<Data, DVF, DEF, DDF, DStrtF> {
DDF df = DDF{}, DDF df = DDF{},
DStrtF strtf = DStrtF{}) DStrtF strtf = DStrtF{})
: data_(std::move(d)), : data_(std::move(d)),
nf_(nf), nf_(std::move(nf)),
ef_(ef), ef_(std::move(ef)),
df_(df), df_(std::move(df)),
strtf_(std::move(strtf)) {} strtf_(std::move(strtf)) {}
......
...@@ -273,11 +273,11 @@ class receiver<Data, DVF, DEF, DDF> { ...@@ -273,11 +273,11 @@ class receiver<Data, DVF, DEF, DDF> {
constexpr explicit receiver(Data d) constexpr explicit receiver(Data d)
: receiver(std::move(d), DVF{}, DEF{}, DDF{}) {} : receiver(std::move(d), DVF{}, DEF{}, DDF{}) {}
constexpr receiver(Data d, DDF df) constexpr receiver(Data d, DDF df)
: done_(false), data_(std::move(d)), vf_(), ef_(), df_(df) {} : done_(false), data_(std::move(d)), vf_(), ef_(), df_(std::move(df)) {}
constexpr receiver(Data d, DEF ef, DDF df = DDF{}) constexpr receiver(Data d, DEF ef, DDF df = DDF{})
: done_(false), data_(std::move(d)), vf_(), ef_(ef), df_(df) {} : done_(false), data_(std::move(d)), vf_(), ef_(std::move(ef)), df_(std::move(df)) {}
constexpr receiver(Data d, DVF vf, DEF ef = DEF{}, DDF df = DDF{}) constexpr receiver(Data d, DVF vf, DEF ef = DEF{}, DDF df = DDF{})
: done_(false), data_(std::move(d)), vf_(vf), ef_(ef), df_(df) {} : done_(false), data_(std::move(d)), vf_(std::move(vf)), ef_(std::move(ef)), df_(std::move(df)) {}
Data& data() { Data& data() {
return data_; return data_;
......
...@@ -131,9 +131,16 @@ class flow_sender<SF> { ...@@ -131,9 +131,16 @@ class flow_sender<SF> {
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires FlowReceiver<Out> && Invocable<SF&, Out>) (requires FlowReceiver<Out> && Invocable<SF&, Out>)
void submit(Out out) { void submit(Out out) & {
sf_(std::move(out)); sf_(std::move(out));
} }
PUSHMI_TEMPLATE(class Out)
(requires FlowReceiver<Out> && Invocable<SF&&, Out>)
void submit(Out out) && {
std::move(sf_)(std::move(out));
}
}; };
template <PUSHMI_TYPE_CONSTRAINT(FlowSender) Data, class DSF> template <PUSHMI_TYPE_CONSTRAINT(FlowSender) Data, class DSF>
...@@ -156,16 +163,14 @@ class flow_sender<Data, DSF> { ...@@ -156,16 +163,14 @@ class flow_sender<Data, DSF> {
: data_(std::move(data)), sf_(std::move(sf)) {} : data_(std::move(data)), sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(lazy::FlowReceiver<Out> PUSHMI_AND (requires FlowReceiver<Out> && Invocable<DSF&, Data&, Out>)
lazy::Invocable<DSF&, Data&, Out>))
void submit(Out out) & { void submit(Out out) & {
sf_(data_, std::move(out)); sf_(data_, std::move(out));
} }
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(lazy::FlowReceiver<Out> PUSHMI_AND (requires FlowReceiver<Out> && Invocable<DSF&&, Data&&, Out>)
lazy::Invocable<DSF&, Data&, Out>))
void submit(Out out) && { void submit(Out out) && {
sf_(std::move(data_), std::move(out)); std::move(sf_)(std::move(data_), std::move(out));
} }
}; };
......
...@@ -141,9 +141,15 @@ class flow_single_sender<SF> { ...@@ -141,9 +141,15 @@ class flow_single_sender<SF> {
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out> && Invocable<SF&, Out>) (requires Receiver<Out> && Invocable<SF&, Out>)
void submit(Out out) { void submit(Out out) & {
sf_(std::move(out)); sf_(std::move(out));
} }
PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out> && Invocable<SF&&, Out>)
void submit(Out out) && {
std::move(sf_)(std::move(out));
}
}; };
template < template <
...@@ -171,11 +177,16 @@ class flow_single_sender<Data, DSF> { ...@@ -171,11 +177,16 @@ class flow_single_sender<Data, DSF> {
: data_(std::move(data)), sf_(std::move(sf)) {} : data_(std::move(data)), sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(lazy::Receiver<Out> PUSHMI_AND (requires Receiver<Out> && Invocable<DSF&, Data&, Out>)
lazy::Invocable<DSF&, Data&, Out>)) void submit(Out out) & {
void submit(Out out) {
sf_(data_, std::move(out)); sf_(data_, std::move(out));
} }
PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out> && Invocable<DSF&&, Data&&, Out>)
void submit(Out out) && {
std::move(sf_)(std::move(data_), std::move(out));
}
}; };
template <> template <>
......
...@@ -77,7 +77,7 @@ namespace _submit_adl { ...@@ -77,7 +77,7 @@ namespace _submit_adl {
#endif #endif
struct _impl_ { struct _impl_ {
PUSHMI_TEMPLATE(class S, class R) PUSHMI_TEMPLATE_DEBUG(class S, class R)
(requires Sender<S> && Receiver<R>) (requires Sender<S> && Receiver<R>)
auto operator()(S&& from, R&& to) const auto operator()(S&& from, R&& to) const
{ {
...@@ -101,7 +101,11 @@ namespace _submit_adl { ...@@ -101,7 +101,11 @@ namespace _submit_adl {
return std::false_type{}; return std::false_type{};
)) ))
#else #else
// does not work for free functions
id((S&&) from).submit((R&&) to);
return std::false_type{}; return std::false_type{};
#endif #endif
)) ))
)) ))
...@@ -109,7 +113,8 @@ namespace _submit_adl { ...@@ -109,7 +113,8 @@ namespace _submit_adl {
}; };
public: public:
PUSHMI_TEMPLATE(class S, class R)
PUSHMI_TEMPLATE_DEBUG(class S, class R)
(requires Invocable<_impl_, S, R> && invoke_result_t<_impl_, S, R>::value) (requires Invocable<_impl_, S, R> && invoke_result_t<_impl_, S, R>::value)
constexpr void operator()(S&& from, R&& to) const { constexpr void operator()(S&& from, R&& to) const {
(void) _impl_{}((S&&) from, (R&&) to); (void) _impl_{}((S&&) from, (R&&) to);
......
...@@ -129,9 +129,16 @@ class sender<SF> : public sender_tag { ...@@ -129,9 +129,16 @@ class sender<SF> : public sender_tag {
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP( (requires PUSHMI_EXP(
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<SF&, Out>)) // lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<SF&, Out>)) //
void submit(Out out) { void submit(Out out) & {
sf_(std::move(out)); sf_(std::move(out));
} }
PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<SF&&, Out>)) //
void submit(Out out) && {
std::move(sf_)(std::move(out));
}
}; };
template <PUSHMI_TYPE_CONSTRAINT(Sender) Data, class DSF> template <PUSHMI_TYPE_CONSTRAINT(Sender) Data, class DSF>
...@@ -160,9 +167,9 @@ class sender<Data, DSF> { ...@@ -160,9 +167,9 @@ class sender<Data, DSF> {
} }
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP( (requires PUSHMI_EXP(
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<DSF&, Data&&, Out>)) // lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<DSF&&, Data&&, Out>)) //
void submit(Out out) && { void submit(Out out) && {
sf_(std::move(data_), std::move(out)); std::move(sf_)(std::move(data_), std::move(out));
} }
}; };
......
...@@ -167,11 +167,16 @@ class single_sender<SF> { ...@@ -167,11 +167,16 @@ class single_sender<SF> {
constexpr explicit single_sender(SF sf) : sf_(std::move(sf)) {} constexpr explicit single_sender(SF sf) : sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP( (requires Receiver<Out> && Invocable<SF&, Out>) //
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<SF&, Out>)) // void submit(Out&& out) & {
void submit(Out&& out) {
sf_((Out&&)out); sf_((Out&&)out);
} }
PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out> && Invocable<SF&&, Out>) //
void submit(Out&& out) && {
std::move(sf_)((Out&&)out);
}
}; };
template < template <
...@@ -194,16 +199,14 @@ class single_sender<Data, DSF> { ...@@ -194,16 +199,14 @@ class single_sender<Data, DSF> {
: data_(std::move(data)), sf_(std::move(sf)) {} : data_(std::move(data)), sf_(std::move(sf)) {}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP( (requires Receiver<Out> && Invocable<DSF&, Data&, Out>) //
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<DSF&, Data&, Out>)) //
void submit(Out&& out) & { void submit(Out&& out) & {
sf_(data_, (Out&&)out); sf_(data_, (Out&&)out);
} }
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP( (requires Receiver<Out> && Invocable<DSF&&, Data&&, Out>) //
lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<DSF&, Data&&, Out>)) //
void submit(Out&& out) && { void submit(Out&& out) && {
sf_(std::move(data_), (Out&&)out); std::move(sf_)(std::move(data_), (Out&&)out);
} }
}; };
......
...@@ -160,7 +160,8 @@ using FlowReceiverSignals = ...@@ -160,7 +160,8 @@ using FlowReceiverSignals =
detail::ReceiverSignals_<mi::flow_receiver<>>; detail::ReceiverSignals_<mi::flow_receiver<>>;
TEST(EmptySourceEmptyTriggerTrampoline, TakeUntil) { TEST(EmptySourceEmptyTriggerTrampoline, TakeUntil) {
auto e = op::flow_from(std::array<int, 0>{}, mi::trampolines); std::array<int, 0> ae{};
auto e = op::flow_from(ae, mi::trampolines);
FlowReceiverSignals source{"source"}; FlowReceiverSignals source{"source"};
FlowReceiverSignals trigger{"trigger"}; FlowReceiverSignals trigger{"trigger"};
...@@ -188,7 +189,8 @@ TEST(EmptySourceEmptyTriggerTrampoline, TakeUntil) { ...@@ -188,7 +189,8 @@ TEST(EmptySourceEmptyTriggerTrampoline, TakeUntil) {
TEST(EmptySourceEmptyTrigger, TakeUntil) { TEST(EmptySourceEmptyTrigger, TakeUntil) {
auto nt = mi::new_thread(); auto nt = mi::new_thread();
auto e = op::flow_from(std::array<int, 0>{}, mi::strands(nt)); std::array<int, 0> ae{};
auto e = op::flow_from(ae, mi::strands(nt));
FlowReceiverSignals source{"source"}; FlowReceiverSignals source{"source"};
FlowReceiverSignals trigger{"trigger"}; FlowReceiverSignals trigger{"trigger"};
...@@ -216,8 +218,10 @@ TEST(EmptySourceEmptyTrigger, TakeUntil) { ...@@ -216,8 +218,10 @@ TEST(EmptySourceEmptyTrigger, TakeUntil) {
TEST(EmptySourceValueTrigger, TakeUntil) { TEST(EmptySourceValueTrigger, TakeUntil) {
auto nt = mi::new_thread(); auto nt = mi::new_thread();
auto e = op::flow_from(std::array<int, 0>{}, mi::strands(nt)); std::array<int, 0> ae{};
auto v = op::flow_from(std::array<int, 1>{{42}}, mi::strands(nt)); std::array<int, 1> av{{42}};
auto e = op::flow_from(ae, mi::strands(nt));
auto v = op::flow_from(av, mi::strands(nt));
FlowReceiverSignals source{"source"}; FlowReceiverSignals source{"source"};
FlowReceiverSignals trigger{"trigger"}; FlowReceiverSignals trigger{"trigger"};
...@@ -245,8 +249,10 @@ TEST(EmptySourceValueTrigger, TakeUntil) { ...@@ -245,8 +249,10 @@ TEST(EmptySourceValueTrigger, TakeUntil) {
TEST(ValueSourceEmptyTrigger, TakeUntil) { TEST(ValueSourceEmptyTrigger, TakeUntil) {
auto nt = mi::new_thread(); auto nt = mi::new_thread();
auto e = op::flow_from(std::array<int, 0>{}, mi::strands(nt)); std::array<int, 0> ae{};
auto v = op::flow_from(std::array<int, 1>{{42}}, mi::strands(nt)); std::array<int, 1> av{{42}};
auto e = op::flow_from(ae, mi::strands(nt));
auto v = op::flow_from(av, mi::strands(nt));
FlowReceiverSignals source{"source"}; FlowReceiverSignals source{"source"};
FlowReceiverSignals trigger{"trigger"}; FlowReceiverSignals trigger{"trigger"};
...@@ -273,7 +279,8 @@ TEST(ValueSourceEmptyTrigger, TakeUntil) { ...@@ -273,7 +279,8 @@ TEST(ValueSourceEmptyTrigger, TakeUntil) {
TEST(ValueSourceValueTrigger, TakeUntil) { TEST(ValueSourceValueTrigger, TakeUntil) {
auto nt = mi::new_thread(); auto nt = mi::new_thread();
auto v = op::flow_from(std::array<int, 1>{{42}}, mi::strands(nt)); std::array<int, 1> av{{42}};
auto v = op::flow_from(av, mi::strands(nt));
FlowReceiverSignals source{"source"}; FlowReceiverSignals source{"source"};
FlowReceiverSignals trigger{"trigger"}; FlowReceiverSignals trigger{"trigger"};
......
/*
* 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 <type_traits>
#include <chrono>
using namespace std::literals;
#include <folly/experimental/pushmi/sender/flow_single_sender.h>
#include <folly/experimental/pushmi/o/empty.h>
#include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/o/for_each.h>
#include <folly/experimental/pushmi/o/from.h>
#include <folly/experimental/pushmi/o/just.h>
#include <folly/experimental/pushmi/o/transform.h>
#include <folly/experimental/pushmi/executor/trampoline.h>
using namespace folly::pushmi::aliases;
#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>
using namespace testing;
auto l_x2 = [](int x) {
return x * x;
};
struct mo_x2 {
mo_x2() = default;
mo_x2(mo_x2&&) = default;
mo_x2& operator=(mo_x2&&) = default;
mo_x2(const mo_x2&) = delete;
mo_x2& operator=(const mo_x2&) = delete;
int operator()(int x) const {
return x * x;
}
};
TEST(Lambda, Transform) {
auto v = op::just(42);
v | op::transform(l_x2) |
op::submit();
}
TEST(MoveOnly, Transform) {
auto v = op::just(42);
v | op::transform(mo_x2{}) |
op::submit();
}
TEST(ManyLambda, Transform) {
std::array<int, 1> a{{42}};
auto v = op::from(a);
v | op::transform(l_x2) |
op::submit();
}
TEST(ManyMoveOnly, Transform) {
std::array<int, 1> a{{42}};
auto v = op::from(a);
v | op::transform(mo_x2{}) |
op::submit();
}
TEST(FlowManyLambda, Transform) {
std::array<int, 1> a{{42}};
auto v = op::flow_from(a);
v | op::transform(l_x2) |
op::for_each();
}
TEST(FlowManyMoveOnly, Transform) {
std::array<int, 1> a{{42}};
auto v = op::flow_from(a);
v | op::transform(mo_x2{}) |
op::for_each();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment