blob: 0f54d91ff52802550e59b99bcdf77e1b35d4472b [file] [edit]
// include/beman/execution/detail/spawn.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_SPAWN
#define INCLUDED_BEMAN_EXECUTION_DETAIL_SPAWN
#include <beman/execution/detail/common.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
import std;
#else
#include <memory>
#include <type_traits>
#include <utility>
#endif
#ifdef BEMAN_HAS_MODULES
import beman.execution.detail.connect;
import beman.execution.detail.connect_result_t;
import beman.execution.detail.env;
import beman.execution.detail.queryable;
import beman.execution.detail.receiver;
import beman.execution.detail.scope_token;
import beman.execution.detail.sender;
import beman.execution.detail.spawn_get_allocator;
import beman.execution.detail.start;
import beman.execution.detail.write_env;
#else
#include <beman/execution/detail/connect.hpp>
#include <beman/execution/detail/connect_result_t.hpp>
#include <beman/execution/detail/env.hpp>
#include <beman/execution/detail/queryable.hpp>
#include <beman/execution/detail/receiver.hpp>
#include <beman/execution/detail/scope_token.hpp>
#include <beman/execution/detail/sender.hpp>
#include <beman/execution/detail/spawn_get_allocator.hpp>
#include <beman/execution/detail/start.hpp>
#include <beman/execution/detail/write_env.hpp>
#endif
// ----------------------------------------------------------------------------
namespace beman::execution::detail {
struct spawn_t {
struct state_base {
virtual ~state_base() = default;
virtual auto complete() noexcept -> void = 0;
};
struct receiver {
using receiver_concept = ::beman::execution::receiver_tag;
state_base* state{};
auto set_value() && noexcept -> void { this->state->complete(); }
auto set_stopped() && noexcept -> void { this->state->complete(); }
};
template <typename Alloc, ::beman::execution::scope_token Tok, ::beman::execution::sender Sndr>
struct state : state_base {
using op_t = ::beman::execution::connect_result_t<Sndr, receiver>;
using assoc_t = ::std::remove_cvref_t<decltype(::std::declval<const Tok&>().try_associate())>;
using alloc_t = typename ::std::allocator_traits<Alloc>::template rebind_alloc<state>;
using traits_t = ::std::allocator_traits<alloc_t>;
state(Alloc a, Sndr&& sndr, const Tok& tok)
: alloc(a),
op(::beman::execution::connect(::std::forward<Sndr>(sndr), receiver{this})),
assoc(tok.try_associate()) {
if (this->assoc) {
::beman::execution::start(this->op);
} else {
this->destroy();
}
}
auto complete() noexcept -> void override {
assoc_t _ = ::std::move(this->assoc);
this->destroy();
}
auto destroy() noexcept -> void {
alloc_t all(this->alloc);
traits_t::destroy(all, this);
traits_t::deallocate(all, this, 1);
}
alloc_t alloc;
op_t op;
assoc_t assoc;
};
template <::beman::execution::sender Sender, ::beman::execution::scope_token Token, typename Env>
requires ::beman::execution::detail::queryable<::std::remove_cvref_t<Env>>
auto operator()(Sender&& sender, const Token& tok, Env&& env) const {
auto new_sender{tok.wrap(::std::forward<Sender>(sender))};
auto [all, senv] = ::beman::execution::detail::spawn_get_allocator(new_sender, env);
using sender_t = decltype(::beman::execution::write_env(::std::move(new_sender), senv));
using state_t = state<decltype(all), Token, sender_t>;
using alloc_t = typename ::std::allocator_traits<decltype(all)>::template rebind_alloc<state_t>;
using traits_t = ::std::allocator_traits<alloc_t>;
alloc_t alloc(all);
state_t* op{traits_t::allocate(alloc, 1u)};
try {
traits_t::construct(alloc, op, all, ::beman::execution::write_env(::std::move(new_sender), senv), tok);
} catch (...) {
traits_t::deallocate(alloc, op, 1u);
throw;
}
}
template <::beman::execution::sender Sender, ::beman::execution::scope_token Token>
auto operator()(Sender&& sender, const Token& token) const {
return (*this)(::std::forward<Sender>(sender), token, ::beman::execution::env<>{});
}
};
} // namespace beman::execution::detail
namespace beman::execution {
using spawn_t = ::beman::execution::detail::spawn_t;
inline constexpr spawn_t spawn{};
} // namespace beman::execution
// ----------------------------------------------------------------------------
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_SPAWN