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
29 changes: 25 additions & 4 deletions include/stdexec/__detail/__any.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,27 @@ namespace STDEXEC::__any

//////////////////////////////////////////////////////////////////////////////////////////
// __emplace_into
template <class _Alloc2>
struct __dealloc_guard
{
_Alloc2 &__alloc;
typename std::allocator_traits<_Alloc2>::pointer __ptr;
bool __dismissed = false;

constexpr void __dismiss() noexcept
{
__dismissed = true;
}

constexpr ~__dealloc_guard() noexcept
{
if (!__dismissed)
{
std::allocator_traits<_Alloc2>::deallocate(__alloc, __ptr, 1);
}
}
};

template <class _Model, class _Allocator, class... _Args>
constexpr _Model &__emplace_into([[maybe_unused]] _Allocator const &__alloc,
[[maybe_unused]] __iroot *&__root_ptr,
Expand All @@ -606,10 +627,10 @@ namespace STDEXEC::__any
}
else
{
auto __alloc2 = STDEXEC::__rebind_allocator<_Model>(__alloc);
using __traits_t = std::allocator_traits<decltype(__alloc2)>;
auto *const __model = __traits_t::allocate(__alloc2, 1);
__scope_guard __guard{[&]() noexcept { __traits_t::deallocate(__alloc2, __model, 1); }};
auto __alloc2 = STDEXEC::__rebind_allocator<_Model>(__alloc);
using __traits_t = std::allocator_traits<decltype(__alloc2)>;
auto *const __model = __traits_t::allocate(__alloc2, 1);
__dealloc_guard<decltype(__alloc2)> __guard{__alloc2, __model};
__traits_t::construct(__alloc2, __model, static_cast<_Args &&>(__args)...);
__guard.__dismiss();
*__std::start_lifetime_as<__tagged_ptr>(__buff.data()) = __tagged_ptr(__model);
Expand Down
14 changes: 8 additions & 6 deletions include/stdexec/__detail/__completion_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace STDEXEC
, __signature(__mtypeid<_Tag(_Args...)>)
, __domain(__domain)
, __behavior(__behavior)
{}
{ }

template <class _Sender, class... _Env>
constexpr auto __populate() noexcept -> __completion_info &
Expand Down Expand Up @@ -126,17 +126,19 @@ namespace STDEXEC
}
}();

template <auto __sigs, std::size_t... _Is>
consteval auto __completion_sigs_splice(__indices<_Is...>) noexcept
{
return completion_signatures<__msplice<__sigs[_Is]>...>();
}

template <class _GetComplInfo>
consteval auto __completion_sigs_from(_GetComplInfo) noexcept
{
constexpr auto __sigs = __completion_sigs_from_v<(_GetComplInfo())>;
STDEXEC_IF_OK(__sigs)
{
constexpr auto __fn = [=]<std::size_t... _Is>(__indices<_Is...>)
{
return completion_signatures<__msplice<__sigs[_Is]>...>();
};
return __fn(__make_indices<__sigs.size()>());
return __completion_sigs_splice<__sigs>(__make_indices<__sigs.size()>());
}
}

Expand Down
27 changes: 19 additions & 8 deletions include/stdexec/__detail/__let.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,20 +598,31 @@ namespace STDEXEC
return __transform(__signature<__msplice<_Info.__signature>>, _Info);
};

//! @tparam _Info A `__static_vector` of `__completion_info` objects representing
//! the completions of the predecessor sender.
template <auto _Info, auto _Transform>
static constexpr auto __get_cmpl_info_i = []<std::size_t... _Is>(__indices<_Is...>)
template <auto _Info, auto _Transform, std::size_t... _Is>
struct __cmpl_info_inner_fn
{
return []
constexpr auto operator()() const
{
__static_vector<__completion_info, 0> __result;
// NB: this fold uses an overloaded addition operator that propagates
// __mexception objects when constexpr exceptions are not available.
return (__maybe_transform_cmplsig<_Info[_Is]>(_Transform) + ... + __result);
};
}
};

template <auto _Info, auto _Transform>
struct __cmpl_info_outer_fn
{
template <std::size_t... _Is>
constexpr auto operator()(__indices<_Is...>) const
{
return __cmpl_info_inner_fn<_Info, _Transform, _Is...>{};
}
};

//! @tparam _Info A `__static_vector` of `__completion_info` objects representing
//! the completions of the predecessor sender.
template <auto _Info, auto _Transform>
static constexpr auto __get_cmpl_info_i = __cmpl_info_outer_fn<_Info, _Transform>{};

template <class _Fun, class _Child, class... _Env>
struct __get_cmpl_info
{
Expand Down
20 changes: 15 additions & 5 deletions include/stdexec/__detail/__memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,24 @@ namespace STDEXEC
/////////////////////////////////////////////////////////////////////////////////////////
// __allocator_aware_forward: https://eel.is/c++draft/exec#snd.expos-49
template <class _Alloc>
[[nodiscard]]
constexpr auto __mk_obj_using_alloc_fn(_Alloc const &__alloc) noexcept
struct __obj_using_alloc_fn
{
return [&__alloc]<class... _Args>(_Args &&...__args)
_Alloc const &__alloc_;

template <class... _Args>
constexpr auto operator()([[maybe_unused]] _Args &&...__args) const
{
return __tuple{
std::make_obj_using_allocator<__decay_t<_Args>>(__alloc, static_cast<_Args &&>(__args))...};
};
std::make_obj_using_allocator<__decay_t<_Args>>(__alloc_,
static_cast<_Args &&>(__args))...};
}
};

template <class _Alloc>
[[nodiscard]]
constexpr auto __mk_obj_using_alloc_fn(_Alloc const &__alloc) noexcept
{
return __obj_using_alloc_fn<_Alloc>{__alloc};
}

template <class _Ty, class _Context>
Expand Down
26 changes: 18 additions & 8 deletions include/stdexec/__detail/__parallel_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,19 @@ namespace STDEXEC
return {__sched_};
}

template <class _Op>
struct __connect_fn
{
_Previous __previous;
__detail::__backend_ptr_t __sched;

auto operator()(_Op& __op) && noexcept
{
using __receiver_t = _Op::__intermediate_receiver_t;
return STDEXEC::connect(std::move(__previous), __receiver_t{__op, std::move(__sched)});
}
};

/// Connects `__self` to `__rcvr`, returning the operation state containing the work to be done.
template <receiver _Rcvr>
auto connect(_Rcvr __rcvr) && noexcept(__nothrow_move_constructible<_Rcvr>)
Expand All @@ -664,14 +677,11 @@ namespace STDEXEC
using __res_t =
__detail::__system_bulk_op<_IsUnchunked, _Previous, _Size, _Fn, _Rcvr, _Parallelize>;
using __receiver_t = __res_t::__intermediate_receiver_t;
return {std::move(*this),
std::move(__rcvr),
[this](auto& __op)
{
// Connect bulk input receiver with the previous operation and store in the operating state.
return STDEXEC::connect(std::move(this->__previous_),
__receiver_t{__op, std::move(this->__sched_)});
}};
return {
std::move(*this),
std::move(__rcvr),
__connect_fn<__res_t>{std::move(__previous_), std::move(__sched_)}
};
}

/// Gets the completion signatures for this sender.
Expand Down
25 changes: 17 additions & 8 deletions include/stdexec/__detail/__receivers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ namespace STDEXEC
&& __std::constructible_from<__decay_t<_Receiver>, _Receiver>;

struct _THE_RECEIVER_DOES_NOT_ACCEPT_ALL_OF_THE_SENDERS_COMPLETION_SIGNALS_
{};
{ };

namespace __detail
{
Expand Down Expand Up @@ -457,12 +457,21 @@ namespace STDEXEC
}

template <class _Tag, class _Receiver>
constexpr auto __mk_completion_fn(_Tag, _Receiver &__rcvr) noexcept
struct __completion_fn
{
return [&]<class... _Args>(_Args &&...__args) noexcept
_Receiver &__rcvr_;

template <class... _Args>
constexpr void operator()(_Args &&...__args) const noexcept
{
_Tag()(static_cast<_Receiver &&>(__rcvr), static_cast<_Args &&>(__args)...);
};
_Tag()(static_cast<_Receiver &&>(__rcvr_), static_cast<_Args &&>(__args)...);
}
};

template <class _Tag, class _Receiver>
constexpr auto __mk_completion_fn(_Tag, _Receiver &__rcvr) noexcept
{
return __completion_fn<_Tag, _Receiver>{__rcvr};
}

// Used to test whether a sender has a nothrow connect to a receiver whose environment
Expand All @@ -475,15 +484,15 @@ namespace STDEXEC
template <class... _Args>
STDEXEC_ATTRIBUTE(host, device)
constexpr void set_value(_Args &&...) noexcept
{}
{ }

template <class _Error>
STDEXEC_ATTRIBUTE(host, device)
constexpr void set_error(_Error &&) noexcept
{}
{ }

STDEXEC_ATTRIBUTE(host, device)
constexpr void set_stopped() noexcept {}
constexpr void set_stopped() noexcept { }
};

template <class _Env>
Expand Down
24 changes: 18 additions & 6 deletions include/stdexec/__detail/__tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ namespace STDEXEC

template <class... _Ts>
struct __tuple : __tup::__tupl_base<__make_indices<sizeof...(_Ts)>, _Ts...>
{};
{ };

template <>
struct __tuple<>
Expand Down Expand Up @@ -453,15 +453,27 @@ namespace STDEXEC
//
namespace __tup
{
template <class _Fn, class _Tuple>
struct __apply_partial_t
{
_Tuple&& __tup;
_Fn __fn;

template <class... _Us>
STDEXEC_ATTRIBUTE(host, device, always_inline)
constexpr auto operator()(_Us&&... __us) noexcept(__nothrow_applicable<_Fn, _Tuple, _Us...>)
-> __apply_result_t<_Fn, _Tuple, _Us...>
{
return STDEXEC::__apply(__fn, static_cast<_Tuple&&>(__tup), static_cast<_Us&&>(__us)...);
}
};

template <__is_tuple _Tuple, class _Fn>
STDEXEC_ATTRIBUTE(host, device, always_inline)
constexpr auto operator%(_Tuple&& __tup, _Fn __fn) noexcept(__nothrow_move_constructible<_Fn>)
-> __apply_partial_t<_Fn, _Tuple>
{
return [&__tup, __fn = static_cast<_Fn&&>(__fn)]<class... _Us>(_Us&&... __us) noexcept(
__nothrow_applicable<_Fn, _Tuple, _Us...>) -> __apply_result_t<_Fn, _Tuple, _Us...>
{
return STDEXEC::__apply(__fn, static_cast<_Tuple&&>(__tup), static_cast<_Us&&>(__us)...);
};
return __apply_partial_t<_Fn, _Tuple>{static_cast<_Tuple&&>(__tup), static_cast<_Fn&&>(__fn)};
}

struct __cat_apply_t
Expand Down
31 changes: 25 additions & 6 deletions include/stdexec/__detail/__variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace STDEXEC
#endif

struct __monostate
{};
{ };

struct __visit_t
{
Expand Down Expand Up @@ -102,7 +102,7 @@ namespace STDEXEC
{
public:
STDEXEC_ATTRIBUTE(host, device)
constexpr __variant(__no_init_t) noexcept {}
constexpr __variant(__no_init_t) noexcept { }

template <class _Fn, class... _Us>
STDEXEC_ATTRIBUTE(host, device)
Expand Down Expand Up @@ -169,7 +169,7 @@ namespace STDEXEC

// Construct into the valueless state:
STDEXEC_ATTRIBUTE(host, device)
constexpr explicit __variant(__no_init_t) noexcept {}
constexpr explicit __variant(__no_init_t) noexcept { }

STDEXEC_ATTRIBUTE(host, device)
constexpr __variant(__variant &&__other) noexcept(__nothrow_move_constructible<_Ts...>)
Expand Down Expand Up @@ -298,6 +298,27 @@ namespace STDEXEC
return *std::launder(__ptr);
}

template <class _Fn, class... _As>
struct __emplace_from_fn
{
_Fn &__fn_;
std::tuple<_As &...> __as_;

static constexpr bool __is_nothrow = __nothrow_callable<_Fn, _As...>;

template <std::size_t... _Size>
constexpr auto
__call(std::index_sequence<_Size...>) const noexcept(__is_nothrow) -> decltype(auto)
{
return static_cast<_Fn &&>(__fn_)(static_cast<_As &&>(std::get<_Size>(__as_))...);
}

constexpr auto operator()() const noexcept(__is_nothrow) -> decltype(auto)
{
return __call(std::index_sequence_for<_As...>{});
}
};

template <std::size_t _Ny, class _Fn, class... _As>
STDEXEC_ATTRIBUTE(host, device)
constexpr auto __emplace_from(_Fn &&__fn, _As &&...__as)
Expand All @@ -314,9 +335,7 @@ namespace STDEXEC
{
auto *__ptr = std::construct_at<__value_t>(
static_cast<__value_t *>(__data()),
STDEXEC::__emplace_from(
[&]() noexcept(__is_nothrow) -> decltype(auto)
{ return static_cast<_Fn &&>(__fn)(static_cast<_As &&>(__as)...); }));
STDEXEC::__emplace_from(__emplace_from_fn<_Fn, _As...>{__fn, {__as...}}));
__sg.__dismiss();
return *std::launder(__ptr);
}
Expand Down
Loading