Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/intro-5-consumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ struct expected_to_channel_t {
sender<std::remove_cvref_t<CSender>> operator()(CSender&& child_sender) const {
return {std::forward<CSender>(child_sender)};
}
auto operator()() const { return ex::detail::sender_adaptor{*this}; }
auto operator()() const { return ex::detail::make_sender_adaptor(*this); }
};
inline constexpr expected_to_channel_t expected_to_channel{};

Expand Down
4 changes: 2 additions & 2 deletions include/beman/execution/detail/affine_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import beman.execution.detail.schedule;
import beman.execution.detail.schedule_from;
import beman.execution.detail.scheduler;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.sender_for;
import beman.execution.detail.sender_has_affine_on;
Expand Down Expand Up @@ -108,7 +108,7 @@ struct affine_on_t : ::beman::execution::sender_adaptor_closure<affine_on_t> {
*
* @return A sender adaptor for the affine_on_t.
*/
auto operator()() const { return ::beman::execution::detail::sender_adaptor{*this}; }
auto operator()() const { return ::beman::execution::detail::make_sender_adaptor(*this); }

/**
* @brief affine_on is implemented by transforming it into a use of schedule_from.
Expand Down
4 changes: 2 additions & 2 deletions include/beman/execution/detail/associate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import beman.execution.detail.make_sender;
import beman.execution.detail.nothrow_callable;
import beman.execution.detail.scope_token;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.set_stopped;
import beman.execution.detail.set_value;
import beman.execution.detail.start;
Expand Down Expand Up @@ -118,7 +118,7 @@ struct associate_t {

template <::beman::execution::scope_token Token>
auto operator()(Token token) const {
return ::beman::execution::detail::sender_adaptor{*this, ::std::move(token)};
return ::beman::execution::detail::make_sender_adaptor(*this, ::std::move(token));
}

public:
Expand Down
4 changes: 2 additions & 2 deletions include/beman/execution/detail/bulk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import beman.execution.detail.meta.unique;
import beman.execution.detail.movable_value;
import beman.execution.detail.product_type;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.set_error;
import beman.execution.detail.set_value;
Expand Down Expand Up @@ -84,7 +83,8 @@ struct bulk_t : ::beman::execution::sender_adaptor_closure<bulk_t> {
template <class Shape, class f>
requires(std::is_integral_v<Shape> && ::beman::execution::detail::movable_value<f>)
auto operator()(Shape&& shape, f&& fun) const {
return beman::execution::detail::sender_adaptor{*this, std::forward<Shape>(shape), std::forward<f>(fun)};
return ::beman::execution::detail::make_sender_adaptor(
*this, std::forward<Shape>(shape), std::forward<f>(fun));
}

template <class Sender, class Shape, class f>
Expand Down
4 changes: 2 additions & 2 deletions include/beman/execution/detail/continues_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import beman.execution.detail.sched_attrs;
import beman.execution.detail.schedule_from;
import beman.execution.detail.scheduler;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.sender_for;
import beman.execution.detail.transform_sender;
#else
Expand Down Expand Up @@ -70,7 +70,7 @@ struct continues_on_t {
}
template <::beman::execution::scheduler Scheduler>
auto operator()(Scheduler&& scheduler) const {
return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Scheduler>(scheduler)};
return ::beman::execution::detail::make_sender_adaptor(*this, ::std::forward<Scheduler>(scheduler));
}
template <::beman::execution::sender Sender, ::beman::execution::scheduler Scheduler>
auto operator()(Sender&& sender, Scheduler&& scheduler) const {
Expand Down
4 changes: 2 additions & 2 deletions include/beman/execution/detail/let.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import beman.execution.detail.movable_value;
import beman.execution.detail.receiver;
import beman.execution.detail.sched_env;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.set_error;
import beman.execution.detail.set_stopped;
import beman.execution.detail.set_value;
Expand Down Expand Up @@ -99,7 +99,7 @@ template <typename Completion>
struct let_t {
template <::beman::execution::detail::movable_value Fun>
auto operator()(Fun&& fun) const {
return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Fun>(fun)};
return ::beman::execution::detail::make_sender_adaptor(*this, ::std::forward<Fun>(fun));
}
template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun>
auto operator()(Sender&& sender, Fun&& fun) const {
Expand Down
5 changes: 2 additions & 3 deletions include/beman/execution/detail/on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import beman.execution.detail.query_with_default;
import beman.execution.detail.sched_env;
import beman.execution.detail.scheduler;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.sender_for;
import beman.execution.detail.set_value;
Expand Down Expand Up @@ -157,8 +156,8 @@ struct on_t : ::beman::execution::sender_adaptor_closure<on_t> {
}
template <::beman::execution::scheduler Sch, ::beman::execution::detail::is_sender_adaptor_closure Closure>
auto operator()(Sch&& sch, Closure&& closure) const {
return ::beman::execution::detail::sender_adaptor{
*this, ::std::forward<Sch>(sch), ::std::forward<Closure>(closure)};
return ::beman::execution::detail::make_sender_adaptor(
*this, ::std::forward<Sch>(sch), ::std::forward<Closure>(closure));
}
};

Expand Down
28 changes: 7 additions & 21 deletions include/beman/execution/detail/sender_adaptor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,14 @@ import beman.execution.detail.sender_decompose;
// ----------------------------------------------------------------------------

namespace beman::execution::detail {
template <typename Adaptor, typename... T> //-dk:TODO detail export
struct sender_adaptor : ::beman::execution::detail::product_type<::std::decay_t<Adaptor>, ::std::decay_t<T>...>,
::beman::execution::sender_adaptor_closure<sender_adaptor<Adaptor, T...>> {
template <::beman::execution::sender Sender, typename Self>
static auto apply(Sender&& sender, Self&& self) {
return [&self, &sender]<::std::size_t... I>(::std::index_sequence<I...>) {
auto&& fun(self.template get<0>());
return fun(::std::forward<Sender>(sender),
::beman::execution::detail::forward_like<Self>(self.template get<I + 1>())...);
}(::std::make_index_sequence<sender_adaptor::size() - 1u>{});
}
template <::beman::execution::sender Sender>
auto operator()(Sender&& sender) {
return apply(::std::forward<Sender>(sender), ::std::move(*this));
}
template <::beman::execution::sender Sender>
auto operator()(Sender&& sender) const {
return apply(::std::forward<Sender>(sender), *this);
}
};

template <typename... T>
sender_adaptor(T&&...) -> sender_adaptor<T...>;
using sender_adaptor
[[deprecated("sender_adaptor is deprecated and layout incompatible with previous versions."
" Use make_sender_adaptor(adaptor, args...) instead. "
"The implementation now uses bound_sender_adaptor_closure, which stores the adaptor with "
"[[no_unique_address]] and keeps bound arguments in product_type.")]] =
bound_sender_adaptor_closure<std::decay_t<T>...>;
} // namespace beman::execution::detail

// ----------------------------------------------------------------------------
Expand Down
181 changes: 160 additions & 21 deletions include/beman/execution/detail/sender_adaptor_closure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,181 @@ import std;
#endif
#ifdef BEMAN_HAS_MODULES
import beman.execution.detail.sender;
import beman.execution.detail.call_result_t;
import beman.execution.detail.callable;
import beman.execution.detail.class_type;
import beman.execution.detail.nothrow_callable;
import beman.execution.detail.movable_value;
import beman.execution.detail.product_type;

#else
#include <beman/execution/detail/sender.hpp>
#include <beman/execution/detail/class_type.hpp>
#include <beman/execution/detail/call_result_t.hpp>
#include <beman/execution/detail/callable.hpp>
#include <beman/execution/detail/nothrow_callable.hpp>
#include <beman/execution/detail/movable_value.hpp>
#include <beman/execution/detail/product_type.hpp>

#endif

// ----------------------------------------------------------------------------

namespace beman::execution::detail::pipeable {
struct sender_adaptor_closure_base {};
} // namespace beman::execution::detail::pipeable

namespace beman::execution {
// NOLINTBEGIN(bugprone-crtp-constructor-accessibility)
template <typename>
struct sender_adaptor_closure : ::beman::execution::detail::pipeable::sender_adaptor_closure_base {};
// NOLINTEND(bugprone-crtp-constructor-accessibility)

/*!
* \brief CRTP base class for pipeable sender adaptor closure objects.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
*/
template <detail::class_type D>
struct sender_adaptor_closure {};

} // namespace beman::execution

namespace beman::execution::detail {
template <typename Closure>

/*!
* \brief Helper to detect a unique sender_adaptor_closure base class.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class T>
auto is_sender_adaptor_closure_base(const sender_adaptor_closure<T>&) -> T;

/*!
* \brief Checks that T has exactly one sender_adaptor_closure base where U == decay_t<T>.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class T>
concept has_unique_sender_adaptor_closure_base = requires(const T& s) {
{ is_sender_adaptor_closure_base(s) } -> std::same_as<std::decay_t<T>>;
};

/*!
* \brief Determine if a type is a pipeable sender adaptor closure.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class T>
concept is_sender_adaptor_closure =
::std::derived_from<::std::decay_t<Closure>, ::beman::execution::sender_adaptor_closure<::std::decay_t<Closure>>>;
std::derived_from<std::decay_t<T>, sender_adaptor_closure<std::decay_t<T>>> and
has_unique_sender_adaptor_closure_base<std::decay_t<T>> and (not sender<std::decay_t<T>>);

/*!
* \brief Checks that Closure is a pipeable sender adaptor closure invocable with Sender.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class Closure, class Sender>
concept sender_adaptor_closure_for =
is_sender_adaptor_closure<Closure> and sender<Sender> and requires(Closure&& closure, Sender&& sndr) {
{ std::forward<Closure>(closure)(std::forward<Sender>(sndr)) } -> sender;
};

/*!
* \brief Utility alias to copy cv-ref qualifiers from one type onto another.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class As, class Reqs>
using apply_cvref_t = decltype(std::forward_like<As>(std::declval<Reqs&>()));

/*!
* \brief Perfect forwarding call wrapper produced by closure-closure composition via operator|.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class Inner, class Outer>
struct composed_sender_adaptor_closure : sender_adaptor_closure<composed_sender_adaptor_closure<Inner, Outer>> {
[[no_unique_address]] Inner inner;
[[no_unique_address]] Outer outer;

template <class Self, sender Sender>
requires callable<apply_cvref_t<Self, Inner>, Sender> and
callable<apply_cvref_t<Self, Outer>, call_result_t<apply_cvref_t<Self, Inner>, Sender>>
constexpr auto operator()(this Self&& self, Sender&& sndr) noexcept(
nothrow_callable<apply_cvref_t<Self, Inner>, Sender> and
nothrow_callable<apply_cvref_t<Self, Outer>, call_result_t<apply_cvref_t<Self, Inner>, Sender>>)
-> call_result_t<apply_cvref_t<Self, Outer>, call_result_t<apply_cvref_t<Self, Inner>, Sender>> {
return std::forward_like<Self>(self.outer)(std::forward_like<Self>(self.inner)(std::forward<Sender>(sndr)));
}
};

// ctad
template <class Inner, class Outer>
composed_sender_adaptor_closure(Inner&&, Outer&&)
-> composed_sender_adaptor_closure<std::decay_t<Inner>, std::decay_t<Outer>>;

/*!
* \brief Perfect forwarding call wrapper produced by adaptor(args...) for multi-argument adaptors.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class Adaptor, movable_value... BoundArgs>
struct bound_sender_adaptor_closure : detail::product_type<std::decay_t<BoundArgs>...>,
sender_adaptor_closure<bound_sender_adaptor_closure<Adaptor, BoundArgs...>> {

[[no_unique_address]] Adaptor adaptor;

template <class Self, sender Sender>
requires callable<apply_cvref_t<Self, Adaptor>, Sender, apply_cvref_t<Self, BoundArgs>...>
constexpr auto operator()(this Self&& self, Sender&& sndr) noexcept(
nothrow_callable<apply_cvref_t<Self, Adaptor>, Sender, apply_cvref_t<Self, BoundArgs>...>)
-> call_result_t<apply_cvref_t<Self, Adaptor>, Sender, apply_cvref_t<Self, BoundArgs>...> {
return self.apply([&](auto&&... bound_args) {
return std::forward_like<Self>(self.adaptor)(std::forward<Sender>(sndr),
std::forward_like<Self>(bound_args)...);
});
}
};

template <class Tag, class... Args>
bound_sender_adaptor_closure(Tag&&, Args&&...)
-> bound_sender_adaptor_closure<std::decay_t<Tag>, std::decay_t<Args>...>;

/*!
* \brief Factory function producing a bound_sender_adaptor_closure from an adaptor and arguments.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
* \internal
*/
template <class Tag, class... Args>
requires(movable_value<Args> && ...)
constexpr auto
make_sender_adaptor(Tag&& tag,
Args&&... args) noexcept(std::is_nothrow_constructible_v<std::decay_t<Tag>, Tag> and
(std::is_nothrow_constructible_v<std::decay_t<Args>, Args> and ...))
-> bound_sender_adaptor_closure<std::decay_t<Tag>, std::decay_t<Args>...> {
return {{std::forward<Args>(args)...}, {}, tag};
}
} // namespace beman::execution::detail

namespace beman::execution::detail::pipeable {
template <::beman::execution::sender Sender, typename Adaptor>
requires(!::beman::execution::sender<Adaptor>) &&
::std::derived_from<::std::decay_t<Adaptor>,
::beman::execution::sender_adaptor_closure<::std::decay_t<Adaptor>>> &&
requires(Sender&& sender, Adaptor&& adaptor) {
{ adaptor(::std::forward<Sender>(sender)) } -> ::beman::execution::sender;
}
auto operator|(Sender&& sender, Adaptor&& adaptor) {
return adaptor(::std::forward<Sender>(sender));
namespace beman::execution {

/*!
* \brief Pipe operator connecting a sender to a pipeable sender adaptor closure.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
*/
template <sender Sender, detail::sender_adaptor_closure_for<Sender> Closure>
constexpr auto operator|(Sender&& sndr, Closure&& cl) noexcept(detail::nothrow_callable<Closure, Sender>)
-> detail::call_result_t<Closure, Sender> {
return std::forward<Closure>(cl)(std::forward<Sender>(sndr));
}

/*!
* \brief Pipe operator composing two pipeable sender adaptor closure objects.
* \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
*/
template <detail::is_sender_adaptor_closure Inner, detail::is_sender_adaptor_closure Outer>
requires std::constructible_from<std::decay_t<Inner>, Inner> && std::constructible_from<std::decay_t<Outer>, Outer>
constexpr auto operator|(Inner&& inner,
Outer&& outer) noexcept(std::is_nothrow_constructible_v<std::decay_t<Inner>, Inner> &&
std::is_nothrow_constructible_v<std::decay_t<Outer>, Outer>)
-> detail::composed_sender_adaptor_closure<std::decay_t<Inner>, std::decay_t<Outer>> {
return {{}, std::forward<Inner>(inner), std::forward<Outer>(outer)};
}
} // namespace beman::execution::detail::pipeable

} // namespace beman::execution

// ----------------------------------------------------------------------------

Expand Down
3 changes: 1 addition & 2 deletions include/beman/execution/detail/then.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import beman.execution.detail.meta.unique;
import beman.execution.detail.movable_value;
import beman.execution.detail.nested_sender_has_affine_on;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.set_error;
import beman.execution.detail.set_stopped;
Expand Down Expand Up @@ -108,7 +107,7 @@ template <typename Completion>
struct then_t : ::beman::execution::sender_adaptor_closure<then_t<Completion>> {
template <::beman::execution::detail::movable_value Fun>
auto operator()(Fun&& fun) const {
return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Fun>(fun)};
return ::beman::execution::detail::make_sender_adaptor(*this, std::forward<decltype(fun)>(fun));
}
template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun>
auto operator()(Sender&& sender, Fun&& fun) const {
Expand Down
2 changes: 2 additions & 0 deletions include/beman/execution/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import beman.execution.detail.schedule_from;
import beman.execution.detail.schedule;
import beman.execution.detail.scheduler;
import beman.execution.detail.scope_token;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.sender_in;
import beman.execution.detail.sender;
import beman.execution.detail.set_error;
Expand Down Expand Up @@ -92,6 +93,7 @@ import beman.execution.detail.write_env;
#include <beman/execution/detail/schedule.hpp>
#include <beman/execution/detail/scheduler.hpp>
#include <beman/execution/detail/scope_token.hpp>
#include <beman/execution/detail/sender_adaptor_closure.hpp>
#include <beman/execution/detail/sender_in.hpp>
#include <beman/execution/detail/sender.hpp>
#include <beman/execution/detail/set_error.hpp>
Expand Down
1 change: 0 additions & 1 deletion src/beman/execution/execution-detail.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export import beman.execution.detail.queryable;
export import beman.execution.detail.sched_attrs;
export import beman.execution.detail.sched_env;
export import beman.execution.detail.sender;
export import beman.execution.detail.sender_adaptor;
export import beman.execution.detail.sender_adaptor_closure;
export import beman.execution.detail.sender_decompose;
export import beman.execution.detail.sender_for;
Expand Down
Loading