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