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

make subset of pushmi build in xplat

Summary:
changes needed to add pushmi to xplat which is needed to make folly::Executor depend on pushmi.

split from - D12912583

MSVC 15.6.7 (required to keep cuda working) issues:
- __VA_ARGS__ results in a single token on MSVC and not on gcc or clang. I changed the macros to expand the single token so that it is parsed as multiuple tokens again
- some template usage must be placed inside `decltype()` to work with MSVC
- a nested set of macros using __VA_ARGS__ only worked on MSVC and clang when nested twice, but not when nested three times. changed the macros to use explicit parameters.
- gave up on pushmi invoke/invoke_result_t, now uses folly:Invoke instead.
- gave up on property_insert_t, removed usage that was needed for ExecutorTest
- switched many uses of make_receiver/make_sender to full bespoke receiver/sender implementations.
- disabled deduction guides on windows
- disabled apply on windows
- added additional disambiguity for function overloads that MSVC complained were redefinitions (only differed in SFINAE) also reduced to one `operator|` for this reason
- restructured `__property_category_t` and `__properties_t` to reduce MSVC ICE and other issues.
- MSVC did not like `property_set_element<POut, property_category_t<PIn>>` changed to `property_set_element<POut, PCategory>`
- MSVC complained about implicitly deleted destructors for `property_set_insert` explicitly added them..
- MSVC does not like `)::value` sequence added `bool_v`.
- replaced auto with explicit return types in some places.
- added the missing `remove_cvref_t`

In other news:
- added tags.h to minimize Executor dependencies on pushmi
- add `property_set_traits_disable_v` to allow EventBase to disable SequencedExecutor traits specialization
- add support for building without exceptions to the customization points

Reviewed By: ericniebler

Differential Revision: D14686496

fbshipit-source-id: c3f195783fd9a5f77b997498c44d4eebef1afe57
parent 8044c14f
......@@ -15,7 +15,10 @@
*/
#pragma once
#include <functional>
#include <folly/experimental/pushmi/extension_points.h>
#include <folly/experimental/pushmi/detail/functional.h>
#include <folly/experimental/pushmi/forwards.h>
#include <folly/experimental/pushmi/properties.h>
......@@ -24,85 +27,30 @@ namespace pushmi {
// traits & tags
// cardinality affects both sender and receiver
struct cardinality_category {};
// Trait
template <class PS>
struct has_cardinality : category_query<PS, cardinality_category> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool has_cardinality_v = has_cardinality<PS>::value;
// flow affects both sender and receiver
struct flow_category {};
// sender and receiver are mutually exclusive
struct receiver_category {};
struct sender_category {};
// blocking affects senders
struct blocking_category {};
// sequence affects senders
struct sequence_category {};
// is_single trait and tag
template <class... TN>
struct is_single;
// Tag
template <>
struct is_single<> {
using property_category = cardinality_category;
};
// Trait
// is_single trait
template <class PS>
struct is_single<PS> : property_query<PS, is_single<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_single_v = is_single<PS>::value;
// is_many trait and tag
template <class... TN>
struct is_many;
// Tag
template <>
struct is_many<> {
using property_category = cardinality_category;
}; // many::value() does not terminate, so it is not a refinement of single
// Trait
// is_many trait
template <class PS>
struct is_many<PS> : property_query<PS, is_many<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_many_v = is_many<PS>::value;
// is_flow trait and tag
template <class... TN>
struct is_flow;
// Tag
template <>
struct is_flow<> {
using property_category = flow_category;
};
// Trait
// 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;
// Receiver trait and tag
template <class... TN>
struct is_receiver;
// Tag
template <>
struct is_receiver<> {
using property_category = receiver_category;
};
// Trait
// is_receiver trait
template <class PS>
struct is_receiver<PS> : property_query<PS, is_receiver<>> {};
template <class PS>
......@@ -134,15 +82,7 @@ PUSHMI_CONCEPT_DEF(
Receiver<R> && MoveConstructible<E>
);
// Sender trait and tag
template <class... TN>
struct is_sender;
// Tag
template <>
struct is_sender<> {
using property_category = sender_category;
};
// Trait
// is_sender trait
template <class PS>
struct is_sender<PS> : property_query<PS, is_sender<>> {};
template <class PS>
......@@ -170,74 +110,34 @@ PUSHMI_CONCEPT_DEF(
Sender<S> && Receiver<R>);
// is_always_blocking trait and tag
template <class... TN>
struct is_always_blocking;
// Tag
template <>
struct is_always_blocking<> {
using property_category = blocking_category;
};
// Trait
template <class PS>
struct is_always_blocking<PS> : property_query<PS, is_always_blocking<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_always_blocking_v =
is_always_blocking<PS>::value;
// is_never_blocking trait and tag
template <class... TN>
struct is_never_blocking;
// Tag
template <>
struct is_never_blocking<> {
using property_category = blocking_category;
};
// Trait
// is_never_blocking trait
template <class PS>
struct is_never_blocking<PS> : property_query<PS, is_never_blocking<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_never_blocking_v =
is_never_blocking<PS>::value;
// is_maybe_blocking trait and tag
template <class... TN>
struct is_maybe_blocking;
// Tag
template <>
struct is_maybe_blocking<> {
using property_category = blocking_category;
};
// Trait
// is_maybe_blocking trait
template <class PS>
struct is_maybe_blocking<PS> : property_query<PS, is_maybe_blocking<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_maybe_blocking_v =
is_maybe_blocking<PS>::value;
// is_fifo_sequence trait and tag
template <class... TN>
struct is_fifo_sequence;
// Tag
template <>
struct is_fifo_sequence<> {
using property_category = sequence_category;
};
// Trait
// is_fifo_sequence trait
template <class PS>
struct is_fifo_sequence<PS> : property_query<PS, is_fifo_sequence<>> {};
template <class PS>
PUSHMI_INLINE_VAR constexpr bool is_fifo_sequence_v =
is_fifo_sequence<PS>::value;
// is_concurrent_sequence trait and tag
template <class... TN>
struct is_concurrent_sequence;
// Tag
template <>
struct is_concurrent_sequence<> {
using property_category = sequence_category;
};
// Trait
// is_concurrent_sequence trait
template <class PS>
struct is_concurrent_sequence<PS>
: property_query<PS, is_concurrent_sequence<>> {};
......
......@@ -15,40 +15,21 @@
*/
#pragma once
#include <functional>
#include <folly/functional/Invoke.h>
#include <folly/experimental/pushmi/detail/concept_def.h>
namespace folly {
namespace pushmi {
PUSHMI_INLINE_VAR constexpr struct invoke_fn {
private:
template <class F>
using mem_fn_t = decltype(std::mem_fn(std::declval<F>()));
/* using override */ using folly::invoke;
public:
PUSHMI_TEMPLATE(class F, class... As)
(requires //
requires(
std::declval<F>()(std::declval<As>()...))) //
auto operator()(F&& f, As&&... as) const
noexcept(noexcept(((F &&) f)((As &&) as...))) {
return ((F &&) f)((As &&) as...);
}
PUSHMI_TEMPLATE(class F, class... As)
(requires //
requires(
std::mem_fn(std::declval<F>())(std::declval<As>()...))) //
auto operator()(F&& f, As&&... as) const
noexcept(noexcept(std::declval<mem_fn_t<F>>()((As &&) as...))) {
return std::mem_fn(f)((As &&) as...);
}
} invoke{};
template <class F, class... As>
using invoke_result_t =
decltype(folly::pushmi::invoke(std::declval<F>(), std::declval<As>()...));
/* using override */ using folly::invoke_result;
/* using override */ using folly::invoke_result_t;
/* using override */ using folly::is_invocable;
/* using override */ using folly::is_invocable_r;
/* using override */ using folly::is_nothrow_invocable;
/* using override */ using folly::is_nothrow_invocable_r;
PUSHMI_CONCEPT_DEF(
template (class F, class... Args)
......
......@@ -36,9 +36,10 @@ using not_is_t = std::enable_if_t<!is_v<std::decay_t<T>, C>, std::decay_t<T>>;
template <class E>
class any_executor {
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_storage_t< 2 * sizeof(void*) > buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -215,7 +216,7 @@ PUSHMI_INLINE_VAR constexpr struct make_executor_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
executor()->executor<ignoreSF>;
PUSHMI_TEMPLATE(class SF)
......@@ -294,7 +295,7 @@ PUSHMI_TEMPLATE(class E = std::exception_ptr, class Wrapped)
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
any_executor_ref()->any_executor_ref<std::exception_ptr>;
PUSHMI_TEMPLATE(class Wrapped)
......@@ -309,9 +310,10 @@ PUSHMI_TEMPLATE(class Wrapped)
template <class E, class CV>
class any_constrained_executor {
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_storage_t< 2 * sizeof(void*) > buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -560,7 +562,7 @@ PUSHMI_INLINE_VAR constexpr struct make_constrained_executor_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
constrained_executor()->constrained_executor<ignoreSF, priorityZeroF>;
PUSHMI_TEMPLATE(class SF)
......@@ -665,7 +667,7 @@ PUSHMI_TEMPLATE(class E = std::exception_ptr, class Wrapped)
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
any_constrained_executor_ref()
->any_constrained_executor_ref<std::exception_ptr, std::ptrdiff_t>;
......@@ -683,9 +685,10 @@ PUSHMI_TEMPLATE(class Wrapped)
template <class E, class TP>
class any_time_executor {
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_storage_t< 2 * sizeof(void*) > buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -932,7 +935,7 @@ PUSHMI_INLINE_VAR constexpr struct make_time_executor_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
time_executor()->time_executor<ignoreSF, systemNowF>;
PUSHMI_TEMPLATE(class SF)
......@@ -1067,7 +1070,7 @@ PUSHMI_TEMPLATE(class E = std::exception_ptr, class Wrapped)
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
any_time_executor_ref()
->any_time_executor_ref<
std::exception_ptr,
......
......@@ -15,12 +15,12 @@
*/
#pragma once
#include <functional>
#include <future>
#include <folly/experimental/pushmi/forwards.h>
#include <folly/experimental/pushmi/detail/functional.h>
#include <folly/experimental/pushmi/properties.h>
#include <folly/experimental/pushmi/traits.h>
#include <folly/experimental/pushmi/tags.h>
#include <folly/Portability.h>
namespace folly {
namespace pushmi {
......@@ -162,7 +162,7 @@ PUSHMI_TEMPLATE(class SD)
PUSHMI_TEMPLATE(class SD, class Out)
(requires //
requires(submit(*std::declval<SD>(), std::declval<Out>()))) //
void submit(SD&& sd, Out&& out) //
void submit(SD&& sd, Out&& out, ...) // MSVC(use ... to disambiguate)
noexcept(noexcept(submit(*sd, (Out &&) out))) {
submit(*sd, (Out &&) out);
}
......@@ -264,11 +264,15 @@ struct set_done_fn {
set_error(std::declval<S&>(), std::current_exception()))) //
void
operator()(S& s) const noexcept {
#if FOLLY_HAS_EXCEPTIONS
try {
set_done(s);
} catch (...) {
set_error(s, std::current_exception());
}
#else // FOLLY_HAS_EXCEPTIONS
set_done(s);
#endif // FOLLY_HAS_EXCEPTIONS
}
};
struct set_error_fn {
......@@ -289,11 +293,15 @@ struct set_value_fn {
set_error(std::declval<S&>(), std::current_exception()))) //
void
operator()(S& s, VN&&... vn) const noexcept {
#if FOLLY_HAS_EXCEPTIONS
try {
set_value(s, (VN &&) vn...);
} catch (...) {
set_error(s, std::current_exception());
}
#else // FOLLY_HAS_EXCEPTIONS
set_value(s, (VN &&) vn...);
#endif // FOLLY_HAS_EXCEPTIONS
}
};
......@@ -305,11 +313,15 @@ struct set_starting_fn {
set_error(std::declval<S&>(), std::current_exception()))) //
void
operator()(S& s, Up&& up) const noexcept {
#if FOLLY_HAS_EXCEPTIONS
try {
set_starting(s, (Up &&) up);
} catch (...) {
set_error(s, std::current_exception());
}
#else // FOLLY_HAS_EXCEPTIONS
set_starting(s, (Up &&) up);
#endif // FOLLY_HAS_EXCEPTIONS
}
};
......
......@@ -25,9 +25,10 @@ namespace pushmi {
template <class PE, class PV, class E, class... VN>
class any_flow_many_sender {
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_union_t<0, std::tuple<VN...>> buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -138,7 +139,14 @@ class flow_many_sender<Data, DSF> {
DSF sf_;
public:
using properties = property_set_insert_t<properties_t<Data>, property_set<is_sender<>, is_flow<>, is_many<>>>;
using properties = properties_t<Data>;
static_assert(
FlowSender<Data>,
"Data must be a flow sender");
static_assert(
is_many_v<Data>,
"Data must be a many sender");
constexpr flow_many_sender() = default;
constexpr explicit flow_many_sender(Data data)
......@@ -149,9 +157,15 @@ class flow_many_sender<Data, DSF> {
PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(lazy::FlowReceiver<Out> PUSHMI_AND
lazy::Invocable<DSF&, Data&, Out>))
void submit(Out out) {
void submit(Out out) & {
sf_(data_, std::move(out));
}
PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(lazy::FlowReceiver<Out> PUSHMI_AND
lazy::Invocable<DSF&, Data&, Out>))
void submit(Out out) && {
sf_(std::move(data_), std::move(out));
}
};
template <>
......@@ -186,7 +200,7 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_many_sender_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
flow_many_sender() -> flow_many_sender<ignoreSF>;
PUSHMI_TEMPLATE(class SF)
......
......@@ -25,9 +25,10 @@ template <class PE, class PV, class E, class... VN>
class any_flow_receiver {
bool done_ = false;
bool started_ = false;
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_union_t<0, std::tuple<VN...>> buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -228,8 +229,15 @@ class flow_receiver<VF, EF, DF, StrtF> {
}
};
PUSHMI_CONCEPT_DEF(
template (class T)
concept FlowReceiverDataArg,
FlowReceiver<T> &&
not Invocable<T&>
);
template<
PUSHMI_TYPE_CONSTRAINT(Receiver) Data,
PUSHMI_TYPE_CONSTRAINT(FlowReceiverDataArg) Data,
class DVF,
class DEF,
class DDF,
......@@ -247,7 +255,11 @@ class flow_receiver<Data, DVF, DEF, DDF, DStrtF> {
DStrtF strtf_;
public:
using properties = property_set_insert_t<properties_t<Data>, property_set<is_receiver<>, is_flow<>>>;
using properties = properties_t<Data>;
static_assert(
FlowReceiverDataArg<Data>,
"Data must be a flow receiver");
static_assert(
!detail::is_v<DVF, on_error_fn>,
......@@ -255,6 +267,9 @@ class flow_receiver<Data, DVF, DEF, DDF, DStrtF> {
static_assert(
!detail::is_v<DEF, on_value_fn>,
"the second parameter is the error implementation, but on_value{} was passed");
static_assert(
NothrowInvocable<DEF, Data&, std::exception_ptr>,
"error function must be noexcept and support std::exception_ptr");
constexpr explicit flow_receiver(Data d)
: flow_receiver(std::move(d), DVF{}, DEF{}, DDF{}) {}
......@@ -316,20 +331,14 @@ class flow_receiver<>
: public flow_receiver<ignoreVF, abortEF, ignoreDF, ignoreStrtF> {
};
PUSHMI_CONCEPT_DEF(
template (class T)
concept FlowReceiverDataArg,
FlowReceiver<T> &&
not Invocable<T&>
);
// TODO winnow down the number of make_flow_receiver overloads and deduction
// guides here, as was done for make_many.
////////////////////////////////////////////////////////////////////////////////
// make_flow_receiver
PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
inline auto operator()() const {
inline flow_receiver<>
operator()() const {
return flow_receiver<>{};
}
PUSHMI_TEMPLATE (class VF)
......@@ -337,17 +346,20 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
lazy::True<>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND
not lazy::FlowReceiverDataArg<VF>)))
auto operator()(VF nf) const {
flow_receiver<VF, abortEF, ignoreDF, ignoreStrtF>
operator()(VF nf) const {
return flow_receiver<VF, abortEF, ignoreDF, ignoreStrtF>{
std::move(nf)};
}
template <class... EFN>
auto operator()(on_error_fn<EFN...> ef) const {
flow_receiver<ignoreVF, on_error_fn<EFN...>, ignoreDF, ignoreStrtF>
operator()(on_error_fn<EFN...> ef) const {
return flow_receiver<ignoreVF, on_error_fn<EFN...>, ignoreDF, ignoreStrtF>{
std::move(ef)};
}
template <class DF>
auto operator()(on_done_fn<DF> df) const {
flow_receiver<ignoreVF, abortEF, on_done_fn<DF>, ignoreStrtF>
operator()(on_done_fn<DF> df) const {
return flow_receiver<ignoreVF, abortEF, on_done_fn<DF>, ignoreStrtF>{
std::move(df)};
}
......@@ -357,7 +369,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND
not lazy::FlowReceiverDataArg<VF> PUSHMI_AND
not lazy::Invocable<EF&>)))
auto operator()(VF nf, EF ef) const {
flow_receiver<VF, EF, ignoreDF, ignoreStrtF>
operator()(VF nf, EF ef) const {
return flow_receiver<VF, EF, ignoreDF, ignoreStrtF>{std::move(nf),
std::move(ef)};
}
......@@ -367,7 +380,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
lazy::Invocable<DF&>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND
not lazy::FlowReceiverDataArg<EF>)))
auto operator()(EF ef, DF df) const {
flow_receiver<ignoreVF, EF, DF, ignoreStrtF>
operator()(EF ef, DF df) const {
return flow_receiver<ignoreVF, EF, DF, ignoreStrtF>{std::move(ef), std::move(df)};
}
PUSHMI_TEMPLATE (class VF, class EF, class DF)
......@@ -375,7 +389,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
lazy::Invocable<DF&>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND
not lazy::FlowReceiverDataArg<VF>)))
auto operator()(VF nf, EF ef, DF df) const {
flow_receiver<VF, EF, DF, ignoreStrtF>
operator()(VF nf, EF ef, DF df) const {
return flow_receiver<VF, EF, DF, ignoreStrtF>{std::move(nf),
std::move(ef), std::move(df)};
}
......@@ -384,7 +399,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
lazy::Invocable<DF&>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND
not lazy::FlowReceiverDataArg<VF>)))
auto operator()(VF nf, EF ef, DF df, StrtF strtf) const {
flow_receiver<VF, EF, DF, StrtF>
operator()(VF nf, EF ef, DF df, StrtF strtf) const {
return flow_receiver<VF, EF, DF, StrtF>{std::move(nf), std::move(ef),
std::move(df), std::move(strtf)};
}
......@@ -392,7 +408,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::FlowReceiverDataArg<Data>))
auto operator()(Data d) const {
flow_receiver<Data, passDVF, passDEF, passDDF, passDStrtF>
operator()(Data d) const {
return flow_receiver<Data, passDVF, passDEF, passDDF, passDStrtF>{
std::move(d)};
}
......@@ -400,21 +417,24 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::FlowReceiverDataArg<Data>))
auto operator()(Data d, DVF nf) const {
flow_receiver<Data, DVF, passDEF, passDDF, passDStrtF>
operator()(Data d, DVF nf) const {
return flow_receiver<Data, DVF, passDEF, passDDF, passDStrtF>{
std::move(d), std::move(nf)};
}
PUSHMI_TEMPLATE(class Data, class... DEFN)
(requires PUSHMI_EXP(
lazy::FlowReceiverDataArg<Data>))
auto operator()(Data d, on_error_fn<DEFN...> ef) const {
flow_receiver<Data, passDVF, on_error_fn<DEFN...>, passDDF, passDStrtF>
operator()(Data d, on_error_fn<DEFN...> ef) const {
return flow_receiver<Data, passDVF, on_error_fn<DEFN...>, passDDF, passDStrtF>{
std::move(d), std::move(ef)};
}
PUSHMI_TEMPLATE(class Data, class DDF)
(requires PUSHMI_EXP(
lazy::FlowReceiverDataArg<Data>))
auto operator()(Data d, on_done_fn<DDF> df) const {
flow_receiver<Data, passDVF, passDEF, on_done_fn<DDF>, passDStrtF>
operator()(Data d, on_done_fn<DDF> df) const {
return flow_receiver<Data, passDVF, passDEF, on_done_fn<DDF>, passDStrtF>{
std::move(d), std::move(df)};
}
......@@ -423,14 +443,16 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
lazy::FlowReceiverDataArg<Data>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND
not lazy::Invocable<DEF&, Data&>)))
auto operator()(Data d, DVF nf, DEF ef) const {
flow_receiver<Data, DVF, DEF, passDDF, passDStrtF>
operator()(Data d, DVF nf, DEF ef) const {
return flow_receiver<Data, DVF, DEF, passDDF, passDStrtF>{std::move(d), std::move(nf), std::move(ef)};
}
PUSHMI_TEMPLATE(class Data, class DEF, class DDF)
(requires PUSHMI_EXP(
lazy::FlowReceiverDataArg<Data> PUSHMI_AND
lazy::Invocable<DDF&, Data&>))
auto operator()(Data d, DEF ef, DDF df) const {
flow_receiver<Data, passDVF, DEF, DDF, passDStrtF>
operator()(Data d, DEF ef, DDF df) const {
return flow_receiver<Data, passDVF, DEF, DDF, passDStrtF>{
std::move(d), std::move(ef), std::move(df)};
}
......@@ -438,7 +460,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
(requires PUSHMI_EXP(
lazy::FlowReceiverDataArg<Data> PUSHMI_AND
lazy::Invocable<DDF&, Data&>))
auto operator()(Data d, DVF nf, DEF ef, DDF df) const {
flow_receiver<Data, DVF, DEF, DDF, passDStrtF>
operator()(Data d, DVF nf, DEF ef, DDF df) const {
return flow_receiver<Data, DVF, DEF, DDF, passDStrtF>{std::move(d),
std::move(nf), std::move(ef), std::move(df)};
}
......@@ -446,7 +469,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
(requires PUSHMI_EXP(
lazy::FlowReceiverDataArg<Data> PUSHMI_AND
lazy::Invocable<DDF&, Data&>))
auto operator()(Data d, DVF nf, DEF ef, DDF df, DStrtF strtf) const {
flow_receiver<Data, DVF, DEF, DDF, DStrtF>
operator()(Data d, DVF nf, DEF ef, DDF df, DStrtF strtf) const {
return flow_receiver<Data, DVF, DEF, DDF, DStrtF>{std::move(d),
std::move(nf), std::move(ef), std::move(df), std::move(strtf)};
}
......@@ -454,7 +478,7 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_receiver_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
flow_receiver() -> flow_receiver<>;
PUSHMI_TEMPLATE(class VF)
......
......@@ -18,6 +18,7 @@
#include <folly/experimental/pushmi/flow_receiver.h>
#include <folly/experimental/pushmi/executor.h>
#include <folly/experimental/pushmi/trampoline.h>
#include <tuple>
#include <type_traits>
namespace folly {
......@@ -25,10 +26,10 @@ namespace pushmi {
template <class PE, class E, class... VN>
class any_flow_single_sender {
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_storage_t<
sizeof(std::tuple<VN...>), alignof(std::tuple<VN...>)> buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -147,9 +148,14 @@ class flow_single_sender<Data, DSF> {
DSF sf_;
public:
using properties = property_set_insert_t<
properties_t<Data>,
property_set<is_sender<>, is_flow<>, is_single<>>>;
using properties = properties_t<Data>;
static_assert(
FlowSender<Data>,
"Data must be a flow sender");
static_assert(
is_single_v<Data>,
"Data must be a single sender");
constexpr flow_single_sender() = default;
constexpr explicit flow_single_sender(Data data)
......@@ -197,7 +203,7 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_single_sender_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
flow_single_sender() -> flow_single_sender<ignoreSF>;
PUSHMI_TEMPLATE(class SF)
......
......@@ -15,54 +15,16 @@
*/
#pragma once
#include <folly/experimental/pushmi/traits.h>
#include <chrono>
#include <exception>
#include <folly/experimental/pushmi/traits.h>
#include <folly/experimental/pushmi/tags.h>
#include <folly/experimental/pushmi/properties.h>
namespace folly {
namespace pushmi {
// property_set
template <class T, class = void>
struct property_traits;
template <class T, class = void>
struct property_set_traits;
template <class... PropertyN>
struct property_set;
// trait & tag types
template <class... TN>
struct is_single;
template <class... TN>
struct is_many;
template <class... TN>
struct is_flow;
template <class... TN>
struct is_receiver;
template <class... TN>
struct is_sender;
template <class... TN>
struct is_always_blocking;
template <class... TN>
struct is_never_blocking;
template <class... TN>
struct is_maybe_blocking;
template <class... TN>
struct is_fifo_sequence;
template <class... TN>
struct is_concurrent_sequence;
// implementation types
template <PUSHMI_TYPE_CONSTRAINT(SemiMovable)... TN>
......
......@@ -25,9 +25,10 @@ namespace pushmi {
template <class E, class... VN>
class any_many_sender {
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_union_t<0, std::tuple<VN...>> buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -140,9 +141,14 @@ class many_sender<Data, DSF> {
DSF sf_;
public:
using properties = property_set_insert_t<
properties_t<Data>,
property_set<is_sender<>, is_many<>>>;
using properties = properties_t<Data>;
static_assert(
Sender<Data>,
"Data must be a sender");
static_assert(
is_many_v<Data>,
"Data must be a many sender");
constexpr many_sender() = default;
constexpr explicit many_sender(Data data) : data_(std::move(data)) {}
......@@ -197,7 +203,7 @@ PUSHMI_INLINE_VAR constexpr struct make_many_sender_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
many_sender()->many_sender<ignoreSF>;
PUSHMI_TEMPLATE(class SF)
......
......@@ -36,7 +36,7 @@
namespace folly {
namespace pushmi {
#if __cpp_lib_apply >= 201603
#if __cpp_lib_apply >= 201603 || not PUSHMI_NOT_ON_WINDOWS
using std::apply;
#else
namespace detail {
......@@ -77,7 +77,7 @@ struct make_receiver<> : construct_deduced<receiver> {};
template <>
struct make_receiver<true> : construct_deduced<flow_receiver> {};
template <class Cardinality, bool IsFlow>
template <bool IsFlow>
struct receiver_from_impl {
using MakeReceiver = make_receiver<IsFlow>;
template <class... AN>
......@@ -111,7 +111,6 @@ struct receiver_from_impl {
template <PUSHMI_TYPE_CONSTRAINT(Sender) In>
using receiver_from_fn = receiver_from_impl<
property_set_index_t<properties_t<In>, is_single<>>,
property_query_v<properties_t<In>, is_flow<>>>;
template <PUSHMI_TYPE_CONSTRAINT(Sender) In, class... AN>
......
......@@ -34,22 +34,21 @@ namespace operators {
PUSHMI_INLINE_VAR constexpr struct from_fn {
private:
struct sender_base : many_sender<> {
template <class I, class S>
struct sender_impl : pipeorigin {
using properties = property_set<
is_sender<>,
is_many<>,
is_always_blocking<>>;
};
template <class I, class S>
struct out_impl {
I begin_;
S end_;
PUSHMI_TEMPLATE(class In, class Out)
sender_impl(I begin, S end) : begin_(begin), end_(end) {}
PUSHMI_TEMPLATE(class Out)
(requires ReceiveValue<
Out,
typename std::iterator_traits<I>::value_type>) //
void
operator()(In&&, Out out) const {
submit(Out out) {
auto c = begin_;
for (; c != end_; ++c) {
set_value(out, *c);
......@@ -65,7 +64,7 @@ PUSHMI_INLINE_VAR constexpr struct from_fn {
std::forward_iterator_tag>) //
auto
operator()(I begin, S end) const {
return make_many_sender(sender_base{}, out_impl<I, S>{begin, end});
return sender_impl<I, S>{begin, end};
}
PUSHMI_TEMPLATE(class R)
......@@ -91,9 +90,30 @@ struct flow_from_producer {
std::atomic<bool> stop;
};
template <class Producer>
struct flow_from_done {
using properties = property_set<is_receiver<>>;
explicit flow_from_done(std::shared_ptr<Producer> p) : p_(std::move(p)) {}
std::shared_ptr<Producer> p_;
template <class SubExec>
void value(SubExec) {
set_done(p_->out);
}
template <class E>
void error(E) noexcept {
set_done(p_->out);
}
void done() {
}
};
template <class Producer>
struct flow_from_up {
using properties = properties_t<receiver<>>;
using properties = property_set<is_receiver<>>;
explicit flow_from_up(std::shared_ptr<Producer> p_) : p(std::move(p_)) {}
std::shared_ptr<Producer> p;
......@@ -125,38 +145,63 @@ struct flow_from_up {
void error(E) noexcept {
p->stop.store(true);
::folly::pushmi::submit(
::folly::pushmi::schedule(p->exec), make_receiver([p = p](auto) { set_done(p->out); }));
::folly::pushmi::schedule(p->exec), flow_from_done<Producer>{p});
}
void done() {
p->stop.store(true);
::folly::pushmi::submit(
::folly::pushmi::schedule(p->exec), make_receiver([p = p](auto) { set_done(p->out); }));
::folly::pushmi::schedule(p->exec), flow_from_done<Producer>{p});
}
};
PUSHMI_INLINE_VAR constexpr struct flow_from_fn {
private:
template <class Producer>
struct receiver_impl : pipeorigin {
using properties = property_set<is_receiver<>>;
explicit receiver_impl(std::shared_ptr<Producer> p) : p_(std::move(p)) {}
std::shared_ptr<Producer> p_;
template<class SubExec>
void value(SubExec) {
// pass reference for cancellation.
set_starting(p_->out, flow_from_up<Producer>{p_});
}
template <class E>
void error(E) noexcept {
p_->stop.store(true);
set_done(p_->out);
}
void done() {
}
};
template <class I, class S, class Exec>
struct out_impl {
struct sender_impl : pipeorigin {
using properties = property_set<
is_sender<>,
is_flow<>,
is_many<>,
is_always_blocking<>>;
I begin_;
S end_;
Exec exec_;
sender_impl(I begin, S end, Exec exec) : begin_(begin), end_(end), exec_(exec) {}
PUSHMI_TEMPLATE(class Out)
(requires ReceiveValue<
Out,
Out&,
typename std::iterator_traits<I>::value_type>) //
void
operator()(Out out) {
submit(Out out) {
using Producer = flow_from_producer<I, S, Out, Exec>;
auto p = std::make_shared<Producer>(
begin_, end_, std::move(out), exec_, false);
::folly::pushmi::submit(
::folly::pushmi::schedule(exec_), make_receiver([p](auto) {
// pass reference for cancellation.
set_starting(p->out, make_receiver(flow_from_up<Producer>{p}));
}));
::folly::pushmi::schedule(exec_), receiver_impl<Producer>{p});
}
};
......@@ -183,7 +228,7 @@ PUSHMI_INLINE_VAR constexpr struct flow_from_fn {
std::forward_iterator_tag>&& Executor<Exec>) //
auto
operator()(I begin, S end, Exec exec) const {
return make_flow_many_sender(out_impl<I, S, Exec>{begin, end, exec});
return sender_impl<I, S, Exec>{begin, end, exec};
}
PUSHMI_TEMPLATE(class R, class Exec)
......
......@@ -132,10 +132,10 @@ struct blocking_submit_fn {
}
PUSHMI_TEMPLATE(class Exec_ = Exec)
(requires ConstrainedExecutor<Exec_>) //
auto schedule(constraint_t<Exec_> top) {
auto schedule(constraint_t<Exec_> at) {
auto protected_scope = protect_stack{state_};
return nested_task_impl<sender_t<Exec_, constraint_t<Exec_>>>{
state_, ::folly::pushmi::schedule(ex_, std::move(top))};
state_, ::folly::pushmi::schedule(ex_, std::move(at))};
}
};
......
......@@ -71,16 +71,18 @@ PUSHMI_INLINE_VAR constexpr struct make_tap_fn {
struct tap_fn {
private:
PUSHMI_TEMPLATE(class In, class SideEffects)
(requires SenderTo<In, SideEffects>) //
static auto impl(
In&& in,
SideEffects&& sideEffects) {
return ::folly::pushmi::detail::sender_from(
(In &&) in,
submit_impl<In, std::decay_t<SideEffects>>{(SideEffects &&)
struct impl_fn {
PUSHMI_TEMPLATE(class In, class SideEffects)
(requires SenderTo<In, SideEffects>) //
auto operator()(
In&& in,
SideEffects&& sideEffects) {
return ::folly::pushmi::detail::sender_from(
(In &&) in,
submit_impl<In, std::decay_t<SideEffects>>{(SideEffects &&)
sideEffects});
}
}
};
template <class... AN>
struct adapt_impl {
......@@ -88,7 +90,7 @@ struct tap_fn {
PUSHMI_TEMPLATE(class In)
(requires Sender<std::decay_t<In>>) //
auto operator()(In&& in) {
return tap_fn::impl(
return tap_fn::impl_fn{}(
(In &&) in,
::folly::pushmi::detail::receiver_from_fn<In>()(std::move(args_)));
}
......
......@@ -62,7 +62,7 @@ struct transform_on<F, is_single<>, true> {
constexpr explicit transform_on(F f) : f_(std::move(f)) {}
template <class Out>
auto operator()(Out out) const {
return make_flow_single(std::move(out), on_value(*this));
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) {
......
......@@ -34,32 +34,67 @@ struct via_fn_base {
}
};
template <class Exec, class Out>
struct via_fn_data : flow_receiver<>, via_fn_base<Exec> {
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))) {}
using properties = properties_t<Out>;
using flow_receiver<>::value;
using flow_receiver<>::error;
using flow_receiver<>::done;
template <class Up>
template <class CPO, class... AN>
struct impl {
Up up_;
using properties = property_set<is_receiver<>>;
const CPO& fn_;
std::tuple<Out&, AN...> an_;
std::shared_ptr<Out> out_;
void operator()(any) {
set_starting(out_, std::move(up_));
void value(any) {
::folly::pushmi::apply(fn_, std::move(an_));
}
template<class E>
void error(E e) noexcept {
set_error(*out_, e);
}
void done() {
}
};
template <class CPO, class... AN>
void via(const CPO& fn, AN&&... an) {
submit(
::folly::pushmi::schedule(this->via_fn_base_ref().exec_),
impl<CPO, std::decay_t<AN>...>{
fn, std::tuple<Out&, std::decay_t<AN>...>{*out_, (AN &&) an...}, out_});
}
template<class... VN>
void value(VN&&... vn) {
if (this->via_fn_base_ref().done_) {
return;
}
via(set_value, (VN&&) vn...);
}
template<class E>
void error(E&& e) noexcept {
if (this->via_fn_base_ref().done_) {
return;
}
this->via_fn_base_ref().done_ = true;
via(set_error, (E&&) e);
}
void done() {
if (this->via_fn_base_ref().done_) {
return;
}
this->via_fn_base_ref().done_ = true;
via(set_done);
}
template<class Up>
void starting(Up&& up) {
if (this->via_fn_base_ref().done_) {
return;
}
submit(
::folly::pushmi::schedule(this->via_fn_base_ref().exec_),
::folly::pushmi::make_receiver(impl<std::decay_t<Up>>{
(Up &&) up, out_}));
via(set_starting, (Up&&) up);
}
std::shared_ptr<Out> out_;
};
......@@ -71,69 +106,6 @@ auto make_via_fn_data(Out out, Exec ex) -> via_fn_data<Exec, Out> {
struct via_fn {
private:
template <class Out>
struct on_value_impl {
template <class V>
struct impl {
V v_;
std::shared_ptr<Out> out_;
void operator()(any) {
set_value(out_, std::move(v_));
}
};
template <class Data, class V>
void operator()(Data& data, V&& v) const {
if (data.via_fn_base_ref().done_) {
return;
}
submit(
::folly::pushmi::schedule(data.via_fn_base_ref().exec_),
::folly::pushmi::make_receiver(impl<std::decay_t<V>>{
(V &&) v, data.out_}));
}
};
template <class Out>
struct on_error_impl {
template <class E>
struct impl {
E e_;
std::shared_ptr<Out> out_;
void operator()(any) noexcept {
set_error(out_, std::move(e_));
}
};
template <class Data, class E>
void operator()(Data& data, E e) const noexcept {
if (data.via_fn_base_ref().done_) {
return;
}
data.via_fn_base_ref().done_ = true;
submit(
::folly::pushmi::schedule(data.via_fn_base_ref().exec_),
::folly::pushmi::make_receiver(
impl<E>{std::move(e), std::move(data.out_)}));
}
};
template <class Out>
struct on_done_impl {
struct impl {
std::shared_ptr<Out> out_;
void operator()(any) {
set_done(out_);
}
};
template <class Data>
void operator()(Data& data) const {
if (data.via_fn_base_ref().done_) {
return;
}
data.via_fn_base_ref().done_ = true;
submit(
::folly::pushmi::schedule(data.via_fn_base_ref().exec_),
::folly::pushmi::make_receiver(
impl{std::move(data.out_)}));
}
};
template <class In, class Factory>
struct submit_impl {
Factory ef_;
......@@ -142,13 +114,8 @@ struct via_fn {
void
operator()(SIn&& in, Out out) const {
auto exec = ::folly::pushmi::make_strand(ef_);
::folly::pushmi::submit(
(In &&) in,
::folly::pushmi::detail::receiver_from_fn<std::decay_t<In>>()(
make_via_fn_data(std::move(out), std::move(exec)),
on_value_impl<Out>{},
on_error_impl<Out>{},
on_done_impl<Out>{}));
::folly::pushmi::submit((In &&) in,
make_via_fn_data(std::move(out), std::move(exec)));
}
};
template <class Factory>
......
......@@ -21,32 +21,15 @@
namespace folly {
namespace pushmi {
struct pipeorigin {};
PUSHMI_TEMPLATE(class In, class Op)
(requires PUSHMI_EXP(lazy::Sender<In> PUSHMI_AND
lazy::Invocable<Op&, In>)) //
(requires PUSHMI_EXP(lazy::Invocable<Op&, In>)) //
decltype(auto)
operator|(In&& in, Op&& op) {
return op((In &&) in);
}
PUSHMI_TEMPLATE(class Ex, class Op)
(requires PUSHMI_EXP(lazy::Executor<Ex> PUSHMI_AND
lazy::Invocable<Op&, Ex>)) //
decltype(auto)
operator|(Ex&& ex, Op&& op) {
return op((Ex &&) ex);
}
PUSHMI_TEMPLATE(class Out, class Op)
(requires PUSHMI_EXP(lazy::Receiver<Out> PUSHMI_AND
lazy::Invocable<Op&, Out>)) //
decltype(auto)
operator|(Out&& out, Op&& op) {
return op((Out &&) out);
}
PUSHMI_INLINE_VAR constexpr struct pipe_fn {
#if __cpp_fold_expressions >= 201603
#if __cpp_fold_expressions >= 201603 && PUSHMI_NOT_ON_WINDOWS
template <class T, class... FN>
auto operator()(T&& t, FN&&... fn) const
-> decltype(((T &&) t | ... | (FN &&) fn)) {
......
......@@ -15,9 +15,8 @@
*/
#pragma once
#include <folly/Traits.h>
#include <folly/experimental/pushmi/traits.h>
#include <folly/experimental/pushmi/forwards.h>
#include <folly/Traits.h>
namespace folly {
namespace pushmi {
......@@ -25,10 +24,19 @@ namespace pushmi {
// property_set implements a map of category-type to property-type.
// for each category only one property in that category is allowed in the set.
// customization point for a property with a category
template <class T, class = void>
struct property_traits;
template <class T>
using __property_category_t = typename T::property_category;
template <class T, class = void>
struct property_set_traits;
template <class... PropertyN>
struct property_set;
template <class T, class Target, class = void>
struct property_set_traits_disable;
// customization point for a property with a category
template <class T, class Void=void>
struct member_property_category {};
......@@ -36,10 +44,13 @@ struct member_property_category {};
template <class T>
struct member_property_category<
T,
void_t<__property_category_t<T>>> {
using property_category = __property_category_t<T>;
void_t<typename T::property_category>> {
using property_category = typename T::property_category;
};
template <class T>
using __property_category_t = typename member_property_category<T>::property_category;
// allow specializations to use enable_if to constrain
template <class T, class Void>
struct property_traits : std::conditional_t<
......@@ -102,19 +113,20 @@ concept PropertySet,
// customization point for a type with properties
template <class T>
using __properties_t = typename T::properties;
template <class T, class Void=void>
struct member_properties {};
struct member_properties {
using properties = property_set<>;
};
template <class T>
struct member_properties<
T,
void_t<__properties_t<T>>> {
using properties = __properties_t<T>;
T, void_t<typename T::properties>> {
using properties = typename T::properties;
};
template <class T>
using __properties_t = typename member_properties<T>::properties;
// allow specializations to use enable_if to constrain
template <class T, class Void>
struct property_set_traits : std::conditional_t<
......@@ -123,6 +135,13 @@ struct property_set_traits : std::conditional_t<
property_set_traits<std::decay_t<T>, Void>>
{};
template <class T, class Target, class Void>
struct property_set_traits_disable : std::false_type {};
template <class T, class Target>
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<
PropertySet<__properties_t<property_set_traits<T>>>,
......@@ -137,9 +156,9 @@ concept Properties,
// find property in the specified set that matches the category of the property
// specified.
namespace detail {
template <class PIn, class POut>
template <class PCategory, class POut>
POut __property_set_index_fn(
property_set_element<POut, property_category_t<PIn>>);
property_set_element<POut, PCategory>*);
template <class PIn, class POut, class... Ps>
property_set<std::conditional_t<PUSHMI_PP_IS_SAME(Ps, POut), PIn, Ps>...>
......@@ -156,6 +175,8 @@ using property_set_insert_one_t =
template <class PS0, class>
struct property_set_insert {
// fix MSVC issue
~property_set_insert();
using type = PS0;
};
......@@ -163,13 +184,17 @@ template <class PS0, class P, class... P1>
struct property_set_insert<PS0, property_set<P, P1...>>
: property_set_insert<
property_set_insert_one_t<PS0, P>,
property_set<P1...>> {};
property_set<P1...>> {
// fix MSVC issue
~property_set_insert();
};
} // namespace detail
template <class PS, class P>
using property_set_index_t = std::enable_if_t<
PropertySet<PS> && Property<P>,
decltype(detail::__property_set_index_fn<P>(PS{}))>;
decltype(detail::__property_set_index_fn<property_category_t<P>>(std::declval<PS*>()))>;
template <class PS0, class PS1>
using property_set_insert_t = typename std::enable_if_t<
......@@ -186,8 +211,8 @@ template <class PIn>
std::false_type property_query_fn(void*);
template <class PS, class... ExpectedN>
struct property_query_impl : bool_<and_v<decltype(property_query_fn<ExpectedN>(
(properties_t<PS>*)nullptr))::value...>> {};
struct property_query_impl : bool_<and_v<bool_v<decltype(property_query_fn<ExpectedN>(
(properties_t<PS>*)nullptr))>...>> {};
} // namespace detail
template <class PS, class... ExpectedN>
......@@ -209,8 +234,8 @@ template <class C>
std::false_type category_query_fn(void*);
template <class PS, class... ExpectedN>
struct category_query_impl : bool_<and_v<decltype(category_query_fn<ExpectedN>(
(properties_t<PS>*)nullptr))::value...>> {};
struct category_query_impl : bool_<and_v<bool_v<decltype(category_query_fn<ExpectedN>(
(properties_t<PS>*)nullptr))>...>> {};
} // namespace detail
template <class PS, class... ExpectedN>
......
......@@ -32,9 +32,10 @@ namespace pushmi {
template <class E, class... VN>
class any_receiver {
bool done_ = false;
using insitu_t = std::promise<int>;
union data {
void* pobj_ = nullptr;
std::aligned_union_t<0, std::promise<int>> buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() noexcept {
......@@ -229,8 +230,16 @@ class receiver<VF, EF, DF> {
}
};
PUSHMI_CONCEPT_DEF(
template (class T)
concept ReceiverDataArg,
Receiver<T> &&
not Invocable<T&>
);
template <
PUSHMI_TYPE_CONSTRAINT(Receiver) Data,
PUSHMI_TYPE_CONSTRAINT(ReceiverDataArg) Data,
class DVF,
class DEF,
class DDF>
......@@ -244,6 +253,10 @@ class receiver<Data, DVF, DEF, DDF> {
DEF ef_;
DDF df_;
static_assert(
ReceiverDataArg<Data>,
"Data must be a receiver");
static_assert(
!detail::is_v<DVF, on_error_fn>,
"the first parameter is the value implementation, but on_error{} was passed");
......@@ -255,8 +268,7 @@ class receiver<Data, DVF, DEF, DDF> {
"error function must be noexcept and support std::exception_ptr");
public:
using properties =
property_set_insert_t<properties_t<Data>, property_set<is_receiver<>>>;
using properties = properties_t<Data>;
constexpr explicit receiver(Data d)
: receiver(std::move(d), DVF{}, DEF{}, DDF{}) {}
......@@ -302,32 +314,28 @@ class receiver<> : public receiver<ignoreVF, abortEF, ignoreDF> {
receiver() = default;
};
PUSHMI_CONCEPT_DEF(
template (class T)
concept ReceiverDataArg,
Receiver<T> &&
not Invocable<T&>
);
////////////////////////////////////////////////////////////////////////////////
// make_receiver
PUSHMI_INLINE_VAR constexpr struct make_receiver_fn {
inline auto operator()() const {
inline receiver<>
operator()() const {
return receiver<>{};
}
PUSHMI_TEMPLATE(class VF)
(requires PUSHMI_EXP(
lazy::True<>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<VF>)))
auto operator()(VF vf) const {
receiver<VF, abortEF, ignoreDF> operator()(VF vf) const {
return receiver<VF, abortEF, ignoreDF>{std::move(vf)};
}
template <class... EFN>
auto operator()(on_error_fn<EFN...> ef) const {
receiver<ignoreVF, on_error_fn<EFN...>, ignoreDF>
operator()(on_error_fn<EFN...> ef) const {
return receiver<ignoreVF, on_error_fn<EFN...>, ignoreDF>{std::move(ef)};
}
template <class... DFN>
auto operator()(on_done_fn<DFN...> df) const {
receiver<ignoreVF, abortEF, on_done_fn<DFN...>>
operator()(on_done_fn<DFN...> df) const {
return receiver<ignoreVF, abortEF, on_done_fn<DFN...>>{std::move(df)};
}
PUSHMI_TEMPLATE(class VF, class EF)
......@@ -336,7 +344,8 @@ PUSHMI_INLINE_VAR constexpr struct make_receiver_fn {
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND
not lazy::ReceiverDataArg<VF> PUSHMI_AND
not lazy::Invocable<EF&>)))
auto operator()(VF vf, EF ef) const {
receiver<VF, EF, ignoreDF>
operator()(VF vf, EF ef) const {
return receiver<VF, EF, ignoreDF>{std::move(vf), std::move(ef)};
}
PUSHMI_TEMPLATE(class EF, class DF)
......@@ -344,7 +353,8 @@ PUSHMI_INLINE_VAR constexpr struct make_receiver_fn {
lazy::True<> PUSHMI_AND
lazy::Invocable<DF&>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<EF>)))
auto operator()(EF ef, DF df) const {
receiver<ignoreVF, EF, DF>
operator()(EF ef, DF df) const {
return receiver<ignoreVF, EF, DF>{std::move(ef), std::move(df)};
}
PUSHMI_TEMPLATE(class VF, class EF, class DF)
......@@ -352,49 +362,56 @@ PUSHMI_INLINE_VAR constexpr struct make_receiver_fn {
lazy::True<> PUSHMI_AND
lazy::Invocable<DF&>
PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<VF>)))
auto operator()(VF vf, EF ef, DF df) const {
receiver<VF, EF, DF>
operator()(VF vf, EF ef, DF df) const {
return receiver<VF, EF, DF>{std::move(vf), std::move(ef), std::move(df)};
}
PUSHMI_TEMPLATE(class Data)
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::ReceiverDataArg<Data>))
auto operator()(Data d) const {
receiver<Data, passDVF, passDEF, passDDF>
operator()(Data d) const {
return receiver<Data, passDVF, passDEF, passDDF>{std::move(d)};
}
PUSHMI_TEMPLATE(class Data, class DVF)
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::ReceiverDataArg<Data>))
auto operator()(Data d, DVF vf) const {
receiver<Data, DVF, passDEF, passDDF>
operator()(Data d, DVF vf) const {
return receiver<Data, DVF, passDEF, passDDF>{std::move(d), std::move(vf)};
}
PUSHMI_TEMPLATE(class Data, class... DEFN)
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::ReceiverDataArg<Data>))
auto operator()(Data d, on_error_fn<DEFN...> ef) const {
receiver<Data, passDVF, on_error_fn<DEFN...>, passDDF>
operator()(Data d, on_error_fn<DEFN...> ef) const {
return receiver<Data, passDVF, on_error_fn<DEFN...>, passDDF>{std::move(d), std::move(ef)};
}
PUSHMI_TEMPLATE(class Data, class... DDFN)
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::ReceiverDataArg<Data>))
auto operator()(Data d, on_done_fn<DDFN...> df) const {
receiver<Data, passDVF, passDEF, on_done_fn<DDFN...>>
operator()(Data d, on_done_fn<DDFN...> df) const {
return receiver<Data, passDVF, passDEF, on_done_fn<DDFN...>>{std::move(d), std::move(df)};
}
PUSHMI_TEMPLATE(class Data, class DVF, class... DEFN)
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::ReceiverDataArg<Data>))
auto operator()(Data d, DVF vf, on_error_fn<DEFN...> ef) const {
receiver<Data, DVF, on_error_fn<DEFN...>, passDDF>
operator()(Data d, DVF vf, on_error_fn<DEFN...> ef) const {
return receiver<Data, DVF, on_error_fn<DEFN...>, passDDF>{std::move(d), std::move(vf), std::move(ef)};
}
PUSHMI_TEMPLATE(class Data, class DEF, class... DDFN)
(requires PUSHMI_EXP(
lazy::True<> PUSHMI_AND
lazy::ReceiverDataArg<Data>))
auto operator()(Data d, DEF ef, on_done_fn<DDFN...> df) const {
receiver<Data, passDVF, DEF, on_done_fn<DDFN...>>
operator()(Data d, DEF ef, on_done_fn<DDFN...> df) const {
return receiver<Data, passDVF, DEF, on_done_fn<DDFN...>>{std::move(d), std::move(ef), std::move(df)};
}
PUSHMI_TEMPLATE(class Data, class DVF, class DEF, class DDF)
......@@ -402,14 +419,15 @@ PUSHMI_INLINE_VAR constexpr struct make_receiver_fn {
lazy::True<> PUSHMI_AND
lazy::ReceiverDataArg<Data> PUSHMI_AND
lazy::Invocable<DDF&, Data&>))
auto operator()(Data d, DVF vf, DEF ef, DDF df) const {
receiver<Data, DVF, DEF, DDF>
operator()(Data d, DVF vf, DEF ef, DDF df) const {
return receiver<Data, DVF, DEF, DDF>{std::move(d), std::move(vf), std::move(ef), std::move(df)};
}
} const make_receiver {};
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
receiver() -> receiver<>;
PUSHMI_TEMPLATE(class VF)
......
......@@ -25,9 +25,10 @@ namespace pushmi {
template <class E, class... VN>
class any_single_sender {
using insitu_t = void*[2];
union data {
void* pobj_ = nullptr;
std::aligned_union_t<0, std::tuple<VN...>> buffer_;
std::aligned_union_t<0, insitu_t> buffer_;
} data_{};
template <class Wrapped>
static constexpr bool insitu() {
......@@ -176,9 +177,14 @@ class single_sender<Data, DSF> {
DSF sf_;
public:
using properties = property_set_insert_t<
properties_t<Data>,
property_set<is_sender<>, is_single<>>>;
using properties = properties_t<Data>;
static_assert(
Sender<Data>,
"Data must be a sender");
static_assert(
is_single_v<Data>,
"Data must be a single sender");
constexpr single_sender() = default;
constexpr explicit single_sender(Data data) : data_(std::move(data)) {}
......@@ -233,7 +239,7 @@ PUSHMI_INLINE_VAR constexpr struct make_single_sender_fn {
////////////////////////////////////////////////////////////////////////////////
// deduction guides
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
single_sender()->single_sender<ignoreSF>;
PUSHMI_TEMPLATE(class SF)
......
/*
* 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.
*/
#pragma once
namespace folly {
namespace pushmi {
// derive from this for types that need to find operator|() overloads by ADL
struct pipeorigin {};
// cardinality affects both sender and receiver
struct cardinality_category {};
// flow affects both sender and receiver
struct flow_category {};
// sender and receiver are mutually exclusive
struct receiver_category {};
struct sender_category {};
// blocking affects senders
struct blocking_category {};
// sequence affects senders
struct sequence_category {};
// trait & tag types
template <class... TN>
struct is_single;
template <>
struct is_single<> {
using property_category = cardinality_category;
};
template <class... TN>
struct is_many;
template <>
struct is_many<> {
using property_category = cardinality_category;
};
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_sender;
template <>
struct is_sender<> {
using property_category = sender_category;
};
template <class... TN>
struct is_always_blocking;
template <>
struct is_always_blocking<> {
using property_category = blocking_category;
};
template <class... TN>
struct is_never_blocking;
template <>
struct is_never_blocking<> {
using property_category = blocking_category;
};
template <class... TN>
struct is_maybe_blocking;
template <>
struct is_maybe_blocking<> {
using property_category = blocking_category;
};
template <class... TN>
struct is_fifo_sequence;
template <>
struct is_fifo_sequence<> {
using property_category = sequence_category;
};
template <class... TN>
struct is_concurrent_sequence;
template <>
struct is_concurrent_sequence<> {
using property_category = sequence_category;
};
} // namespace pushmi
} // namespace folly
......@@ -32,7 +32,7 @@ using namespace testing;
using namespace std::literals;
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
#define MAKE(x) x MAKE_
#define MAKE_(...) \
{ __VA_ARGS__ }
......
......@@ -38,7 +38,7 @@ using namespace folly::pushmi::aliases;
using namespace testing;
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
#define MAKE(x) x MAKE_
#define MAKE_(...) \
{ __VA_ARGS__ }
......
......@@ -35,7 +35,7 @@ using namespace folly::pushmi::aliases;
using namespace testing;
#if __cpp_deduction_guides >= 201703
#if __cpp_deduction_guides >= 201703 && PUSHMI_NOT_ON_WINDOWS
#define MAKE(x) x MAKE_
#define MAKE_(...) \
{ __VA_ARGS__ }
......
......@@ -15,11 +15,9 @@
*/
#pragma once
#include <functional>
#include <type_traits>
#include <folly/Traits.h>
#include <folly/experimental/pushmi/detail/functional.h>
#include <folly/experimental/pushmi/detail/concept_def.h>
#define PUSHMI_NOEXCEPT_AUTO(...) \
noexcept(noexcept(static_cast<decltype((__VA_ARGS__))>(__VA_ARGS__)))\
......@@ -75,6 +73,12 @@ PUSHMI_INLINE_VAR constexpr int sum_v = detail::sum_impl<Is...>();
template <class...>
struct typelist;
template <class T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template<class T>
PUSHMI_INLINE_VAR constexpr bool bool_v = T::value;
PUSHMI_CONCEPT_DEF(
template(class... Args)
(concept True)(Args...),
......
......@@ -118,11 +118,19 @@ class trampoline {
return owner() != nullptr;
}
template<class SingleReceiver>
struct delegate_impl {
template<class Data>
void operator()(Data& d){
using properties = property_set<is_receiver<>>;
std::decay_t<SingleReceiver> out_;
void value(){
delegator<E> that;
set_value(d, that);
set_value(out_, that);
}
void error(E e) noexcept {
set_error(out_, e);
}
void done() {
set_done(out_);
}
};
......@@ -148,7 +156,8 @@ class trampoline {
try {
if (++depth(*owner()) > 100) {
// defer work to owner
pending(*owner()).push_back(work_type{make_receiver(std::move(awhat), delegate_impl{})});
work_type work(delegate_impl<SingleReceiver>{std::move(awhat)});
pending(*owner()).push_back(std::move(work));
} else {
// dynamic recursion - optimization to balance queueing and
// stack usage and value interleaving on the same thread.
......@@ -225,7 +234,7 @@ class trampoline {
go = repeat(pending_store);
}
} else {
pending(pending_store).push_back(work_type{make_receiver(std::move(awhat), delegate_impl{})});
pending(pending_store).push_back(work_type{delegate_impl<SingleReceiver>{std::move(awhat)}});
}
if (pending(pending_store).empty()) {
......
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