Skip to content

Commit 8f573d1

Browse files
authored
Merge pull request #2079 from ahmedhussein89/main
Remove local classes in function templates
2 parents 307b83c + 42df75e commit 8f573d1

9 files changed

Lines changed: 148 additions & 51 deletions

File tree

include/stdexec/__detail/__any.hpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,27 @@ namespace STDEXEC::__any
585585

586586
//////////////////////////////////////////////////////////////////////////////////////////
587587
// __emplace_into
588+
template <class _Alloc2>
589+
struct __dealloc_guard
590+
{
591+
_Alloc2 &__alloc;
592+
typename std::allocator_traits<_Alloc2>::pointer __ptr;
593+
bool __dismissed = false;
594+
595+
constexpr void __dismiss() noexcept
596+
{
597+
__dismissed = true;
598+
}
599+
600+
constexpr ~__dealloc_guard() noexcept
601+
{
602+
if (!__dismissed)
603+
{
604+
std::allocator_traits<_Alloc2>::deallocate(__alloc, __ptr, 1);
605+
}
606+
}
607+
};
608+
588609
template <class _Model, class _Allocator, class... _Args>
589610
constexpr _Model &__emplace_into([[maybe_unused]] _Allocator const &__alloc,
590611
[[maybe_unused]] __iroot *&__root_ptr,
@@ -606,10 +627,10 @@ namespace STDEXEC::__any
606627
}
607628
else
608629
{
609-
auto __alloc2 = STDEXEC::__rebind_allocator<_Model>(__alloc);
610-
using __traits_t = std::allocator_traits<decltype(__alloc2)>;
611-
auto *const __model = __traits_t::allocate(__alloc2, 1);
612-
__scope_guard __guard{[&]() noexcept { __traits_t::deallocate(__alloc2, __model, 1); }};
630+
auto __alloc2 = STDEXEC::__rebind_allocator<_Model>(__alloc);
631+
using __traits_t = std::allocator_traits<decltype(__alloc2)>;
632+
auto *const __model = __traits_t::allocate(__alloc2, 1);
633+
__dealloc_guard<decltype(__alloc2)> __guard{__alloc2, __model};
613634
__traits_t::construct(__alloc2, __model, static_cast<_Args &&>(__args)...);
614635
__guard.__dismiss();
615636
*__std::start_lifetime_as<__tagged_ptr>(__buff.data()) = __tagged_ptr(__model);

include/stdexec/__detail/__completion_info.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,19 @@ namespace STDEXEC
126126
}
127127
}();
128128

129+
template <auto __sigs, std::size_t... _Is>
130+
consteval auto __completion_sigs_splice(__indices<_Is...>) noexcept
131+
{
132+
return completion_signatures<__msplice<__sigs[_Is]>...>();
133+
}
134+
129135
template <class _GetComplInfo>
130136
consteval auto __completion_sigs_from(_GetComplInfo) noexcept
131137
{
132138
constexpr auto __sigs = __completion_sigs_from_v<(_GetComplInfo())>;
133139
STDEXEC_IF_OK(__sigs)
134140
{
135-
constexpr auto __fn = [=]<std::size_t... _Is>(__indices<_Is...>)
136-
{
137-
return completion_signatures<__msplice<__sigs[_Is]>...>();
138-
};
139-
return __fn(__make_indices<__sigs.size()>());
141+
return __completion_sigs_splice<__sigs>(__make_indices<__sigs.size()>());
140142
}
141143
}
142144

include/stdexec/__detail/__let.hpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -598,20 +598,31 @@ namespace STDEXEC
598598
return __transform(__signature<__msplice<_Info.__signature>>, _Info);
599599
};
600600

601-
//! @tparam _Info A `__static_vector` of `__completion_info` objects representing
602-
//! the completions of the predecessor sender.
603-
template <auto _Info, auto _Transform>
604-
static constexpr auto __get_cmpl_info_i = []<std::size_t... _Is>(__indices<_Is...>)
601+
template <auto _Info, auto _Transform, std::size_t... _Is>
602+
struct __cmpl_info_inner_fn
605603
{
606-
return []
604+
constexpr auto operator()() const
607605
{
608606
__static_vector<__completion_info, 0> __result;
609-
// NB: this fold uses an overloaded addition operator that propagates
610-
// __mexception objects when constexpr exceptions are not available.
611607
return (__maybe_transform_cmplsig<_Info[_Is]>(_Transform) + ... + __result);
612-
};
608+
}
613609
};
614610

611+
template <auto _Info, auto _Transform>
612+
struct __cmpl_info_outer_fn
613+
{
614+
template <std::size_t... _Is>
615+
constexpr auto operator()(__indices<_Is...>) const
616+
{
617+
return __cmpl_info_inner_fn<_Info, _Transform, _Is...>{};
618+
}
619+
};
620+
621+
//! @tparam _Info A `__static_vector` of `__completion_info` objects representing
622+
//! the completions of the predecessor sender.
623+
template <auto _Info, auto _Transform>
624+
static constexpr auto __get_cmpl_info_i = __cmpl_info_outer_fn<_Info, _Transform>{};
625+
615626
template <class _Fun, class _Child, class... _Env>
616627
struct __get_cmpl_info
617628
{

include/stdexec/__detail/__memory.hpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,24 @@ namespace STDEXEC
9494
/////////////////////////////////////////////////////////////////////////////////////////
9595
// __allocator_aware_forward: https://eel.is/c++draft/exec#snd.expos-49
9696
template <class _Alloc>
97-
[[nodiscard]]
98-
constexpr auto __mk_obj_using_alloc_fn(_Alloc const &__alloc) noexcept
97+
struct __obj_using_alloc_fn
9998
{
100-
return [&__alloc]<class... _Args>(_Args &&...__args)
99+
_Alloc const &__alloc_;
100+
101+
template <class... _Args>
102+
constexpr auto operator()([[maybe_unused]] _Args &&...__args) const
101103
{
102104
return __tuple{
103-
std::make_obj_using_allocator<__decay_t<_Args>>(__alloc, static_cast<_Args &&>(__args))...};
104-
};
105+
std::make_obj_using_allocator<__decay_t<_Args>>(__alloc_,
106+
static_cast<_Args &&>(__args))...};
107+
}
108+
};
109+
110+
template <class _Alloc>
111+
[[nodiscard]]
112+
constexpr auto __mk_obj_using_alloc_fn(_Alloc const &__alloc) noexcept
113+
{
114+
return __obj_using_alloc_fn<_Alloc>{__alloc};
105115
}
106116

107117
template <class _Ty, class _Context>

include/stdexec/__detail/__parallel_scheduler.hpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,19 @@ namespace STDEXEC
656656
return {__sched_};
657657
}
658658

659+
template <class _Op>
660+
struct __connect_fn
661+
{
662+
_Previous __previous;
663+
__detail::__backend_ptr_t __sched;
664+
665+
auto operator()(_Op& __op) && noexcept
666+
{
667+
using __receiver_t = _Op::__intermediate_receiver_t;
668+
return STDEXEC::connect(std::move(__previous), __receiver_t{__op, std::move(__sched)});
669+
}
670+
};
671+
659672
/// Connects `__self` to `__rcvr`, returning the operation state containing the work to be done.
660673
template <receiver _Rcvr>
661674
auto connect(_Rcvr __rcvr) && noexcept(__nothrow_move_constructible<_Rcvr>)
@@ -664,14 +677,11 @@ namespace STDEXEC
664677
using __res_t =
665678
__detail::__system_bulk_op<_IsUnchunked, _Previous, _Size, _Fn, _Rcvr, _Parallelize>;
666679
using __receiver_t = __res_t::__intermediate_receiver_t;
667-
return {std::move(*this),
668-
std::move(__rcvr),
669-
[this](auto& __op)
670-
{
671-
// Connect bulk input receiver with the previous operation and store in the operating state.
672-
return STDEXEC::connect(std::move(this->__previous_),
673-
__receiver_t{__op, std::move(this->__sched_)});
674-
}};
680+
return {
681+
std::move(*this),
682+
std::move(__rcvr),
683+
__connect_fn<__res_t>{std::move(__previous_), std::move(__sched_)}
684+
};
675685
}
676686

677687
/// Gets the completion signatures for this sender.

include/stdexec/__detail/__receivers.hpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,21 @@ namespace STDEXEC
457457
}
458458

459459
template <class _Tag, class _Receiver>
460-
constexpr auto __mk_completion_fn(_Tag, _Receiver &__rcvr) noexcept
460+
struct __completion_fn
461461
{
462-
return [&]<class... _Args>(_Args &&...__args) noexcept
462+
_Receiver &__rcvr_;
463+
464+
template <class... _Args>
465+
constexpr void operator()(_Args &&...__args) const noexcept
463466
{
464-
_Tag()(static_cast<_Receiver &&>(__rcvr), static_cast<_Args &&>(__args)...);
465-
};
467+
_Tag()(static_cast<_Receiver &&>(__rcvr_), static_cast<_Args &&>(__args)...);
468+
}
469+
};
470+
471+
template <class _Tag, class _Receiver>
472+
constexpr auto __mk_completion_fn(_Tag, _Receiver &__rcvr) noexcept
473+
{
474+
return __completion_fn<_Tag, _Receiver>{__rcvr};
466475
}
467476

468477
// Used to test whether a sender has a nothrow connect to a receiver whose environment

include/stdexec/__detail/__tuple.hpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -453,15 +453,27 @@ namespace STDEXEC
453453
//
454454
namespace __tup
455455
{
456+
template <class _Fn, class _Tuple>
457+
struct __apply_partial_t
458+
{
459+
_Tuple&& __tup;
460+
_Fn __fn;
461+
462+
template <class... _Us>
463+
STDEXEC_ATTRIBUTE(host, device, always_inline)
464+
constexpr auto operator()(_Us&&... __us) noexcept(__nothrow_applicable<_Fn, _Tuple, _Us...>)
465+
-> __apply_result_t<_Fn, _Tuple, _Us...>
466+
{
467+
return STDEXEC::__apply(__fn, static_cast<_Tuple&&>(__tup), static_cast<_Us&&>(__us)...);
468+
}
469+
};
470+
456471
template <__is_tuple _Tuple, class _Fn>
457472
STDEXEC_ATTRIBUTE(host, device, always_inline)
458473
constexpr auto operator%(_Tuple&& __tup, _Fn __fn) noexcept(__nothrow_move_constructible<_Fn>)
474+
-> __apply_partial_t<_Fn, _Tuple>
459475
{
460-
return [&__tup, __fn = static_cast<_Fn&&>(__fn)]<class... _Us>(_Us&&... __us) noexcept(
461-
__nothrow_applicable<_Fn, _Tuple, _Us...>) -> __apply_result_t<_Fn, _Tuple, _Us...>
462-
{
463-
return STDEXEC::__apply(__fn, static_cast<_Tuple&&>(__tup), static_cast<_Us&&>(__us)...);
464-
};
476+
return __apply_partial_t<_Fn, _Tuple>{static_cast<_Tuple&&>(__tup), static_cast<_Fn&&>(__fn)};
465477
}
466478

467479
struct __cat_apply_t

include/stdexec/__detail/__variant.hpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,27 @@ namespace STDEXEC
298298
return *std::launder(__ptr);
299299
}
300300

301+
template <class _Fn, class... _As>
302+
struct __emplace_from_fn
303+
{
304+
_Fn &__fn_;
305+
std::tuple<_As &...> __as_;
306+
307+
static constexpr bool __is_nothrow = __nothrow_callable<_Fn, _As...>;
308+
309+
template <std::size_t... _Size>
310+
constexpr auto
311+
__call(std::index_sequence<_Size...>) const noexcept(__is_nothrow) -> decltype(auto)
312+
{
313+
return static_cast<_Fn &&>(__fn_)(static_cast<_As &&>(std::get<_Size>(__as_))...);
314+
}
315+
316+
constexpr auto operator()() const noexcept(__is_nothrow) -> decltype(auto)
317+
{
318+
return __call(std::index_sequence_for<_As...>{});
319+
}
320+
};
321+
301322
template <std::size_t _Ny, class _Fn, class... _As>
302323
STDEXEC_ATTRIBUTE(host, device)
303324
constexpr auto __emplace_from(_Fn &&__fn, _As &&...__as)
@@ -314,9 +335,7 @@ namespace STDEXEC
314335
{
315336
auto *__ptr = std::construct_at<__value_t>(
316337
static_cast<__value_t *>(__data()),
317-
STDEXEC::__emplace_from(
318-
[&]() noexcept(__is_nothrow) -> decltype(auto)
319-
{ return static_cast<_Fn &&>(__fn)(static_cast<_As &&>(__as)...); }));
338+
STDEXEC::__emplace_from(__emplace_from_fn<_Fn, _As...>{__fn, {__as...}}));
320339
__sg.__dismiss();
321340
return *std::launder(__ptr);
322341
}

include/stdexec/coroutine.hpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ namespace STDEXEC
8888
public:
8989
constexpr __coroutine_handle() = default;
9090

91+
template <class _Promise>
92+
static constexpr auto __stopped_callback(void* __address) noexcept -> __std::coroutine_handle<>
93+
{
94+
// This causes the rest of the coroutine (the part after the co_await
95+
// of the sender) to be skipped and invokes the calling coroutine's
96+
// stopped handler.
97+
return __std::coroutine_handle<_Promise>::from_address(__address)
98+
.promise()
99+
.unhandled_stopped();
100+
}
101+
91102
template <class _Promise>
92103
constexpr __coroutine_handle(__std::coroutine_handle<_Promise> __coro) noexcept
93104
: __std::coroutine_handle<>(__coro)
@@ -98,15 +109,7 @@ namespace STDEXEC
98109

99110
if constexpr (__has_unhandled_stopped)
100111
{
101-
__stopped_callback_ = [](void* __address) noexcept -> __std::coroutine_handle<>
102-
{
103-
// This causes the rest of the coroutine (the part after the co_await
104-
// of the sender) to be skipped and invokes the calling coroutine's
105-
// stopped handler.
106-
return __std::coroutine_handle<_Promise>::from_address(__address)
107-
.promise()
108-
.unhandled_stopped();
109-
};
112+
__stopped_callback_ = &__stopped_callback<_Promise>;
110113
}
111114
// If _Promise doesn't implement unhandled_stopped(), then if a "stopped" unwind
112115
// reaches this point, it's considered an unhandled exception and terminate()

0 commit comments

Comments
 (0)