Skip to content

make __tuple and env constexpr #1575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 19, 2025
Merged
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
27 changes: 13 additions & 14 deletions include/exec/env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ namespace exec {
namespace __envs {
struct __with_t {
template <class _Tag, class _Value>
auto operator()(_Tag, _Value&& __val) const {
constexpr auto operator()(_Tag, _Value&& __val) const {
return stdexec::prop{_Tag(), static_cast<_Value&&>(__val)};
}
};

struct __without_t {
template <class _Env, class _Tag>
auto operator()(_Env&& __env, _Tag) const -> decltype(auto) {
constexpr auto operator()(_Env&& __env, _Tag) const -> decltype(auto) {
return stdexec::__env::__without(static_cast<_Env&&>(__env), _Tag());
}
};
Expand All @@ -46,13 +46,13 @@ namespace exec {
stdexec::__nothrow_move_constructible _Base,
stdexec::__nothrow_move_constructible _Env
>
auto operator()(_Base&& __base, _Env&& __env) const noexcept
constexpr auto operator()(_Base&& __base, _Env&& __env) const noexcept
-> stdexec::__join_env_t<_Env, _Base> {
return stdexec::__env::__join(static_cast<_Env&&>(__env), static_cast<_Base&&>(__base));
}

template <stdexec::__nothrow_move_constructible _Env>
auto operator()(_Env&& __env) const noexcept -> _Env {
constexpr auto operator()(_Env&& __env) const noexcept -> _Env {
return static_cast<_Env&&>(__env);
}
};
Expand Down Expand Up @@ -81,7 +81,7 @@ namespace exec {
STDEXEC_ATTRIBUTE(no_unique_address) _Default __default_;
_Receiver __rcvr_;

void start() & noexcept {
constexpr void start() & noexcept {
STDEXEC_TRY {
if constexpr (__callable<_Tag, env_of_t<_Receiver>>) {
const auto& __env = get_env(__rcvr_);
Expand All @@ -91,7 +91,6 @@ namespace exec {
}
}
STDEXEC_CATCH_ALL {

stdexec::set_error(std::move(__rcvr_), std::current_exception());
}
}
Expand Down Expand Up @@ -120,14 +119,14 @@ namespace exec {

template <__decays_to<__sender> _Self, class _Receiver>
requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>>
static auto connect(_Self&& __self, _Receiver __rcvr)
static constexpr auto connect(_Self&& __self, _Receiver __rcvr)
noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
-> __operation_t<_Tag, __default_t<env_of_t<_Receiver>>, _Receiver> {
return {{}, static_cast<_Self&&>(__self).__default_, static_cast<_Receiver&&>(__rcvr)};
}

template <class _Env>
auto get_completion_signatures(_Env&&) -> __completions_t<_Env> {
constexpr auto get_completion_signatures(_Env&&) -> __completions_t<_Env> {
return {};
}
};
Expand Down Expand Up @@ -160,19 +159,19 @@ namespace exec {
_Sender __sndr_;
_Attrs __attrs_;

auto get_env() const noexcept -> __join_env_t<const _Attrs&, env_of_t<_Sender>> {
constexpr auto get_env() const noexcept -> __join_env_t<const _Attrs&, env_of_t<_Sender>> {
return stdexec::__env::__join(__attrs_, stdexec::get_env(__sndr_));
}

template <__decays_to<__t> _Self, class... _Env>
static auto get_completion_signatures(_Self&&, _Env&&...)
static constexpr auto get_completion_signatures(_Self&&, _Env&&...)
-> completion_signatures_of_t<__copy_cvref_t<_Self, _Sender>, _Env...> {
return {};
}

template <__decays_to<__t> _Self, class _Receiver>
requires sender_in<__copy_cvref_t<_Self, _Sender>, env_of_t<_Receiver>>
static auto connect(_Self&& __self, _Receiver __rcvr)
static constexpr auto connect(_Self&& __self, _Receiver __rcvr)
-> connect_result_t<__copy_cvref_t<_Self, _Sender>, _Receiver> {
return stdexec::connect(std::forward<_Self>(__self).__sndr_, std::move(__rcvr));
}
Expand All @@ -182,7 +181,7 @@ namespace exec {
struct __write_attrs_t {
template <class _Sender, class _Attrs>
STDEXEC_ATTRIBUTE(host, device)
auto
constexpr auto
operator()(_Sender snd, _Attrs __attrs_) const -> __write_attrs::__sender<_Sender, _Attrs> {
return __t<__write_attrs::__sender<__id<_Sender>, _Attrs>>{
static_cast<_Sender&&>(snd), static_cast<_Attrs&&>(__attrs_)};
Expand All @@ -194,15 +193,15 @@ namespace exec {

template <class _Sender>
STDEXEC_ATTRIBUTE(host, device)
friend auto operator|(_Sender __sndr_, __closure _clsr) {
friend constexpr auto operator|(_Sender __sndr_, __closure _clsr) {
return __t<__write_attrs::__sender<__id<_Sender>, _Attrs>>{
static_cast<_Sender&&>(__sndr_), static_cast<_Attrs&&>(_clsr.__attrs_)};
}
};

template <class _Attrs>
STDEXEC_ATTRIBUTE(host, device)
auto operator()(_Attrs __attrs_) const {
constexpr auto operator()(_Attrs __attrs_) const {
return __closure<_Attrs>{static_cast<_Attrs&&>(__attrs_)};
}
};
Expand Down
12 changes: 12 additions & 0 deletions include/stdexec/__detail/__env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "__tag_invoke.hpp"
#include "__tuple.hpp"

#include <exception> // IWYU pragma: keep for std::terminate
#include <functional> // IWYU pragma: keep for unwrap_reference_t
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -363,12 +364,23 @@ namespace stdexec {
template <class _Env, class _Query, class... _Args>
using __query_result_t = tag_invoke_result_t<_Query, const _Env&, _Args...>;

template <class ValueType>
struct __prop_like {
template <class _Query>
STDEXEC_ATTRIBUTE(nodiscard)
constexpr auto query(_Query) const noexcept -> const ValueType& {
STDEXEC_TERMINATE();
}
};

// A singleton environment from a query/value pair
template <class _Query, class _Value>
struct prop {
using __t = prop;
using __id = prop;

static_assert(__callable<_Query, __prop_like<_Value>>);

STDEXEC_ATTRIBUTE(no_unique_address) _Query __query;

STDEXEC_ATTRIBUTE(no_unique_address) _Value __value;
Expand Down
2 changes: 1 addition & 1 deletion include/stdexec/__detail/__execution_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
#pragma once

#include "__config.hpp"
#include "__config.hpp" // IWYU pragma: export
#include "__meta.hpp"
#include "__concepts.hpp"
#include "__type_traits.hpp"
Expand Down
24 changes: 12 additions & 12 deletions include/stdexec/__detail/__tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,33 +87,33 @@ namespace stdexec {
requires(sizeof...(_Ts) - 1 > 3) // intentional unsigned wrap-around for sizeof...(Ts) is zero
struct __tuple<_Idx, _Ts...> : __box<_Ts, _Is>... {
template <class... _Us>
static auto __convert_from(__tuple<_Idx, _Us...> &&__tup) -> __tuple {
static constexpr auto __convert_from(__tuple<_Idx, _Us...> &&__tup) -> __tuple {
return __tuple{
{static_cast<_Us &&>(__tup.STDEXEC_CWG1835_TEMPLATE __box<_Us, _Is>::__value)}...};
}

template <class... _Us>
static auto __convert_from(__tuple<_Idx, _Us...> const &__tup) -> __tuple {
static constexpr auto __convert_from(__tuple<_Idx, _Us...> const &__tup) -> __tuple {
return __tuple{{__tup.STDEXEC_CWG1835_TEMPLATE __box<_Us, _Is>::__value}...};
}

template <std::size_t _Np, class _Self>
STDEXEC_ATTRIBUTE(host, device, always_inline)
static auto __get(_Self &&__self) noexcept
static constexpr auto __get(_Self &&__self) noexcept
-> decltype(__tup::__get<_Np>(static_cast<_Self &&>(__self))) {
return __tup::__get<_Np>(static_cast<_Self &&>(__self));
}

// clang-format off
template <class _Fn, class _Self, class... _Us>
STDEXEC_ATTRIBUTE(host, device, always_inline) static auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us)
STDEXEC_ATTRIBUTE(host, device, always_inline) static constexpr auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us)
STDEXEC_AUTO_RETURN(
static_cast<_Fn &&>(__fn)(
static_cast<_Us &&>(__us)...,
static_cast<_Self &&>(__self).STDEXEC_CWG1835_TEMPLATE __box<_Ts, _Is>::__value...))

template <class _Fn, class _Self, class... _Us>
STDEXEC_ATTRIBUTE(host, device, always_inline) static auto for_each(_Fn &&__fn, _Self &&__self)
STDEXEC_ATTRIBUTE(host, device, always_inline) static constexpr auto for_each(_Fn &&__fn, _Self &&__self)
STDEXEC_AUTO_RETURN(
(static_cast<void>(
__fn(static_cast<_Self &&>(__self).STDEXEC_CWG1835_TEMPLATE __box<_Ts, _Is>::__value)),
Expand Down Expand Up @@ -145,34 +145,34 @@ namespace stdexec {
STDEXEC_REPEAT(_N, STDEXEC_TUPLE_ELEM_DEFN) \
\
template <STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_DEFN))> \
static auto __convert_from(__tuple<_Idx STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_USE)> &&__tup) \
static constexpr auto __convert_from(__tuple<_Idx STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_USE)> &&__tup) \
-> __tuple { \
return __tuple{ \
STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TUPLE_OTHER_ELEM_RVALUE))}; \
} \
\
template <STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_DEFN))> \
static auto __convert_from( \
static constexpr auto __convert_from( \
__tuple<_Idx STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_USE)> const &__tup) -> __tuple { \
return __tuple{ \
STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TUPLE_OTHER_ELEM_LVALUE))}; \
} \
\
template <std::size_t _Np, class _Self> \
STDEXEC_ATTRIBUTE(host, device, always_inline) \
static auto __get(_Self &&__self) noexcept -> decltype(auto) requires(_Np < _N) { \
static constexpr auto __get(_Self &&__self) noexcept -> decltype(auto) requires(_Np < _N) { \
STDEXEC_REPEAT(_N, STDEXEC_TUPLE_GET_ELEM); \
} \
\
template <class _Fn, class _Self, class... _Us> \
STDEXEC_ATTRIBUTE(host, device, always_inline) \
static auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us) STDEXEC_AUTO_RETURN( \
static constexpr auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us) STDEXEC_AUTO_RETURN( \
static_cast<_Fn &&>(__fn)(static_cast<_Us &&>(__us)... \
STDEXEC_REPEAT(_N, STDEXEC_TUPLE_ELEM_USE))) \
\
template <class _Fn, class _Self> \
STDEXEC_ATTRIBUTE(host, device, always_inline) \
static auto for_each(_Fn &&__fn, _Self &&__self) STDEXEC_AUTO_RETURN( \
static constexpr auto for_each(_Fn &&__fn, _Self &&__self) STDEXEC_AUTO_RETURN( \
STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TUPLE_FOR_EACH_ELEM))) \
};
// clang-format on
Expand Down Expand Up @@ -209,15 +209,15 @@ namespace stdexec {

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

template <class _Fn, class... _Tuples>
auto __cat_apply(_Fn __fn, _Tuples &&...__tups)
constexpr auto __cat_apply(_Fn __fn, _Tuples &&...__tups)
STDEXEC_AUTO_RETURN((static_cast<_Tuples &&>(__tups) << ... << __fn)())

STDEXEC_PRAGMA_PUSH() STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
Expand Down
Loading