Initial Commit

This commit is contained in:
2024-12-11 22:08:45 +01:00
commit 2d05d854ff
43 changed files with 3610 additions and 0 deletions

304
cpepetest1/demo_task.hpp Normal file
View File

@@ -0,0 +1,304 @@
// examples/demo_task.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef INCLUDED_EXAMPLES_DEMO_TASK
#define INCLUDED_EXAMPLES_DEMO_TASK
#include <beman/net29/net.hpp>
#include <exception>
#include <coroutine>
#include <memory>
#include <tuple>
#include <optional>
#include <type_traits>
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wreturn-type"
#endif
// ----------------------------------------------------------------------------
namespace demo
{
namespace ex = ::beman::net29::detail::ex;
template <typename T>
struct task_state_base
{
::std::optional<T> task_result;
virtual auto complete_value() -> void = 0;
virtual auto complete_error(::std::exception_ptr) -> void = 0;
virtual auto complete_stopped() -> void = 0;
template <typename Receiver>
auto complete_set_value(Receiver& receiver)
{
::beman::net29::detail::ex::set_value(
::std::move(receiver), ::std::move(*this->task_result)
);
}
};
template <>
struct task_state_base<void>
{
virtual auto complete_value() -> void = 0;
virtual auto complete_error(::std::exception_ptr) -> void = 0;
virtual auto complete_stopped() -> void = 0;
template <typename Receiver>
auto complete_set_value(Receiver& receiver)
{
::beman::net29::detail::ex::set_value(::std::move(receiver));
}
};
struct task_none {};
template <typename... T> struct task_type_or_none;
template <typename T> struct task_type_or_none<T> { using type = T; };
template <> struct task_type_or_none<> { using type = task_none; };
template <typename... T> using task_type_or_none_t = typename task_type_or_none<T...>::type;
template <typename... T>
struct task_single_or_tuple { using type = ::std::tuple<::std::decay_t<T>...>; };
template <typename T>
struct task_single_or_tuple<T> { using type = ::std::decay_t<T>; };
template <typename... T>
using task_single_or_tuple_t = typename task_single_or_tuple<T...>::type;
template <typename R>
struct task_promise_result
{
task_state_base<R>* state{};
template <typename T>
auto return_value(T&& r) -> void
{
this->state->task_result.emplace(std::forward<T>(r));
}
};
template <>
struct task_promise_result<void>
{
task_state_base<void>* state{};
auto return_void() -> void
{
}
};
template <typename T>
struct task_completion { using type = ::beman::net29::detail::ex::set_value_t(T); };
template <>
struct task_completion<void> { using type = ::beman::net29::detail::ex::set_value_t(); };
template <typename Result = void>
struct task
{
enum class stop_state { running, stopping, stopped };
template <typename Promise, ex::sender Sender>
struct sender_awaiter
{
struct env
{
sender_awaiter* awaiter{};
auto query(ex::get_stop_token_t) const noexcept -> ex::inplace_stop_token;
};
struct receiver
{
using receiver_concept = ex::receiver_t;
sender_awaiter* awaiter{};
template <typename... Args>
auto set_value(Args&&... args) noexcept -> void
{
this->awaiter->result.emplace(::std::forward<Args>(args)...);
this->awaiter->handle.resume();
}
template <typename Error>
auto set_error(Error&& error) noexcept -> void
{
if constexpr (::std::same_as<::std::decay_t<Error>, ::std::exception_ptr>)
this->awaiter->error = error;
else
this->awaiter->error = ::std::make_exception_ptr(::std::forward<Error>(error));
this->awaiter->handle.resume();
}
auto set_stopped() noexcept -> void
{
this->awaiter->stop();
}
auto get_env() const noexcept -> env { return {this->awaiter}; }
};
using value_type
= ex::value_types_of_t<
Sender, Promise, task_single_or_tuple_t, task_type_or_none_t>;
using state_type = decltype(ex::connect(::std::declval<Sender>(), std::declval<receiver>()));
::std::coroutine_handle<Promise> handle;
::std::exception_ptr error;
::std::optional<value_type> result;
state_type state;
sender_awaiter(Sender sender)
: state(ex::connect(::std::move(sender), receiver{this}))
{
}
auto stop() -> void;
auto get_token() const noexcept -> ex::inplace_stop_token;
constexpr auto await_ready() const noexcept -> bool { return false; }
auto await_suspend(::std::coroutine_handle<Promise> handle) -> void
{
this->handle = handle;
ex::start(this->state);
}
auto await_resume()
{
if (this->error)
std::rethrow_exception(this->error);
return ::std::move(*this->result);
}
};
struct promise_type;
struct final_awaiter
{
promise_type* promise;
constexpr auto await_ready() const noexcept -> bool { return false; }
auto await_suspend(::std::coroutine_handle<>) noexcept -> void
{
this->promise->state->complete_value();
}
constexpr auto await_resume() const noexcept -> void {}
};
struct promise_type
: task_promise_result<Result>
{
task::stop_state stop_state{task::stop_state::running};
ex::inplace_stop_source stop_source{};
auto initial_suspend() -> ::std::suspend_always { return {}; }
auto final_suspend() noexcept -> final_awaiter { return {this}; }
auto get_return_object() -> task
{
return {unique_handle(this)};
}
auto unhandled_exception() -> void
{
this->state->complete_error(::std::current_exception());
}
template <ex::sender Sender>
auto await_transform(Sender&& sender)
{
return sender_awaiter<promise_type, ::std::remove_cvref_t<Sender>>
(::std::forward<Sender>(sender));
}
};
using deleter = decltype([](promise_type* p) {
std::coroutine_handle<promise_type>::from_promise(*p).destroy();
});
using unique_handle= std::unique_ptr<promise_type, deleter>;
template <typename Receiver>
struct state
: task_state_base<::std::decay_t<Result>>
{
using operation_state_concept = ex::operation_state_t;
struct callback_t
{
state* object;
auto operator()() const
{
auto state{this->object};
state->callback.reset();
state->handle->stop_state = task::stop_state::stopping;
state->handle->stop_source.request_stop();
if (state->handle->stop_state == task::stop_state::stopped)
this->object->handle->state->complete_stopped();
}
};
using stop_token = decltype(ex::get_stop_token(ex::get_env(::std::declval<Receiver>())));
using stop_callback = ex::stop_callback_for_t<stop_token, callback_t>;
unique_handle handle;
::std::decay_t<Receiver> receiver;
::std::optional<stop_callback> callback;
template <typename R>
state(unique_handle handle, R&& receiver)
: handle(::std::move(handle))
, receiver(::std::forward<R>(receiver))
{
}
auto start() & noexcept -> void
{
this->handle->state = this;
this->callback.emplace(ex::get_stop_token(ex::get_env(this->receiver)), callback_t{this});
std::coroutine_handle<promise_type>::from_promise(*this->handle).resume();
}
auto complete_value() -> void override
{
this->complete_set_value(this->receiver);
}
auto complete_error(::std::exception_ptr error) -> void override
{
::beman::net29::detail::ex::set_error(
::std::move(this->receiver),
::std::move(error)
);
}
auto complete_stopped() -> void override
{
::beman::net29::detail::ex::set_stopped(::std::move(this->receiver));
}
};
unique_handle handle;
using sender_concept = ::beman::net29::detail::ex::sender_t;
using completion_signatures = ::beman::net29::detail::ex::completion_signatures<
::beman::net29::detail::ex::set_error_t(::std::exception_ptr),
::beman::net29::detail::ex::set_stopped_t(),
typename task_completion<::std::decay_t<Result>>::type
>;
template <typename Receiver>
auto connect(Receiver&& receiver)
{
return state<Receiver>(
::std::move(this->handle),
::std::forward<Receiver>(receiver)
);
}
};
}
// ----------------------------------------------------------------------------
template <typename Result>
template <typename Promise, demo::ex::sender Sender>
auto
demo::task<Result>::sender_awaiter<Promise, Sender>::env::query(demo::ex::get_stop_token_t) const noexcept
-> demo::ex::inplace_stop_token
{
return this->awaiter->handle.promise().stop_source.get_token();
}
template <typename Result>
template <typename Promise, demo::ex::sender Sender>
auto
demo::task<Result>::sender_awaiter<Promise, Sender>::stop() ->void
{
if (::std::exchange(this->handle.promise().stop_state, task::stop_state::stopped)
== task::stop_state::running)
{
this->handle.promise().state->complete_stopped();
}
}
// ----------------------------------------------------------------------------
#endif