Skip to content

Commit

Permalink
added default_impls
Browse files Browse the repository at this point in the history
  • Loading branch information
dietmarkuehl committed Aug 25, 2024
1 parent d90c6d8 commit 96b5f8b
Show file tree
Hide file tree
Showing 4 changed files with 289 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/dependency.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ continues_on sender_for
default_domain queryable
default_domain sender
default_domain tag_of_t
default_impls fwd_env
default_impls get_env
default_impls empty_env
default_impls start
default_impls callable
default_set_error completion_signatures
default_set_error set_value
default_set_value completion_signatures
Expand Down
63 changes: 63 additions & 0 deletions include/Beman/Execution26/detail/default_impls.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// include/Beman/Execution26/detail/default_impls.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_DEFAULT_IMPLS
#define INCLUDED_BEMAN_EXECUTION26_DETAIL_DEFAULT_IMPLS

#include <Beman/Execution26/detail/fwd_env.hpp>
#include <Beman/Execution26/detail/get_env.hpp>
#include <Beman/Execution26/detail/empty_env.hpp>
#include <Beman/Execution26/detail/start.hpp>
#include <Beman/Execution26/detail/sender_decompose.hpp>
#include <Beman/Execution26/detail/callable.hpp>
#include <utility>
#include <type_traits>

// ----------------------------------------------------------------------------

namespace Beman::Execution26::Detail
{
struct default_impls
{
static constexpr auto get_attrs
= [](auto const&, auto const&... child) noexcept -> decltype(auto)
{
if constexpr (1 == sizeof...(child))
return (::Beman::Execution26::Detail::fwd_env(
::Beman::Execution26::get_env(child)
), ...);
else
return ::Beman::Execution26::empty_env{};
};
static constexpr auto get_env
= [](auto, auto&, auto const& receiver) noexcept -> decltype(auto)
{
return ::Beman::Execution26::Detail::fwd_env(
::Beman::Execution26::get_env(receiver)
);
};
static constexpr auto get_state
= []<typename Sender, typename Receiver>(Sender&& sender, Receiver&) noexcept -> decltype(auto)
{
auto&& decompose = ::Beman::Execution26::Detail::get_sender_data(::std::forward<Sender>(sender));
return ::std::forward_like<Sender>(decompose.data);
};
static constexpr auto start
= [](auto&, auto&, auto&... ops) noexcept -> void
{
(::Beman::Execution26::start(ops), ...);
};
static constexpr auto complete
= []<typename Index, typename Receiver, typename Tag, typename... Args>(
Index, auto&, Receiver& receiver, Tag, Args&&... args) noexcept -> void
requires ::Beman::Execution26::Detail::callable<Tag, Receiver, Args...>
{
static_assert(Index::value == 0);
Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
};
};
}

// ----------------------------------------------------------------------------

#endif
60 changes: 60 additions & 0 deletions include/Beman/Execution26/detail/sender_decompose.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <tuple>
#include <type_traits>
#include <utility>

// ----------------------------------------------------------------------------

Expand All @@ -24,6 +25,14 @@ namespace Beman::Execution26::Detail
using children_type = ::std::remove_cvref_t<Children>;
};

template <typename Tag, typename Data, typename Children>
struct sender_data
{
::std::remove_cvref_t<Tag> tag;
Data& data;
Children children;
};

template <typename Sender>
auto get_sender_meta(Sender&& sender)
{
Expand Down Expand Up @@ -64,6 +73,57 @@ namespace Beman::Execution26::Detail
return ::Beman::Execution26::Detail::sender_meta<void, void, void>{};
}
}

template <typename Sender>
auto get_sender_data(Sender&& sender)
{
#if 0
//-dk:TODO should use a dynamic/language approach:
auto&& [tag, data, ... children] = sender;
return sender_meta<decltype(tag), decltype(data), ::std::tuple<decltype(children)...>>;
#endif
using sender_type = ::std::remove_cvref_t<Sender>;
static constexpr ::Beman::Execution26::Detail::sender_any_t any{};
if constexpr (requires(){ sender_type{ any, any, any, any, any, any }; })
{
auto&& [tag, data, c0, c1, c2, c3] = sender;
return ::Beman::Execution26::Detail::sender_data<decltype(tag), decltype(data), decltype(::std::tie(c0, c1, c2, c3))>{
tag, data, ::std::tie(c0, c1, c2, c3)
};
}
else if constexpr (requires(){ sender_type{ any, any, any, any, any }; })
{
auto&& [tag, data, c0, c1, c2] = sender;
return ::Beman::Execution26::Detail::sender_data<decltype(tag), decltype(data), decltype(::std::tie(c0, c1, c2))>{
tag, data, ::std::tie(c0, c1, c2)
};
}
else if constexpr (requires(){ sender_type{ any, any, any, any }; })
{
auto&& [tag, data, c0, c1] = sender;
return ::Beman::Execution26::Detail::sender_data<decltype(tag), decltype(data), decltype(::std::tie(c0, c1))>{
tag, data, ::std::tie(c0, c1)
};
}
else if constexpr (requires(){ sender_type{ any, any, any }; })
{
auto&& [tag, data, c0] = sender;
return ::Beman::Execution26::Detail::sender_data<decltype(tag), decltype(data), decltype(::std::tie(c0))>{
tag, data, ::std::tie(c0)
};
}
else if constexpr (requires(){ sender_type{ any, any }; })
{
auto&& [tag, data] = sender;
return ::Beman::Execution26::Detail::sender_data<decltype(tag), decltype(data), ::std::tuple<>>{
tag, data, ::std::tuple<>()
};
}
else
{
return ::Beman::Execution26::Detail::sender_meta<void, void, void>{};
}
}
}

namespace Beman::Execution26
Expand Down
161 changes: 161 additions & 0 deletions src/Beman/Execution26/tests/exec-snd-expos.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <Beman/Execution26/detail/sender.hpp>
#include <Beman/Execution26/detail/query_with_default.hpp>
#include <Beman/Execution26/detail/get_domain_late.hpp>
#include <Beman/Execution26/detail/default_impls.hpp>
#include <Beman/Execution26/execution.hpp>
#include <test/execution.hpp>
#include <concepts>
Expand Down Expand Up @@ -317,6 +318,165 @@ namespace
//-dk:TOO test
#endif
}

auto test_default_impls_get_attrs() -> void
{
struct env { int value; };
struct child1 { auto get_env() const noexcept { return env{1}; } };
struct child2 { auto get_env() const noexcept { return env{2}; } };

static_assert(noexcept(test_detail::default_impls::get_attrs(0, child1{})));
static_assert(std::same_as<test_detail::fwd_env<env>,
decltype(test_detail::default_impls::get_attrs(0, child1{}))>);
static_assert(std::same_as<test_std::empty_env,
decltype(test_detail::default_impls::get_attrs(0, child1{}, child2{}))>);
}

auto test_default_impls_get_env() -> void
{
struct env { int value; };
struct receiver { auto get_env() const noexcept { return env{1}; } };

int arg{};
static_assert(noexcept(test_detail::default_impls::get_env(0, arg, receiver{})));
static_assert(std::same_as<test_detail::fwd_env<env>,
decltype(test_detail::default_impls::get_env(0, arg, receiver{}))>);
}

auto test_default_impls_get_state() -> void
{
struct tag {};
struct data
{
int v1{}; int v2{};
auto operator== (data const&) const -> bool = default;
};
struct sender0
{
tag t;
data d{1, 2};
};
struct sender1
{
tag t;
data d{1, 2};
int i1;
};
struct sender2
{
tag t;
data d{1, 2};
int i1;
int i2;
};
struct sender3
{
tag t;
data d{1, 2};
int i1;
int i2;
int i3;
};
struct sender4
{
tag t;
data d{1, 2};
int i1;
int i2;
int i3;
int i4;
};
struct receiver
{
};

sender0 s{};
sender0 const cs{};
receiver r{};
static_assert(noexcept(test_detail::default_impls::get_state(sender0{}, r)));
static_assert(std::same_as<data&&,
decltype(test_detail::default_impls::get_state(sender0{}, r))>);
assert((data{1, 2}) == test_detail::default_impls::get_state(sender0{}, r));
static_assert(std::same_as<data&&,
decltype(test_detail::default_impls::get_state(sender1{}, r))>);
assert((data{1, 2}) == test_detail::default_impls::get_state(sender1{}, r));
static_assert(std::same_as<data&&,
decltype(test_detail::default_impls::get_state(sender2{}, r))>);
assert((data{1, 2}) == test_detail::default_impls::get_state(sender2{}, r));
static_assert(std::same_as<data&&,
decltype(test_detail::default_impls::get_state(sender3{}, r))>);
assert((data{1, 2}) == test_detail::default_impls::get_state(sender3{}, r));
static_assert(std::same_as<data&&,
decltype(test_detail::default_impls::get_state(sender4{}, r))>);
assert((data{1, 2}) == test_detail::default_impls::get_state(sender4{}, r));
static_assert(std::same_as<data&,
decltype(test_detail::default_impls::get_state(s, r))>);
static_assert(std::same_as<data const&,
decltype(test_detail::default_impls::get_state(cs, r))>);
}
auto test_default_impls_start() -> void
{
struct state
{
bool called{false};
auto start() noexcept -> void { called = true; }
};
int a0{};
int a1{};
state s1;
state s2;
state s3;
state s4;
state s5;
static_assert(noexcept(test_detail::default_impls::start(a0, a1, s1, s2, s3, s4, s5)));
assert(s1.called == false);
assert(s2.called == false);
assert(s3.called == false);
assert(s4.called == false);
assert(s5.called == false);
test_detail::default_impls::start(a0, a1, s1, s2, s3, s4, s5);
assert(s1.called == true);
assert(s2.called == true);
assert(s3.called == true);
assert(s4.called == true);
assert(s5.called == true);
}
template <typename Impls>
auto test_default_impls_complete(Impls) -> void
{
struct arg {};
struct receiver { bool& called; };
struct state {};

bool called{false};
auto non_tag = [](receiver&&, int){};
auto tag = [](receiver&& r, int, arg){ r.called = true; };
receiver r{called};
state s{};

static_assert(not requires{
Impls::complete(::std::integral_constant<int, 0>{}, s, r, non_tag, 0, arg{});
});
static_assert(requires{
Impls::complete(::std::integral_constant<int, 0>{}, s, r, tag, 0, arg{});
});
static_assert(noexcept(
Impls::complete(::std::integral_constant<int, 0>{}, s, r, tag, 0, arg{})
));

assert(r.called == false);
Impls::complete(::std::integral_constant<int, 0>{}, s, r, tag, 0, arg{});
assert(r.called == true);
}

auto test_default_impls() -> void
{
test_default_impls_get_attrs();
test_default_impls_get_env();
test_default_impls_get_state();
test_default_impls_start();
test_default_impls_complete(test_detail::default_impls{});
}
}

auto main() -> int
Expand All @@ -329,4 +489,5 @@ auto main() -> int
test_completion_domain();
test_query_with_default();
test_get_domain_late();
test_default_impls();
}

0 comments on commit 96b5f8b

Please sign in to comment.