Commit 432d4332 authored by Eric Niebler's avatar Eric Niebler Committed by Facebook Github Bot

replace receiver properties with receiver_traits

Summary: Types opt in to receiver-ness with pushmi::receiver_traits, analogous to sender_traits (and std::iterator_traits). Alternatively, they can simply define a nested ::receiver_concept typedef that is an alias for one of "sink" or "flow".

Reviewed By: kirkshoop

Differential Revision: D14668335

fbshipit-source-id: 230abfcffef0cd231196b5f6a7ed05e1ac86ef0c
parent 1c1fbc3c
......@@ -47,7 +47,7 @@ template <class R>
struct countdown {
explicit countdown(std::atomic<int>& c) : counter(&c) {}
using properties = mi::properties_t<decltype(R{}())>;
using receiver_category = mi::receiver_category_t<folly::invoke_result_t<R>>;
std::atomic<int>* counter;
......
......@@ -27,82 +27,66 @@
namespace folly {
namespace pushmi {
// traits & tags
struct sender_tag;
struct single_sender_tag;
struct flow_sender_tag;
struct flow_single_sender_tag;
// add concepts to support receivers
//
/// \cond
namespace detail {
template <bool>
struct Enable_ {};
template <>
struct Enable_<true> {
template <class T>
using _type = T;
template <class R, class = void>
struct basic_receiver_traits {
};
#if defined(__cpp_fold_expressions) && __cpp_fold_expressions > 0
// An alias for the type in the pack if the pack has exactly one type in it.
// Otherwise, this SFINAE's away. T cannot be an array type of an abstract type.
template<class... Ts>
using identity_t = typename Enable_<sizeof...(Ts) == 1u>::
template _type<decltype((((Ts(*)())0)(),...))>;
#else
template <class...>
struct Front_ {};
template <class T, class... Us>
struct Front_<T, Us...> {
using type = T;
template <class R>
struct basic_receiver_traits<R, void_t<typename R::receiver_category>> {
using receiver_category = typename R::receiver_category;
};
// Instantiation proceeds from left to right. The use of Enable_ here avoids
// needless instantiations of Front_.
template<class...Ts>
using identity_t = typename Enable_<sizeof...(Ts) == 1u>::
template _type<Front_<Ts...>>::type;
#endif
} // namespace detail
/// \endcond
// is_flow trait
template <class PS>
struct is_flow<PS> : property_query<PS, is_flow<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_flow_v = is_flow<PS>::value;
// is_receiver trait
template <class PS>
struct is_receiver<PS> : property_query<PS, is_receiver<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_receiver_v = is_receiver<PS>::value;
// add concepts to support receivers
//
template<typename R, typename>
struct receiver_traits
: std::conditional_t<
std::is_same<std::decay_t<R>, R>::value,
detail::basic_receiver_traits<R>,
receiver_traits<std::decay_t<R>>> {
using _not_specialized = void;
};
PUSHMI_CONCEPT_DEF(
template(class R) //
(concept Receiver)(R), //
requires(R& r) //
(set_done(r)) &&
SemiMovable<std::decay_t<R>> &&
is_receiver_v<R>);
template(class R) //
(concept Receiver)(R), //
requires(R& r)( //
set_done(r) //
) && //
SemiMovable<std::decay_t<R>> &&
True<typename receiver_traits<R>::receiver_category> &&
DerivedFrom<typename receiver_traits<R>::receiver_category, receiver_tag>
);
template <class R>
PUSHMI_PP_CONSTRAINED_USING(
Receiver<R>,
receiver_category_t =,
typename receiver_traits<R>::receiver_category
);
PUSHMI_CONCEPT_DEF(
template(class R, class... VN) //
(concept ReceiveValue)(R, VN...), //
requires(R& r) //
(set_value(r, std::declval<VN&&>()...)) &&
Receiver<R>&& And<MoveConstructible<VN>...>);
template(class R, class... VN) //
(concept ReceiveValue)(R, VN...), //
requires(R& r)( //
set_value(r, std::declval<VN&&>()...) //
) && //
Receiver<R> && //
And<MoveConstructible<VN>...>
);
PUSHMI_CONCEPT_DEF(
template(class R, class E) //
(concept ReceiveError)(R, E), //
template(class R, class E) //
(concept ReceiveError)(R, E), //
requires(R& r, E&& e)( //
set_error(r, (E &&) e)) &&
Receiver<R> && MoveConstructible<E>
set_error(r, (E &&) e) //
) && //
Receiver<R> && //
MoveConstructible<E>
);
// add concepts to support senders
......@@ -127,6 +111,7 @@ namespace detail {
True<test_value_types<S::template value_types>> &&
True<test_error_type<S::template error_type>>
);
template<class, class = void>
struct basic_sender_traits {
};
......@@ -148,7 +133,7 @@ namespace detail {
};
} // namespace detail
template<typename S>
template<typename S, typename>
struct sender_traits
: std::conditional_t<
std::is_same<std::decay_t<S>, S>::value,
......@@ -421,36 +406,41 @@ PUSHMI_CONCEPT_DEF(
template(class R) //
(concept FlowReceiver)(R), //
Receiver<R>&&
is_flow_v<R>);
DerivedFrom<receiver_category_t<R>, flow_receiver_tag>);
PUSHMI_CONCEPT_DEF(
template(class R, class... VN) //
(concept FlowReceiveValue)(R, VN...), //
is_flow_v<R>&& ReceiveValue<R, VN...>);
FlowReceiver<R>&& ReceiveValue<R, VN...>);
PUSHMI_CONCEPT_DEF(
template(class R, class E = std::exception_ptr) //
(concept FlowReceiveError)(R, E), //
is_flow_v<R>&& ReceiveError<R, E>);
FlowReceiver<R>&& ReceiveError<R, E>);
PUSHMI_CONCEPT_DEF(
template(class R, class Up) //
(concept FlowUpTo)(R, Up), //
requires(R& r, Up&& up)( //
set_starting(r, (Up &&) up)) &&
is_flow_v<R>);
set_starting(r, (Up &&) up) //
) &&
FlowReceiver<R>
);
PUSHMI_CONCEPT_DEF(
template(class S) //
(concept FlowSender)(S), //
Sender<S>&&
DerivedFrom<sender_category_t<S>, flow_sender_tag>);
DerivedFrom<sender_category_t<S>, flow_sender_tag>
);
PUSHMI_CONCEPT_DEF(
template(class S, class R) //
(concept FlowSenderTo)(S, R), //
FlowSender<S>&& SenderTo<S, R>&&
FlowReceiver<R>);
FlowSender<S> && //
SenderTo<S, R>&& //
FlowReceiver<R>
);
} // namespace pushmi
} // namespace folly
......@@ -31,8 +31,7 @@ class pool_executor {
Executor::KeepAlive<CPUThreadPoolExecutor> exec_ {};
public:
using properties =
property_set<is_concurrent_sequence<>>;
using properties = property_set<is_concurrent_sequence<>>;
pool_executor() = default;
explicit pool_executor(pool &e);
......
......@@ -104,8 +104,6 @@ class any_executor {
std::enable_if_t<!std::is_same<U, any_executor>::value, U>;
public:
using properties = property_set<>;
any_executor() = default;
any_executor(const any_executor& that) noexcept : any_executor() {
that.vptr_->op_(that.data_, &data_);
......@@ -148,8 +146,6 @@ class executor<SF> {
SF sf_;
public:
using properties = property_set<>;
constexpr executor() = default;
constexpr explicit executor(SF sf) : sf_(std::move(sf)) {}
......@@ -177,7 +173,7 @@ class executor<Data, DSF> {
PUSHMI_TEMPLATE(class DSF_ = DSF)
(requires Invocable<DSF_&, Data&>) //
auto schedule() {
auto schedule() {
return sf_(data_);
}
};
......@@ -196,20 +192,17 @@ PUSHMI_INLINE_VAR constexpr struct make_executor_fn {
}
PUSHMI_TEMPLATE(class SF)
(requires not Executor<SF>) //
auto
operator()(SF sf) const {
auto operator()(SF sf) const {
return executor<SF>{std::move(sf)};
}
PUSHMI_TEMPLATE(class Data)
(requires True<>&& Executor<Data>) //
auto
operator()(Data d) const {
auto operator()(Data d) const {
return executor<Data, passDSF>{std::move(d)};
}
PUSHMI_TEMPLATE(class Data, class DSF)
(requires Executor<Data>) //
auto
operator()(Data d, DSF sf) const {
auto operator()(Data d, DSF sf) const {
return executor<Data, DSF>{std::move(d), std::move(sf)};
}
} const make_executor{};
......@@ -256,8 +249,6 @@ struct any_executor_ref {
using wrapped_t = detail::not_any_executor_ref_t<T>;
public:
using properties = property_set<>;
any_executor_ref() = delete;
any_executor_ref(const any_executor_ref&) = default;
......@@ -289,7 +280,7 @@ auto make_any_executor_ref() {
PUSHMI_TEMPLATE(class E = std::exception_ptr, class Wrapped)
(requires Executor<detail::not_any_executor_ref_t<Wrapped>>) //
auto make_any_executor_ref(Wrapped& w) {
auto make_any_executor_ref(Wrapped& w) {
return any_executor_ref<E>{w};
}
......@@ -416,8 +407,6 @@ class any_constrained_executor {
std::enable_if_t<!std::is_same<U, any_constrained_executor>::value, U>;
public:
using properties = property_set<>;
any_constrained_executor() = default;
any_constrained_executor(const any_constrained_executor& that) noexcept
: any_constrained_executor() {
......@@ -469,8 +458,6 @@ class constrained_executor<SF, ZF> {
ZF zf_;
public:
using properties = property_set<>;
constexpr constrained_executor() = default;
constexpr explicit constrained_executor(SF sf) : sf_(std::move(sf)) {}
constexpr constrained_executor(SF sf, ZF zf) : sf_(std::move(sf)), zf_(std::move(zf)) {}
......@@ -481,7 +468,7 @@ class constrained_executor<SF, ZF> {
PUSHMI_TEMPLATE(class SF_ = SF)
(requires Invocable<SF_&>) //
auto schedule() {
auto schedule() {
return sf_();
}
};
......@@ -511,7 +498,7 @@ class constrained_executor<Data, DSF, DZF> {
PUSHMI_TEMPLATE(class DSF_ = DSF)
(requires Invocable<DSF_&, Data&>) //
auto schedule() {
auto schedule() {
return sf_(data_);
}
};
......@@ -530,32 +517,27 @@ PUSHMI_INLINE_VAR constexpr struct make_constrained_executor_fn {
}
PUSHMI_TEMPLATE(class SF)
(requires True<> PUSHMI_BROKEN_SUBSUMPTION(&&not ConstrainedExecutor<SF>)) //
auto
operator()(SF sf) const {
auto operator()(SF sf) const {
return constrained_executor<SF, priorityZeroF>{std::move(sf)};
}
PUSHMI_TEMPLATE(class SF, class ZF)
(requires True<> PUSHMI_BROKEN_SUBSUMPTION(&&not ConstrainedExecutor<SF>)) //
auto
operator()(SF sf, ZF zf) const {
auto operator()(SF sf, ZF zf) const {
return constrained_executor<SF, ZF>{std::move(sf), std::move(zf)};
}
PUSHMI_TEMPLATE(class Data)
(requires True<>&& ConstrainedExecutor<Data>) //
auto
operator()(Data d) const {
auto operator()(Data d) const {
return constrained_executor<Data, passDSF, passDZF>{std::move(d)};
}
PUSHMI_TEMPLATE(class Data, class DSF)
(requires ConstrainedExecutor<Data>) //
auto
operator()(Data d, DSF sf) const {
auto operator()(Data d, DSF sf) const {
return constrained_executor<Data, DSF, passDZF>{std::move(d), std::move(sf)};
}
PUSHMI_TEMPLATE(class Data, class DSF, class DZF)
(requires ConstrainedExecutor<Data>) //
auto
operator()(Data d, DSF sf, DZF zf) const {
auto operator()(Data d, DSF sf, DZF zf) const {
return constrained_executor<Data, DSF, DZF>{std::move(d), std::move(sf), std::move(zf)};
}
} const make_constrained_executor{};
......@@ -615,14 +597,12 @@ struct any_constrained_executor_ref {
using wrapped_t = detail::not_any_constrained_executor_ref_t<T>;
public:
using properties = property_set<>;
any_constrained_executor_ref() = delete;
any_constrained_executor_ref(const any_constrained_executor_ref&) = default;
PUSHMI_TEMPLATE(class Wrapped)
(requires ConstrainedExecutor<wrapped_t<Wrapped>>)
any_constrained_executor_ref(Wrapped& w) {
any_constrained_executor_ref(Wrapped& w) {
struct s {
static CV top(void* pobj) {
return ::folly::pushmi::top(*static_cast<Wrapped*>(pobj));
......@@ -661,7 +641,7 @@ auto make_any_constrained_executor_ref() {
PUSHMI_TEMPLATE(class E = std::exception_ptr, class Wrapped)
(requires ConstrainedExecutor<
detail::not_any_constrained_executor_ref_t<Wrapped>>) //
auto make_any_constrained_executor_ref(Wrapped& w) {
auto make_any_constrained_executor_ref(Wrapped& w) {
return any_constrained_executor_ref<E, constraint_t<Wrapped>>{w};
}
......@@ -791,8 +771,6 @@ class any_time_executor {
std::enable_if_t<!std::is_same<U, any_time_executor>::value, U>;
public:
using properties = property_set<>;
any_time_executor() = default;
any_time_executor(const any_time_executor& that) noexcept : any_time_executor() {
that.vptr_->op_(that.data_, &data_);
......@@ -805,7 +783,7 @@ class any_time_executor {
PUSHMI_TEMPLATE(class Wrapped)
(requires TimeExecutor<wrapped_t<Wrapped>>) //
explicit any_time_executor(Wrapped obj) noexcept(insitu<Wrapped>())
explicit any_time_executor(Wrapped obj) noexcept(insitu<Wrapped>())
: any_time_executor{std::move(obj), bool_<insitu<Wrapped>()>{}} {}
~any_time_executor() {
vptr_->consume_op_(std::move(data_), nullptr);
......@@ -842,8 +820,6 @@ class time_executor<SF, NF> {
NF nf_;
public:
using properties = property_set<>;
constexpr time_executor() = default;
constexpr explicit time_executor(SF sf) : sf_(std::move(sf)) {}
constexpr time_executor(SF sf, NF nf) : sf_(std::move(sf)), nf_(std::move(nf)) {}
......@@ -854,7 +830,7 @@ class time_executor<SF, NF> {
PUSHMI_TEMPLATE(class SF_ = SF)
(requires Invocable<SF_&>) //
auto schedule() {
auto schedule() {
return sf_();
}
};
......@@ -884,7 +860,7 @@ class time_executor<Data, DSF, DNF> {
PUSHMI_TEMPLATE(class DSF_ = DSF)
(requires Invocable<DSF_&, Data&>) //
auto schedule() {
auto schedule() {
return sf_(data_);
}
};
......@@ -903,32 +879,27 @@ PUSHMI_INLINE_VAR constexpr struct make_time_executor_fn {
}
PUSHMI_TEMPLATE(class SF)
(requires True<> PUSHMI_BROKEN_SUBSUMPTION(&&not TimeExecutor<SF>)) //
auto
operator()(SF sf) const {
auto operator()(SF sf) const {
return time_executor<SF, systemNowF>{std::move(sf)};
}
PUSHMI_TEMPLATE(class SF, class NF)
(requires True<> PUSHMI_BROKEN_SUBSUMPTION(&&not TimeExecutor<SF>)) //
auto
operator()(SF sf, NF nf) const {
auto operator()(SF sf, NF nf) const {
return time_executor<SF, NF>{std::move(sf), std::move(nf)};
}
PUSHMI_TEMPLATE(class Data)
(requires True<>&& TimeExecutor<Data>) //
auto
operator()(Data d) const {
auto operator()(Data d) const {
return time_executor<Data, passDSF, passDNF>{std::move(d)};
}
PUSHMI_TEMPLATE(class Data, class DSF)
(requires TimeExecutor<Data>) //
auto
operator()(Data d, DSF sf) const {
auto operator()(Data d, DSF sf) const {
return time_executor<Data, DSF, passDNF>{std::move(d), std::move(sf)};
}
PUSHMI_TEMPLATE(class Data, class DSF, class DNF)
(requires TimeExecutor<Data>) //
auto
operator()(Data d, DSF sf, DNF nf) const {
auto operator()(Data d, DSF sf, DNF nf) const {
return time_executor<Data, DSF, DNF>{std::move(d), std::move(sf), std::move(nf)};
}
} const make_time_executor{};
......@@ -967,7 +938,6 @@ PUSHMI_TEMPLATE(class Data, class DSF, class DNF)
template <>
struct construct_deduced<time_executor> : make_time_executor_fn {};
namespace detail {
template <class T>
using not_any_time_executor_ref_t = not_is_t<T, any_time_executor_ref>;
......@@ -988,8 +958,6 @@ struct any_time_executor_ref {
using wrapped_t = detail::not_any_time_executor_ref_t<T>;
public:
using properties = property_set<>;
any_time_executor_ref() = delete;
any_time_executor_ref(const any_time_executor_ref&) = default;
......@@ -1020,7 +988,7 @@ struct any_time_executor_ref {
PUSHMI_TEMPLATE(class Wrapped)
(requires TimeExecutor<wrapped_t<Wrapped>> && //
std::is_rvalue_reference<Wrapped>::value) //
any_time_executor_ref(Wrapped&& w) {
any_time_executor_ref(Wrapped&& w) {
struct s {
static TP now(void* pobj) {
return ::folly::pushmi::now(*static_cast<Wrapped*>(pobj));
......@@ -1064,7 +1032,7 @@ auto make_any_time_executor_ref() {
PUSHMI_TEMPLATE(class E = std::exception_ptr, class Wrapped)
(requires TimeExecutor<detail::not_any_time_executor_ref_t<Wrapped>>) //
auto make_any_time_executor_ref(Wrapped& w) {
auto make_any_time_executor_ref(Wrapped& w) {
return any_time_executor_ref<E, time_point_t<Wrapped>>{w};
}
......@@ -1078,7 +1046,7 @@ any_time_executor_ref()
PUSHMI_TEMPLATE(class Wrapped)
(requires TimeExecutor<detail::not_any_time_executor_ref_t<Wrapped>>) //
any_time_executor_ref(Wrapped&)
any_time_executor_ref(Wrapped&)
->any_time_executor_ref<std::exception_ptr, time_point_t<Wrapped>>;
#endif
......
......@@ -84,8 +84,6 @@ class any_flow_many_sender
using wrapped_t =
std::enable_if_t<!std::is_same<U, any_flow_many_sender>::value, U>;
public:
using properties = property_set<>;
any_flow_many_sender() = default;
any_flow_many_sender(any_flow_many_sender&& that) noexcept
: any_flow_many_sender() {
......@@ -122,7 +120,6 @@ class flow_many_sender<SF> {
public:
using sender_category = flow_sender_tag;
using properties = property_set<>;
constexpr flow_many_sender() = default;
constexpr explicit flow_many_sender(SF sf)
......
......@@ -104,7 +104,7 @@ class any_flow_receiver {
using wrapped_t =
std::enable_if_t<!std::is_same<U, any_flow_receiver>::value, U>;
public:
using properties = property_set<is_receiver<>, is_flow<>>;
using receiver_category = flow_receiver_tag;
any_flow_receiver() = default;
any_flow_receiver(any_flow_receiver&& that) noexcept : any_flow_receiver() {
......@@ -171,7 +171,7 @@ class flow_receiver<VF, EF, DF, StrtF> {
StrtF strtf_;
public:
using properties = property_set<is_receiver<>, is_flow<>>;
using receiver_category = flow_receiver_tag;
static_assert(
!detail::is_v<VF, on_error_fn>,
......@@ -255,11 +255,11 @@ class flow_receiver<Data, DVF, DEF, DDF, DStrtF> {
DStrtF strtf_;
public:
using properties = properties_t<Data>;
static_assert(
FlowReceiverDataArg<Data>,
"Data must be a flow receiver");
using receiver_category = flow_receiver_tag;
using properties = properties_t<Data>;
static_assert(
!detail::is_v<DVF, on_error_fn>,
......
......@@ -91,8 +91,6 @@ class any_flow_single_sender
using wrapped_t =
std::enable_if_t<!std::is_same<U, any_flow_single_sender>::value, U>;
public:
using properties = property_set<>;
any_flow_single_sender() = default;
any_flow_single_sender(any_flow_single_sender&& that) noexcept
: any_flow_single_sender() {
......@@ -132,7 +130,6 @@ class flow_single_sender<SF> {
public:
using sender_category = flow_single_sender_tag;
using properties = property_set<>;
constexpr flow_single_sender() = default;
constexpr explicit flow_single_sender(SF sf)
......
......@@ -25,6 +25,14 @@
namespace folly {
namespace pushmi {
// Traits types:
template< class, class = void >
struct sender_traits;
template< class, class = void >
struct receiver_traits;
// implementation types
template <PUSHMI_TYPE_CONSTRAINT(SemiMovable)... TN>
......
......@@ -84,8 +84,6 @@ class any_many_sender
std::enable_if_t<!std::is_same<U, any_many_sender>::value, U>;
public:
using properties = property_set<>;
any_many_sender() = default;
any_many_sender(any_many_sender&& that) noexcept : any_many_sender() {
that.vptr_->op_(that.data_, &data_);
......@@ -121,8 +119,6 @@ class many_sender<SF> : public sender_tag {
SF sf_;
public:
using properties = property_set<>;
constexpr many_sender() = default;
constexpr explicit many_sender(SF sf) : sf_(std::move(sf)) {}
......
......@@ -109,7 +109,7 @@ using receiver_from_fn = receiver_from_impl<FlowSender<In>>;
template <PUSHMI_TYPE_CONSTRAINT(Sender) In, class... AN>
using receiver_type_t =
typename receiver_from_fn<In>::template receiver_type<AN...>;
typename receiver_from_fn<In>::template receiver_type<AN...>;
template <class SenderCategory>
struct make_sender;
......
......@@ -38,8 +38,7 @@ struct for_each_fn {
struct Pull {
Out out_;
explicit Pull(Out out) : out_(std::move(out)) {}
using properties =
property_set_insert_t<properties_t<Out>, property_set<is_flow<>>>;
using receiver_category = flow_receiver_tag;
folly::Function<void(std::ptrdiff_t)> pull;
template <class... VN>
void value(VN&&... vn) {
......
......@@ -93,7 +93,7 @@ struct flow_from_producer {
template <class Producer>
struct flow_from_done {
using properties = property_set<is_receiver<>>;
using receiver_category = flow_receiver_tag;
explicit flow_from_done(std::shared_ptr<Producer> p) : p_(std::move(p)) {}
std::shared_ptr<Producer> p_;
......@@ -114,7 +114,7 @@ struct flow_from_done {
template <class Producer>
struct flow_from_up {
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
explicit flow_from_up(std::shared_ptr<Producer> p_) : p(std::move(p_)) {}
std::shared_ptr<Producer> p;
......@@ -125,34 +125,37 @@ struct flow_from_up {
}
// submit work to exec
::folly::pushmi::submit(
::folly::pushmi::schedule(p->exec), make_receiver([p = p, requested](auto) {
auto remaining = requested;
// this loop is structured to work when there is
// re-entrancy out.value in the loop may call up.value.
// to handle this the state of p->c must be captured and
// the remaining and p->c must be changed before
// out.value is called.
while (remaining-- > 0 && !p->stop && p->c != p->end) {
auto i = (p->c)++;
set_value(p->out, ::folly::pushmi::detail::as_const(*i));
}
if (p->c == p->end) {
set_done(p->out);
}
}));
::folly::pushmi::schedule(p->exec),
make_receiver([p = p, requested](auto) {
auto remaining = requested;
// this loop is structured to work when there is
// re-entrancy out.value in the loop may call up.value.
// to handle this the state of p->c must be captured and
// the remaining and p->c must be changed before
// out.value is called.
while (remaining-- > 0 && !p->stop && p->c != p->end) {
auto i = (p->c)++;
set_value(p->out, folly::as_const(*i));
}
if (p->c == p->end) {
set_done(p->out);
}
}));
}
template <class E>
void error(E) noexcept {
p->stop.store(true);
::folly::pushmi::submit(
::folly::pushmi::schedule(p->exec), flow_from_done<Producer>{p});
::folly::pushmi::schedule(p->exec),
flow_from_done<Producer>{p});
}
void done() {
p->stop.store(true);
::folly::pushmi::submit(
::folly::pushmi::schedule(p->exec), flow_from_done<Producer>{p});
::folly::pushmi::schedule(p->exec),
flow_from_done<Producer>{p});
}
};
......@@ -160,7 +163,7 @@ PUSHMI_INLINE_VAR constexpr struct flow_from_fn {
private:
template <class Producer>
struct receiver_impl : pipeorigin {
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
explicit receiver_impl(std::shared_ptr<Producer> p) : p_(std::move(p)) {}
std::shared_ptr<Producer> p_;
......
......@@ -28,8 +28,8 @@ namespace detail {
namespace submit_detail {
PUSHMI_CONCEPT_DEF(
template(class In, class... AN) //
(concept AutoSenderTo)(In, AN...), //
template(class In, class... AN) //
(concept AutoSenderTo)(In, AN...), //
SenderTo<In, receiver_type_t<std::decay_t<In>, AN...>>);
} // namespace submit_detail
......@@ -42,15 +42,12 @@ struct submit_fn {
struct fn : pipeorigin {
explicit fn(AN&&... an) : args_((AN &&) an...) {}
std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In)
(requires //
submit_detail::AutoSenderTo<In&&, AN...>) //
void
operator()(In&& in) {
using maker_t = ::folly::pushmi::detail::receiver_from_fn<std::decay_t<In>>;
PUSHMI_TEMPLATE(class In)( //
requires submit_detail::AutoSenderTo<In&&, AN...>) //
void operator()(In&& in) {
using maker_t = receiver_from_fn<std::decay_t<In>>;
using receiver_t = invoke_result_t<maker_t, std::tuple<AN...>&&>;
receiver_t out{
maker_t{}(std::move(args_))};
receiver_t out{maker_t{}(std::move(args_))}; (void)out;
::folly::pushmi::submit((In &&) in, std::move(out));
}
};
......@@ -148,8 +145,6 @@ struct blocking_submit_fn {
lock_state* state_;
Task t_;
using properties = properties_t<Task>;
PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out>) //
void submit(Out out) && {
......@@ -168,7 +163,7 @@ struct blocking_submit_fn {
lock_state* state_;
Out out_;
using properties = properties_t<Out>;
using receiver_category = receiver_category_t<Out>;
template <class V>
void value(V&& v) {
......
......@@ -29,20 +29,20 @@ struct tap_ {
Out out;
// side effect has no effect on the properties.
using properties = properties_t<Out>;
using receiver_category = receiver_category_t<Out>;
PUSHMI_TEMPLATE(class... VN)
(requires ReceiveValue<SideEffects&, const std::remove_reference_t<VN>&...>&&
ReceiveValue<Out&, VN...>) //
void value(VN&&... vn) {
set_value(sideEffects, as_const(vn)...);
void value(VN&&... vn) {
set_value(sideEffects, folly::as_const(vn)...);
set_value(out, (VN &&) vn...);
}
PUSHMI_TEMPLATE(class E)
(requires ReceiveError<SideEffects&, const std::remove_reference_t<E>&>&&
ReceiveError<Out&, E>) //
void error(E&& e) noexcept {
set_error(sideEffects, as_const(e));
void error(E&& e) noexcept {
set_error(sideEffects, folly::as_const(e));
set_error(out, (E&&) e);
}
void done() {
......@@ -51,8 +51,7 @@ struct tap_ {
}
PUSHMI_TEMPLATE(class Up)
(requires FlowReceiver<SideEffects>&& FlowReceiver<Out>) //
void starting(
Up&& up) {
void starting(Up&& up) {
// up is not made const because sideEffects is allowed to call methods on up
set_starting(sideEffects, up);
set_starting(out, (Up &&) up);
......@@ -63,7 +62,7 @@ PUSHMI_INLINE_VAR constexpr struct make_tap_fn {
PUSHMI_TEMPLATE(class SideEffects, class Out)
(requires Receiver<std::decay_t<SideEffects>>&& Receiver<std::decay_t<Out>>&&
Receiver<tap_<std::decay_t<SideEffects>, std::decay_t<Out>>>) //
auto operator()(const SideEffects& se, Out&& out) const {
auto operator()(const SideEffects& se, Out&& out) const {
return tap_<std::decay_t<SideEffects>, std::decay_t<Out>>{se, (Out &&) out};
}
} const make_tap{};
......@@ -105,9 +104,9 @@ struct tap_fn {
using receiver_t =
invoke_result_t<receiver_from_fn<std::decay_t<In>>, tap_t<Out>>;
PUSHMI_TEMPLATE(class Data, class Out)
(requires Receiver<std::decay_t<Out>>
&& SenderTo<In, Out>&&
SenderTo<In, receiver_t<Out>>) //
(requires Receiver<std::decay_t<Out>> &&
SenderTo<In, Out>&&
SenderTo<In, receiver_t<Out>>) //
auto operator()(Data&& in, Out&& out) const {
auto gang{receiver_from_fn<std::decay_t<In>>()(
detail::make_tap(sideEffects_, (Out &&) out))};
......
......@@ -21,7 +21,6 @@
namespace folly {
namespace pushmi {
namespace detail {
template <class Exec>
......@@ -36,13 +35,14 @@ struct via_fn_base {
template <class Exec, class Out>
struct via_fn_data : via_fn_base<Exec> {
via_fn_data(Out out, Exec exec)
: via_fn_base<Exec>(std::move(exec)), out_(std::make_shared<Out>(std::move(out))) {}
: via_fn_base<Exec>(std::move(exec))
, out_(std::make_shared<Out>(std::move(out))) {}
using properties = properties_t<Out>;
using receiver_category = receiver_category_t<Out>;
template <class CPO, class... AN>
struct impl {
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
const CPO& fn_;
std::tuple<Out&, AN...> an_;
std::shared_ptr<Out> out_;
......@@ -109,22 +109,23 @@ struct via_fn {
template <class In, class Factory>
struct submit_impl {
Factory ef_;
PUSHMI_TEMPLATE(class SIn, class Out)
(requires Receiver<Out>) //
void
operator()(SIn&& in, Out out) const {
void operator()(SIn&& in, Out out) const {
auto exec = ::folly::pushmi::make_strand(ef_);
::folly::pushmi::submit((In &&) in,
make_via_fn_data(std::move(out), std::move(exec)));
}
};
template <class Factory>
struct adapt_impl {
Factory ef_;
PUSHMI_TEMPLATE(class In)
(requires Sender<In>) //
auto
operator()(In&& in) const {
auto operator()(In&& in) const {
return ::folly::pushmi::detail::sender_from(
(In&&)in,
submit_impl<In&&, Factory>{ef_});
......
......@@ -113,14 +113,13 @@ concept PropertySet,
// customization point for a type with properties
template <class T, class Void=void>
template <class T, class = void>
struct member_properties {
using properties = property_set<>;
};
template <class T>
struct member_properties<
T, void_t<typename T::properties>> {
struct member_properties<T, void_t<typename T::properties>> {
using properties = typename T::properties;
};
......@@ -132,7 +131,7 @@ template <class T, class Void>
struct property_set_traits : std::conditional_t<
std::is_same<T, std::decay_t<T>>::value,
member_properties<T>,
property_set_traits<std::decay_t<T>, Void>>
property_set_traits<std::decay_t<T>>>
{};
template <class T, class Target, class Void>
......@@ -143,13 +142,14 @@ PUSHMI_INLINE_VAR constexpr bool property_set_traits_disable_v =
property_set_traits_disable<T, Target>::value;
template <class T>
using properties_t = std::enable_if_t<
using properties_t =
std::enable_if_t<
PropertySet<__properties_t<property_set_traits<T>>>,
__properties_t<property_set_traits<T>>>;
PUSHMI_CONCEPT_DEF(
template(class T)
concept Properties,
template(class T)
concept Properties,
PropertySet<__properties_t<property_set_traits<T>>>
);
......
......@@ -117,7 +117,7 @@ class any_receiver {
}
public:
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
any_receiver() = default;
any_receiver(any_receiver&& that) noexcept : any_receiver() {
......@@ -191,7 +191,7 @@ class receiver<VF, EF, DF> {
"error function must be noexcept and support std::exception_ptr");
public:
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
receiver() = default;
constexpr explicit receiver(VF vf) : receiver(std::move(vf), EF{}, DF{}) {}
......@@ -268,7 +268,7 @@ class receiver<Data, DVF, DEF, DDF> {
"error function must be noexcept and support std::exception_ptr");
public:
using properties = properties_t<Data>;
using receiver_category = receiver_tag;
constexpr explicit receiver(Data d)
: receiver(std::move(d), DVF{}, DEF{}, DDF{}) {}
......
......@@ -121,8 +121,6 @@ class any_single_sender
using wrapped_t =
std::enable_if_t<!std::is_same<U, any_single_sender>::value, U>;
public:
using properties = property_set<>;
any_single_sender() = default;
any_single_sender(any_single_sender&& that) noexcept : any_single_sender() {
that.vptr_->op_(that.data_, &data_);
......@@ -160,7 +158,6 @@ class single_sender<SF> {
public:
using sender_category = single_sender_tag;
using properties = property_set<>;
constexpr single_sender() = default;
constexpr explicit single_sender(SF sf) : sf_(std::move(sf)) {}
......@@ -182,7 +179,6 @@ class single_sender<Data, DSF> {
public:
using sender_category = single_sender_tag;
using properties = properties_t<Data>;
static_assert(
SingleSender<Data>,
......
......@@ -135,7 +135,7 @@ class strand_queue : public strand_queue_base<E> {
auto what{std::move(this->front().what)};
this->items_.pop();
guard.unlock();
set_error(what, detail::as_const(e));
set_error(what, folly::as_const(e));
guard.lock();
}
}
......@@ -161,7 +161,7 @@ struct strand_queue_receiver : std::shared_ptr<strand_queue<E, Exec>> {
~strand_queue_receiver() {}
explicit strand_queue_receiver(std::shared_ptr<strand_queue<E, Exec>> that)
: std::shared_ptr<strand_queue<E, Exec>>(that) {}
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
};
template <class E, class Exec>
......@@ -184,9 +184,7 @@ class strand_task
std::shared_ptr<strand_queue<E, Exec>> queue_;
public:
using properties =
property_set<
property_set_index_t<properties_t<sender_t<Exec>>, is_never_blocking<>>>;
using properties = property_set<is_never_blocking<>>;
strand_task(std::shared_ptr<strand_queue<E, Exec>> queue)
: queue_(std::move(queue)) {}
......
......@@ -30,8 +30,6 @@ struct subject;
template <class PS, class... TN>
struct subject<PS, TN...> : single_sender_tag::with_values<TN...> {
using properties = property_set<>;
struct subject_shared : single_sender_tag::with_values<TN...> {
using receiver_t = any_receiver<std::exception_ptr, TN...>;
bool done_ = false;
......@@ -104,7 +102,7 @@ struct subject<PS, TN...> : single_sender_tag::with_values<TN...> {
};
struct subject_receiver {
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
std::shared_ptr<subject_shared> s;
......
......@@ -67,11 +67,11 @@ struct flow_single_sender_tag
detail::inherit<flow_sender_tag, single_sender_tag>> {
};
struct flow_category {};
// sender and receiver are mutually exclusive
struct receiver_tag {
};
struct receiver_category {};
struct flow_receiver_tag : receiver_tag {
};
// blocking affects senders
......@@ -83,20 +83,6 @@ struct sequence_category {};
// trait & tag types
template <class... TN>
struct is_flow;
template <>
struct is_flow<> {
using property_category = flow_category;
};
template <class... TN>
struct is_receiver;
template <>
struct is_receiver<> {
using property_category = receiver_category;
};
template <class... TN>
struct is_always_blocking;
template <>
......
......@@ -198,7 +198,7 @@ class time_source_queue : public time_source_queue_base<E, TP> {
this->heap_.pop();
--s->items_;
guard.unlock();
set_error(what, detail::as_const(e));
set_error(what, folly::as_const(e));
guard.lock();
}
this->dispatching_ = false;
......@@ -231,7 +231,7 @@ struct time_source_queue_receiver
std::shared_ptr<time_source_queue<E, TP, NF, Exec>> that)
: std::shared_ptr<time_source_queue<E, TP, NF, Exec>>(that),
source_(that->source_.lock()) {}
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
std::shared_ptr<time_source_shared<E, TP>> source_;
};
......@@ -451,8 +451,7 @@ class time_source_task
std::shared_ptr<time_source_queue<E, time_point, NF, Exec>> queue_;
public:
using properties = property_set_insert_t<properties_t<sender_t<Exec>>, property_set<
is_never_blocking<>>>;
using properties = property_set<is_never_blocking<>>;
time_source_task(
time_point tp,
......
......@@ -17,7 +17,10 @@
#include <type_traits>
#include <folly/Traits.h>
#include <folly/Utility.h>
#include <folly/experimental/pushmi/detail/concept_def.h>
#include <folly/experimental/pushmi/detail/functional.h>
#define PUSHMI_NOEXCEPT_AUTO(...) \
noexcept(noexcept(static_cast<decltype((__VA_ARGS__))>(__VA_ARGS__)))\
......@@ -216,13 +219,28 @@ constexpr bool is_v = is_<T, C>::value;
template <bool B, class T = void>
using requires_ = std::enable_if_t<B, T>;
PUSHMI_INLINE_VAR constexpr struct as_const_fn {
template <bool>
struct Enable_ {};
template <>
struct Enable_<true> {
template <class T>
constexpr const T& operator()(T& t) const noexcept {
return t;
}
} const as_const{};
using _type = T;
};
template <class...>
struct Front_ {};
template <class T, class... Us>
struct Front_<T, Us...> {
using type = T;
};
// An alias for the type in the pack if the pack has exactly one type in it.
// Otherwise, this SFINAE's away. T cannot be an array type of an abstract type.
// Instantiation proceeds from left to right. The use of Enable_ here avoids
// needless instantiations of Front_.
template<class...Ts>
using identity_t = typename Enable_<sizeof...(Ts) == 1u>::
template _type<Front_<Ts...>>::type;
} // namespace detail
} // namespace pushmi
......
......@@ -118,7 +118,7 @@ class trampoline {
template<class SingleReceiver>
struct delegate_impl {
using properties = property_set<is_receiver<>>;
using receiver_category = receiver_tag;
std::decay_t<SingleReceiver> out_;
void value(){
delegator<E> that;
......
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