Skip to content

Commit

Permalink
WIP: initial implementation of D3206R0
Browse files Browse the repository at this point in the history
  • Loading branch information
maikel committed Jan 8, 2025
1 parent ad1bb84 commit 0587b8f
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 10 deletions.
35 changes: 27 additions & 8 deletions include/beman/execution26/detail/basic_sender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,29 @@ struct basic_sender : ::beman::execution26::detail::product_type<Tag, Data, Chil
data.children);
}

template <class Self, class Env>
constexpr auto get_completion_behaviour(this Self&& self, Env&& env) noexcept -> decltype(auto) {
auto data{::beman::execution26::detail::get_sender_data(self)};
return ::std::apply(
[&data, &env](auto&&... cs) {
return ::beman::execution26::detail::impls_for<Tag>::get_completion_behaviour(
::std::forward<Env>(env),
::beman::execution26::detail::forward_like<Self>(data.data),
::beman::execution26::detail::forward_like<Self>(cs)...);
},
::beman::execution26::detail::forward_like<Self>(data.children));
}

template <typename Receiver>
requires(not::beman::execution26::receiver<Receiver>)
requires(not ::beman::execution26::receiver<Receiver>)
auto connect(Receiver receiver) = BEMAN_EXECUTION26_DELETE("the passed receiver doesn't model receiver");

private:
#if __cpp_explicit_this_parameter < 302110L //-dk:TODO need to figure out how to use explicit this with forwarding
template <::beman::execution26::receiver Receiver>
auto connect(Receiver receiver) & noexcept(
noexcept(::beman::execution26::detail::basic_operation<basic_sender&, Receiver>{*this, ::std::move(receiver)}))
-> ::beman::execution26::detail::basic_operation<basic_sender&, Receiver> {
noexcept(::beman::execution26::detail::basic_operation<basic_sender&, Receiver>{
*this, ::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation<basic_sender&, Receiver> {
return {*this, ::std::move(receiver)};
}
template <::beman::execution26::receiver Receiver>
Expand All @@ -59,18 +72,18 @@ struct basic_sender : ::beman::execution26::detail::product_type<Tag, Data, Chil
}
template <::beman::execution26::receiver Receiver>
auto connect(Receiver receiver) && noexcept(
noexcept(::beman::execution26::detail::basic_operation<basic_sender, Receiver>{::std::move(*this),
::std::move(receiver)}))
-> ::beman::execution26::detail::basic_operation<basic_sender, Receiver> {
noexcept(::beman::execution26::detail::basic_operation<basic_sender, Receiver>{
::std::move(*this),
::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation<basic_sender, Receiver> {
return {::std::move(*this), ::std::move(receiver)};
}
#else
template <::beman::execution26::detail::decays_to<basic_sender> Self, ::beman::execution26::receiver Receiver>
auto
connect(this Self&& self,
Receiver receiver) noexcept(noexcept(::beman::execution26::detail::basic_operation<basic_sender, Receiver>{
::std::forward<Self>(self), ::std::move(receiver)}))
-> ::beman::execution26::detail::basic_operation<Self, Receiver> {
::std::forward<Self>(self),
::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation<Self, Receiver> {
return {::std::forward<Self>(self), ::std::move(receiver)};
}
#endif
Expand Down Expand Up @@ -101,6 +114,12 @@ struct basic_sender : ::beman::execution26::detail::product_type<Tag, Data, Chil
-> ::beman::execution26::detail::completion_signatures_for<Self, Env> {
return {};
}

template <::beman::execution26::detail::decays_to<basic_sender> Self, typename Env>
auto get_completion_behaviour(this Self&&, Env&&) noexcept
-> ::beman::execution26::detail::completion_signatures_for<Self, Env> {
return {};
}
#endif
};
} // namespace beman::execution26::detail
Expand Down
13 changes: 13 additions & 0 deletions include/beman/execution26/detail/completion_behaviour.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// include/beman/execution26/detail/completion_behaviour.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_COMPLETION_BEHAVIOUR
#define INCLUDED_BEMAN_EXECUTION26_DETAIL_COMPLETION_BEHAVIOUR

#include <cstdint>

namespace beman::execution26 {
enum class completion_behaviour : std::uint8_t { inline_completion, synchronous, asynchronous, unknown };
} // namespace beman::execution26

#endif
4 changes: 4 additions & 0 deletions include/beman/execution26/detail/default_impls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ struct default_impls {
static_assert(Index::value == 0);
Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
};
static constexpr auto get_completion_behaviour =
[](const auto& /* env */, const auto& /* data */, const auto&... /* children */) noexcept {
return ::beman::execution26::completion_behaviour::unknown;
};
};
} // namespace beman::execution26::detail

Expand Down
68 changes: 68 additions & 0 deletions include/beman/execution26/detail/get_completion_behaviour.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// include/beman/execution26/detail/get_completion_behaviour.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_GET_COMPLETION_BEHAVIOUR
#define INCLUDED_BEMAN_EXECUTION26_DETAIL_GET_COMPLETION_BEHAVIOUR

#include <beman/execution26/detail/completion_behaviour.hpp>
#include <beman/execution26/detail/forward_like.hpp>
#include <beman/execution26/detail/is_awaitable.hpp>
#include <beman/execution26/detail/get_domain_late.hpp>
#include <beman/execution26/detail/transform_sender.hpp>

#include <type_traits>

namespace beman::execution26 {

struct get_completion_behaviour_t {
template <class Sender>
constexpr auto operator()(Sender&& sender) const noexcept {
if constexpr (requires { typename ::std::remove_cvref_t<Sender>::completion_behaviour; }) {
return typename ::std::remove_cvref_t<Sender>::completion_behaviour{};
} else if constexpr (requires { ::std::forward<Sender>(sender).get_completion_behaviour(); }) {
return ::std::forward<Sender>(sender).get_completion_behaviour();
} else if constexpr (::beman::execution26::detail::is_awaitable<
::std::remove_cvref_t<Sender>,
::beman::execution26::detail::env_promise<::beman::execution26::empty_env>>) {
return sender.await_ready() ? ::beman::execution26::completion_behaviour::inline_completion
: ::beman::execution26::completion_behaviour::unknown;
} else {
return ::beman::execution26::completion_behaviour::unknown;
}
}

template <class Sender, class Env>
constexpr auto operator()(Sender&& sender, Env&& env) const noexcept {
auto new_sender{[](auto&& sndr, auto&& e) -> decltype(auto) {
auto domain{::beman::execution26::detail::get_domain_late(sndr, e)};
return ::beman::execution26::transform_sender(
domain, ::std::forward<Sender>(sndr), ::std::forward<Env>(e));
}};

using new_sender_type =
::std::remove_cvref_t<decltype(new_sender(::std::forward<Sender>(sender), ::std::forward<Env>(env)))>;
using decayed_env = ::std::remove_cvref_t<Env>;

if constexpr (requires { typename new_sender_type::completion_behaviour; }) {
return typename new_sender_type::completion_behaviour{};
} else if constexpr (requires { ::std::move(new_sender).get_completion_behaviour(std::forward<Env>(env)); }) {
return std::move(new_sender).get_completion_behaviour(std::forward<Env>(env));
} else if constexpr (::beman::execution26::detail::is_awaitable<
new_sender_type,
::beman::execution26::detail::env_promise<decayed_env>>) {
if (new_sender(sender, env).await_ready()) {
return completion_behaviour::inline_completion;
} else {
return completion_behaviour::unknown;
}
} else {
return completion_behaviour::unknown;
}
}
};

inline constexpr get_completion_behaviour_t get_completion_behaviour{};

} // namespace beman::execution26

#endif
8 changes: 6 additions & 2 deletions include/beman/execution26/detail/just.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

namespace beman::execution26::detail {
template <typename Completion, typename... T>
concept just_size = (not::std::same_as<Completion, ::beman::execution26::set_error_t> or 1u == sizeof...(T)) &&
(not::std::same_as<Completion, ::beman::execution26::set_stopped_t> or 0u == sizeof...(T));
concept just_size = (not ::std::same_as<Completion, ::beman::execution26::set_error_t> or 1u == sizeof...(T)) &&
(not ::std::same_as<Completion, ::beman::execution26::set_stopped_t> or 0u == sizeof...(T));
template <typename Completion>
struct just_t {
template <typename... T>
Expand All @@ -49,6 +49,10 @@ struct impls_for<just_t<Completion>> : ::beman::execution26::detail::default_imp
Completion()(::std::move(receiver), ::std::move(state.template get<I>())...);
}(::std::make_index_sequence<State::size()>{});
};

static constexpr auto get_completion_behaviour = [](const auto&, const auto&, const auto&) {
return ::beman::execution26::completion_behaviour::inline_completion;
};
};
} // namespace beman::execution26::detail

Expand Down
2 changes: 2 additions & 0 deletions src/beman/execution26/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ target_sources(
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/child_type.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/class_type.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/common.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_behaviour.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_domain.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_signature.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_signatures.hpp
Expand Down Expand Up @@ -84,6 +85,7 @@ target_sources(
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/gather_signatures.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_allocator.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_awaiter.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_completion_behaviour.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_completion_scheduler.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_completion_signatures.hpp
${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_delegation_scheduler.hpp
Expand Down
1 change: 1 addition & 0 deletions tests/beman/execution26/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ list(
exec-general.test
exec-get-allocator.test
exec-get-compl-sched.test
exec-get-completion-behaviour.test
exec-get-delegation-scheduler.test
exec-get-domain.test
exec-get-env.test
Expand Down
53 changes: 53 additions & 0 deletions tests/beman/execution26/exec-get-completion-behaviour.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// src/beman/execution26/tests/exec-get-completion-behaviour.test.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/execution26/detail/get_completion_behaviour.hpp>

#include <test/execution.hpp>

#include <type_traits>

namespace {

template <auto Value>
using value = std::integral_constant<decltype(Value), Value>;

struct awaitable {
static constexpr auto await_ready() noexcept -> bool { return true; }
auto await_suspend(auto parent) noexcept { return parent; }
auto await_resume() noexcept -> void {}
};

void test_constexpr_awaitable() {
auto completion_behaviour = value<test_std::get_completion_behaviour(awaitable{})>{};
ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour);
}
struct sender {
using completion_behaviour = value<test_std::completion_behaviour::inline_completion>;
};

struct sender2 {
static constexpr auto get_completion_behaviour() noexcept -> test_std::completion_behaviour {
return test_std::completion_behaviour::inline_completion;
}
};

void test_typedef_sender() {
auto completion_behaviour =
std::integral_constant<test_std::completion_behaviour, test_std::get_completion_behaviour(sender{})>{};
ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour);
}

void test_constexpr_sender() {
auto completion_behaviour =
std::integral_constant<test_std::completion_behaviour, test_std::get_completion_behaviour(sender{})>{};
ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour);
}

} // namespace

TEST(exec_get_completion_behaviour) {
test_constexpr_awaitable();
test_typedef_sender();
test_constexpr_sender();
}

0 comments on commit 0587b8f

Please sign in to comment.