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
9 changes: 9 additions & 0 deletions include/beman/task/detail/awaiter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct awaiter_op_t<Awaiter, ParentPromise, false> {
template <typename Value, typename Env, typename OwnPromise, typename ParentPromise>
class awaiter : public ::beman::task::detail::state_base<Value, Env> {
public:
using allocator_type = typename ::beman::task::detail::state_base<Value, Env>::allocator_type;
using stop_token_type = typename ::beman::task::detail::state_base<Value, Env>::stop_token_type;
using scheduler_type = typename ::beman::task::detail::state_base<Value, Env>::scheduler_type;

Expand Down Expand Up @@ -87,6 +88,14 @@ class awaiter : public ::beman::task::detail::state_base<Value, Env> {
auto actual_complete() -> std::coroutine_handle<> {
return this->no_completion_set() ? this->parent.promise().unhandled_stopped() : ::std::move(this->parent);
}
auto do_get_allocator() -> allocator_type override {
if constexpr (requires {
::beman::execution::get_allocator(::beman::execution::get_env(this->parent.promise()));
})
return ::beman::execution::get_allocator(::beman::execution::get_env(this->parent.promise()));
else
return allocator_type{};
}
auto do_get_scheduler() -> scheduler_type override { return *this->scheduler; }
auto do_set_scheduler(scheduler_type other) -> scheduler_type override {
return ::std::exchange(*this->scheduler, other);
Expand Down
6 changes: 1 addition & 5 deletions include/beman/task/detail/promise_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ class promise_type
using stop_source_type = ::beman::task::detail::stop_source_of_t<Environment>;
using stop_token_type = decltype(std::declval<stop_source_type>().get_token());

template <typename... A>
promise_type(const A&... a) : allocator(::beman::task::detail::find_allocator<allocator_type>(a...)) {}

constexpr auto initial_suspend() noexcept -> ::std::suspend_always { return {}; }
constexpr auto final_suspend() noexcept -> ::beman::task::detail::final_awaiter { return {}; }

Expand Down Expand Up @@ -106,7 +103,7 @@ class promise_type
}

auto get_scheduler() const noexcept -> scheduler_type { return this->get_state()->get_scheduler(); }
auto get_allocator() const noexcept -> allocator_type { return this->allocator; }
auto get_allocator() const noexcept -> allocator_type { return this->get_state()->get_allocator(); }
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

promise_type::get_allocator() now forwards to this->get_state()->get_allocator() but unlike get_environment() it doesn't assert that get_state() is non-null. If get_allocator is queried before start()/set_state() (e.g. via get_env()), this will dereference a null state pointer. Consider adding an assert(this->get_state()) (or a safe fallback allocator) similar to get_environment().

Suggested change
auto get_allocator() const noexcept -> allocator_type { return this->get_state()->get_allocator(); }
auto get_allocator() const noexcept -> allocator_type {
assert(this);
assert(this->get_state());
return this->get_state()->get_allocator();
}

Copilot uses AI. Check for mistakes.
auto get_stop_token() const noexcept -> stop_token_type { return this->get_state()->get_stop_token(); }
auto get_environment() const noexcept -> const Environment& {
assert(this);
Expand All @@ -117,7 +114,6 @@ class promise_type
private:
using env_t = ::beman::task::detail::promise_env<promise_type>;

allocator_type allocator{};
::std::optional<scheduler_type> scheduler{};
};
} // namespace beman::task::detail
Expand Down
7 changes: 7 additions & 0 deletions include/beman/task/detail/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct state : ::beman::task::detail::state_base<T, C>, ::beman::task::detail::s
using operation_state_concept = ::beman::execution::operation_state_t;
using promise_type = ::beman::task::detail::promise_type<Task, T, C>;
using scheduler_type = typename ::beman::task::detail::state_base<T, C>::scheduler_type;
using allocator_type = typename ::beman::task::detail::state_base<T, C>::allocator_type;
using stop_source_type = ::beman::task::detail::stop_source_of_t<C>;
using stop_token_type = decltype(std::declval<stop_source_type>().get_token());
using stop_token_t =
Expand All @@ -46,6 +47,12 @@ struct state : ::beman::task::detail::state_base<T, C>, ::beman::task::detail::s
this->result_complete(::std::move(this->receiver));
return std::noop_coroutine();
}
auto do_get_allocator() -> allocator_type override {
if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(this->receiver)); })
return ::beman::execution::get_allocator(::beman::execution::get_env(this->receiver));
else
return allocator_type{};
}
auto do_get_scheduler() -> scheduler_type override { return this->scheduler; }
auto do_set_scheduler(scheduler_type other) -> scheduler_type override {
return ::std::exchange(this->scheduler, other);
Expand Down
4 changes: 4 additions & 0 deletions include/beman/task/detail/state_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <beman/task/detail/stop_source.hpp>
#include <beman/task/detail/scheduler_of.hpp>
#include <beman/task/detail/allocator_of.hpp>
#include <beman/task/detail/error_types_of.hpp>
#include <beman/task/detail/result_type.hpp>
#include <coroutine>
Expand All @@ -18,11 +19,13 @@ class state_base : public ::beman::task::detail::result_type<::beman::task::deta
Value,
::beman::task::detail::error_types_of_t<Environment>> {
public:
using allocator_type = ::beman::task::detail::allocator_of_t<Environment>;
using stop_source_type = ::beman::task::detail::stop_source_of_t<Environment>;
using stop_token_type = decltype(std::declval<stop_source_type>().get_token());
using scheduler_type = ::beman::task::detail::scheduler_of_t<Environment>;

auto complete() -> std::coroutine_handle<> { return this->do_complete(); }
auto get_allocator() -> allocator_type { return this->do_get_allocator(); }
auto get_stop_token() -> stop_token_type { return this->do_get_stop_token(); }
auto get_environment() -> Environment& {
assert(this);
Expand All @@ -43,6 +46,7 @@ class state_base : public ::beman::task::detail::result_type<::beman::task::deta

// NOLINTBEGIN(portability-template-virtual-member-function)
virtual auto do_complete() -> std::coroutine_handle<> = 0;
virtual auto do_get_allocator() -> allocator_type = 0;
virtual auto do_get_stop_token() -> stop_token_type = 0;
virtual auto do_get_environment() -> Environment& = 0;
virtual auto do_get_scheduler() -> scheduler_type = 0;
Expand Down
3 changes: 3 additions & 0 deletions tests/beman/task/promise_base.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/task/detail/promise_base.hpp>
#include <beman/task/detail/allocator_of.hpp>
#include <beman/task/detail/state_base.hpp>
#include <beman/task/detail/inline_scheduler.hpp>
#include <beman/execution/execution.hpp>
Expand Down Expand Up @@ -48,6 +49,7 @@ struct env {
template <typename T, typename... E>
struct state : bt::state_base<T, env<E...>> {
using Environment = env<E...>;
using allocator_type = ::beman::task::detail::allocator_of_t<Environment>;
using stop_source_type = ::beman::task::detail::stop_source_of_t<Environment>;
using stop_token_type = decltype(std::declval<stop_source_type>().get_token());
using scheduler_type = ::beman::task::detail::scheduler_of_t<Environment>;
Expand All @@ -62,6 +64,7 @@ struct state : bt::state_base<T, env<E...>> {
this->completed = true;
return std::noop_coroutine();
}
allocator_type do_get_allocator() override { return allocator_type{}; }
stop_token_type do_get_stop_token() override {
this->token = true;
return this->source.get_token();
Expand Down
5 changes: 4 additions & 1 deletion tests/beman/task/promise_type.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <beman/task/detail/promise_type.hpp>
#include <beman/task/detail/allocator_of.hpp>
#include <beman/task/detail/task_scheduler.hpp>
#include <beman/task/detail/inline_scheduler.hpp>
#include <beman/execution/execution.hpp>
Expand Down Expand Up @@ -128,7 +129,8 @@ struct test_error : std::exception {

struct test_task : beman::task::detail::state_base<int, environment> {

using promise_type = beman::task::detail::promise_type<test_task, int, environment>;
using promise_type = ::beman::task::detail::promise_type<test_task, int, environment>;
using allocator_type = ::beman::task::detail::allocator_of_t<environment>;

beman::task::detail::handle<promise_type> handle;
explicit test_task(beman::task::detail::handle<promise_type> h) : handle(std::move(h)) {}
Expand All @@ -153,6 +155,7 @@ struct test_task : beman::task::detail::state_base<int, environment> {
this->latch.count_down();
return std::noop_coroutine();
}
allocator_type do_get_allocator() override { return allocator_type{}; }
stop_token_type do_get_stop_token() override { return this->source.get_token(); }
environment& do_get_environment() override { return this->env; }
auto do_get_scheduler() -> scheduler_type override { return scheduler_type(bt::inline_scheduler()); }
Expand Down
3 changes: 3 additions & 0 deletions tests/beman/task/state_base.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <beman/task/detail/state_base.hpp>
#include <beman/task/detail/inline_scheduler.hpp>
#include <beman/task/detail/allocator_of.hpp>
#ifdef NDEBUG
#undef NDEBUG
#endif
Expand All @@ -16,6 +17,7 @@ namespace {
struct environment {};

struct state : beman::task::detail::state_base<int, environment> {
using allocator_type = ::beman::task::detail::allocator_of_t<environment>;
stop_source_type source;
environment env;
bool completed{};
Expand All @@ -26,6 +28,7 @@ struct state : beman::task::detail::state_base<int, environment> {
this->completed = true;
return std::noop_coroutine();
}
allocator_type do_get_allocator() override { return allocator_type{}; }
stop_token_type do_get_stop_token() override {
this->token = true;
return this->source.get_token();
Expand Down
Loading