Skip to content
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
24 changes: 19 additions & 5 deletions include/stdexec/__detail/__affine_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,14 @@ namespace STDEXEC

namespace __affine_on
{
template <class _Attrs>
template <class _Sender>
struct __attrs
{
template <class _Tag, class... _Env>
requires __queryable_with<_Attrs, __get_completion_behavior_t<_Tag>, _Env const &...>
requires __callable<__get_completion_behavior_t<_Tag>, env_of_t<_Sender>, _Env const &...>
constexpr auto query(__get_completion_behavior_t<_Tag>, _Env const &...) const noexcept
{
constexpr auto __behavior = __completion_behavior_of_v<_Tag, _Attrs, _Env...>;
constexpr auto __behavior = __get_completion_behavior<_Tag, _Sender, _Env...>();

// When the child sender completes inline, we can return "inline" here instead of
// "__asynchronous_affine".
Expand All @@ -138,16 +138,30 @@ namespace STDEXEC
return __completion_behavior::__asynchronous_affine;
}
}

template <__forwarding_query _Tag, class... _Args>
requires(!__completion_query<_Tag>)
&& __queryable_with<env_of_t<_Sender>, _Tag, _Args const &...>
constexpr auto query(_Tag, _Args const &...) const noexcept
-> __query_result_t<env_of_t<_Sender>, _Tag, _Args const &...>
{
return __query_result_t<env_of_t<_Sender>, _Tag, _Args const &...>{};
}

_Sender const &__sndr_;
};

template <class _Sender>
STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __attrs(_Sender const &) -> __attrs<_Sender>;
} // namespace __affine_on

template <>
struct __sexpr_impl<affine_on_t> : __sexpr_defaults
{
static constexpr auto __get_attrs = //
[]<class _Child>(__ignore, __ignore, _Child const &) noexcept
[]<class _Child>(affine_on_t, __ignore, _Child const &__child) noexcept
{
return __affine_on::__attrs<env_of_t<_Child>>{};
return __affine_on::__attrs{__child};
};
};
} // namespace STDEXEC
28 changes: 19 additions & 9 deletions include/stdexec/__detail/__completion_behavior.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,17 +156,11 @@ namespace STDEXEC
template <class _Sig>
inline static constexpr __get_completion_behavior_t (*signature)(_Sig) = nullptr;

template <class _Attrs, class... _Env>
template <class _Attrs>
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
constexpr auto operator()(_Attrs const &, _Env const &...) const noexcept
constexpr auto operator()(_Attrs const &) const noexcept
{
if constexpr (__member_queryable_with<_Attrs const &,
__get_completion_behavior_t<_Tag>,
_Env...>)
{
return __validate<_Attrs, _Env...>();
}
else if constexpr (__member_queryable_with<_Attrs const &, __get_completion_behavior_t<_Tag>>)
if constexpr (__member_queryable_with<_Attrs const &, __get_completion_behavior_t<_Tag>>)
{
return __validate<_Attrs>();
}
Expand All @@ -176,6 +170,22 @@ namespace STDEXEC
}
}

template <class _Attrs, class _Env>
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
constexpr auto operator()([[maybe_unused]] _Attrs const &__attrs, _Env const &) const noexcept
{
if constexpr (__member_queryable_with<_Attrs const &,
__get_completion_behavior_t<_Tag>,
_Env const &>)
{
return __validate<_Attrs, _Env>();
}
else
{
return (*this)(__attrs);
}
}

STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
static constexpr auto query(forwarding_query_t) noexcept -> bool
{
Expand Down
3 changes: 1 addition & 2 deletions include/stdexec/__detail/__continues_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,7 @@ namespace STDEXEC
//! @brief Forwards other queries to the underlying sender's environment.
//! @pre @c _Tag is a forwarding query but not a completion query.
template <__forwarding_query _Tag, class... _Args>
requires(!__is_completion_query<_Tag>)
&& __queryable_with<env_of_t<_Sender>, _Tag, _Args...>
requires(!__completion_query<_Tag>) && __queryable_with<env_of_t<_Sender>, _Tag, _Args...>
[[nodiscard]]
constexpr auto query(_Tag, _Args&&... __args) const
noexcept(__nothrow_queryable_with<env_of_t<_Sender>, _Tag, _Args...>)
Expand Down
22 changes: 14 additions & 8 deletions include/stdexec/__detail/__query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,21 @@ namespace STDEXEC
concept __forwarding_query = forwarding_query(_Tag{});

//////////////////////////////////////////////////////////////////////////////////////////
// __is_completion_query
// __completion_query
namespace __detail
{
template <class _Query>
inline constexpr bool __is_completion_query_v = false;
template <class _Tag>
inline constexpr bool __is_completion_query_v<get_completion_domain_t<_Tag>> = true;
template <class _Tag>
inline constexpr bool __is_completion_query_v<get_completion_scheduler_t<_Tag>> = true;
template <class _Tag>
inline constexpr bool __is_completion_query_v<__get_completion_behavior_t<_Tag>> = true;
} // namespace __detail

template <class _Query>
inline constexpr bool __is_completion_query = false;
template <class _Tag>
inline constexpr bool __is_completion_query<get_completion_domain_t<_Tag>> = true;
template <class _Tag>
inline constexpr bool __is_completion_query<get_completion_scheduler_t<_Tag>> = true;
template <class _Tag>
inline constexpr bool __is_completion_query<__get_completion_behavior_t<_Tag>> = true;
concept __completion_query = __detail::__is_completion_query_v<_Query>;
} // namespace STDEXEC

STDEXEC_P2300_NAMESPACE_BEGIN()
Expand Down
13 changes: 2 additions & 11 deletions include/stdexec/__detail/__read_env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,9 @@ namespace STDEXEC
template <class _Query>
struct __attrs
{
template <class _Env>
requires __callable<_Query, _Env>
template <class _SetTag>
STDEXEC_ATTRIBUTE(nodiscard)
constexpr auto query(__get_completion_behavior_t<set_value_t>, _Env const &) const noexcept
{
return __completion_behavior::__inline_completion;
}

template <class _Env>
requires __callable<_Query, _Env> && (!__nothrow_callable<_Query, _Env>)
STDEXEC_ATTRIBUTE(nodiscard)
constexpr auto query(__get_completion_behavior_t<set_error_t>, _Env const &) const noexcept
constexpr auto query(__get_completion_behavior_t<_SetTag>) const noexcept
{
return __completion_behavior::__inline_completion;
}
Expand Down
63 changes: 41 additions & 22 deletions test/stdexec/queries/test_env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,72 +19,91 @@
#include <catch2/catch.hpp>
#include <stdexec/execution.hpp>

namespace ex = STDEXEC;

namespace
{

template <typename T>
concept can_get_domain = requires(T const & t) { t.query(::STDEXEC::get_domain); };
concept can_get_domain = requires(T const & t) { t.query(::ex::get_domain); };

namespace zero
{
using env = ::STDEXEC::env<>;
static_assert(std::is_same_v<::STDEXEC::never_stop_token, ::STDEXEC::stop_token_of_t<env>>);
using env = ::ex::env<>;
static_assert(std::is_same_v<::ex::never_stop_token, ::ex::stop_token_of_t<env>>);
static_assert(!can_get_domain<env>);
} // namespace zero

namespace one
{
using env = ::STDEXEC::env<::STDEXEC::env<>>;
static_assert(std::is_same_v<::STDEXEC::never_stop_token, ::STDEXEC::stop_token_of_t<env>>);
using env = ::ex::env<::ex::env<>>;
static_assert(std::is_same_v<::ex::never_stop_token, ::ex::stop_token_of_t<env>>);
static_assert(!can_get_domain<env>);
} // namespace one

namespace two
{
using env = ::STDEXEC::env<::STDEXEC::env<>, ::STDEXEC::env<>>;
static_assert(std::is_same_v<::STDEXEC::never_stop_token, ::STDEXEC::stop_token_of_t<env>>);
using env = ::ex::env<::ex::env<>, ::ex::env<>>;
static_assert(std::is_same_v<::ex::never_stop_token, ::ex::stop_token_of_t<env>>);
static_assert(!can_get_domain<env>);
} // namespace two

namespace three
{
using env = ::STDEXEC::env<::STDEXEC::env<>, ::STDEXEC::env<>, ::STDEXEC::env<>>;
static_assert(std::is_same_v<::STDEXEC::never_stop_token, ::STDEXEC::stop_token_of_t<env>>);
using env = ::ex::env<::ex::env<>, ::ex::env<>, ::ex::env<>>;
static_assert(std::is_same_v<::ex::never_stop_token, ::ex::stop_token_of_t<env>>);
static_assert(!can_get_domain<env>);
} // namespace three

// https://github.com/NVIDIA/stdexec/issues/1840
constexpr struct FwdFoo
: STDEXEC::__query<FwdFoo>
, STDEXEC::forwarding_query_t
: ex::__query<FwdFoo>
, ex::forwarding_query_t
{
using STDEXEC::__query<FwdFoo>::operator();
using ex::__query<FwdFoo>::operator();
} fwd_foo{};

constexpr struct Foo : STDEXEC::__query<Foo>
constexpr struct Foo : ex::__query<Foo>
{
} foo{};

constexpr struct Bar : STDEXEC::__query<Bar>
constexpr struct Bar : ex::__query<Bar>
{
} bar{};

constexpr bool test()
{
auto env = STDEXEC::env{
STDEXEC::env{STDEXEC::prop{fwd_foo, 42.}, STDEXEC::prop{foo, 'F'}},
STDEXEC::prop{ bar, 31415}
auto env = ex::env{
ex::env{ex::prop{fwd_foo, 42.}, ex::prop{foo, 'F'}},
ex::prop{ bar, 31415}
};

static_assert(STDEXEC::__queryable_with<decltype(env), Foo>);
static_assert(ex::__queryable_with<decltype(env), Foo>);
return fwd_foo(env) == 42. && bar(env) == 31415;
}
static_assert(test());

struct EnvOfThree
: STDEXEC::env<STDEXEC::env<STDEXEC::prop<FwdFoo, int>, STDEXEC::prop<Foo, int>>,
STDEXEC::prop<Bar, int>>
: ex::env<ex::env<ex::prop<FwdFoo, int>, ex::prop<Foo, int>>, ex::prop<Bar, int>>
{};

static_assert(STDEXEC::__queryable_with<EnvOfThree, Foo>);
static_assert(ex::__queryable_with<EnvOfThree, Foo>);

struct non_dependent_attrs
{
[[nodiscard]]
auto query(ex::get_completion_scheduler_t<ex::set_value_t>) const noexcept
{
return ex::inline_scheduler{};
}
};

TEST_CASE("env forwards non-dependent queries to the root environment", "[queries][env]")
{
auto attrs = ex::env{
ex::prop{fwd_foo, 'F'},
non_dependent_attrs{}
};
auto sch = ex::get_completion_scheduler<ex::set_value_t>(attrs, ex::env{});
CHECK(std::same_as<decltype(sch), ex::inline_scheduler>);
}
} // namespace