From 35d10097d9ff87f32cfdb50d9bd4326f021b7ddc Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Thu, 21 May 2026 16:26:25 -0500 Subject: [PATCH 01/10] task module --- .../detail/{ => task}/allocator_of.hpp | 6 ++-- .../detail/{ => task}/completion.hpp | 6 ++-- .../execution/detail/task/error_types_of.hpp | 28 +++++++++++++++++++ .../detail/{ => task}/find_allocator.hpp | 6 ++-- .../execution/detail/{ => task}/handle.hpp | 6 ++-- .../execution/detail/{ => task}/logger.hpp | 6 ++-- .../execution/detail/{ => task}/poly.hpp | 6 ++-- .../detail/{ => task}/promise_env.hpp | 6 ++-- .../execution/detail/{ => task}/state_rep.hpp | 6 ++-- .../stop_source.hpp} | 8 +++--- .../execution/detail/{ => task}/sub_visit.hpp | 6 ++-- include/beman/execution/task.hpp | 22 +++++++++++++++ src/beman/execution/CMakeLists.txt | 23 +++++++-------- 13 files changed, 93 insertions(+), 42 deletions(-) rename include/beman/execution/detail/{ => task}/allocator_of.hpp (86%) rename include/beman/execution/detail/{ => task}/completion.hpp (79%) create mode 100644 include/beman/execution/detail/task/error_types_of.hpp rename include/beman/execution/detail/{ => task}/find_allocator.hpp (88%) rename include/beman/execution/detail/{ => task}/handle.hpp (88%) rename include/beman/execution/detail/{ => task}/logger.hpp (85%) rename include/beman/execution/detail/{ => task}/poly.hpp (93%) rename include/beman/execution/detail/{ => task}/promise_env.hpp (88%) rename include/beman/execution/detail/{ => task}/state_rep.hpp (91%) rename include/beman/execution/detail/{stop_source_of.hpp => task/stop_source.hpp} (73%) rename include/beman/execution/detail/{ => task}/sub_visit.hpp (88%) create mode 100644 include/beman/execution/task.hpp diff --git a/include/beman/execution/detail/allocator_of.hpp b/include/beman/execution/detail/task/allocator_of.hpp similarity index 86% rename from include/beman/execution/detail/allocator_of.hpp rename to include/beman/execution/detail/task/allocator_of.hpp index 4e6d9010..48a1fec7 100644 --- a/include/beman/execution/detail/allocator_of.hpp +++ b/include/beman/execution/detail/task/allocator_of.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/allocator_of.hpp -*-C++-*- +// include/beman/execution/detail/task/allocator_of.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ALLOCATOR_OF -#define INCLUDED_BEMAN_EXECUTION_DETAIL_ALLOCATOR_OF +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_OF +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_OF #include #include diff --git a/include/beman/execution/detail/completion.hpp b/include/beman/execution/detail/task/completion.hpp similarity index 79% rename from include/beman/execution/detail/completion.hpp rename to include/beman/execution/detail/task/completion.hpp index 75d82ebf..aee3ddfc 100644 --- a/include/beman/execution/detail/completion.hpp +++ b/include/beman/execution/detail/task/completion.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/completion.hpp -*-C++-*- +// include/beman/execution/detail/task/completion.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION -#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_COMPLETION +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_COMPLETION #include diff --git a/include/beman/execution/detail/task/error_types_of.hpp b/include/beman/execution/detail/task/error_types_of.hpp new file mode 100644 index 00000000..b6902bbe --- /dev/null +++ b/include/beman/execution/detail/task/error_types_of.hpp @@ -0,0 +1,28 @@ +// include/beman/execution/detail/task/error_types_of.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ERROR_TYPES_OF +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ERROR_TYPES_OF + +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template +struct error_types_of { + using type = ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>; +}; +template + requires requires { typename Context::error_types; } +struct error_types_of { + using type = typename Context::error_types; +}; +template +using error_types_of_t = typename error_types_of::type; +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ERROR_TYPES_OF diff --git a/include/beman/execution/detail/find_allocator.hpp b/include/beman/execution/detail/task/find_allocator.hpp similarity index 88% rename from include/beman/execution/detail/find_allocator.hpp rename to include/beman/execution/detail/task/find_allocator.hpp index 8ace784d..9f4a8862 100644 --- a/include/beman/execution/detail/find_allocator.hpp +++ b/include/beman/execution/detail/task/find_allocator.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/find_allocator.hpp -*-C++-*- +// include/beman/execution/detail/task/find_allocator.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_FIND_ALLOCATOR -#define INCLUDED_BEMAN_EXECUTION_DETAIL_FIND_ALLOCATOR +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_FIND_ALLOCATOR +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_FIND_ALLOCATOR #include #include diff --git a/include/beman/execution/detail/handle.hpp b/include/beman/execution/detail/task/handle.hpp similarity index 88% rename from include/beman/execution/detail/handle.hpp rename to include/beman/execution/detail/task/handle.hpp index 60d8ce5b..9df48499 100644 --- a/include/beman/execution/detail/handle.hpp +++ b/include/beman/execution/detail/task/handle.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/handle.hpp -*-C++-*- +// include/beman/execution/detail/task/handle.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_HANDLE -#define INCLUDED_BEMAN_EXECUTION_DETAIL_HANDLE +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_HANDLE +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_HANDLE #include #include diff --git a/include/beman/execution/detail/logger.hpp b/include/beman/execution/detail/task/logger.hpp similarity index 85% rename from include/beman/execution/detail/logger.hpp rename to include/beman/execution/detail/task/logger.hpp index 4fea369e..b6d40091 100644 --- a/include/beman/execution/detail/logger.hpp +++ b/include/beman/execution/detail/task/logger.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/logger.hpp -*-C++-*- +// include/beman/execution/detail/task/logger.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_LOGGER -#define INCLUDED_BEMAN_EXECUTION_DETAIL_LOGGER +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_LOGGER +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_LOGGER #include #include diff --git a/include/beman/execution/detail/poly.hpp b/include/beman/execution/detail/task/poly.hpp similarity index 93% rename from include/beman/execution/detail/poly.hpp rename to include/beman/execution/detail/task/poly.hpp index 33358bd5..9fd5cfb7 100644 --- a/include/beman/execution/detail/poly.hpp +++ b/include/beman/execution/detail/task/poly.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/poly.hpp -*-C++-*- +// include/beman/execution/detail/task/poly.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_POLY -#define INCLUDED_BEMAN_EXECUTION_DETAIL_POLY +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_POLY +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_POLY #include #include diff --git a/include/beman/execution/detail/promise_env.hpp b/include/beman/execution/detail/task/promise_env.hpp similarity index 88% rename from include/beman/execution/detail/promise_env.hpp rename to include/beman/execution/detail/task/promise_env.hpp index 9560a0e9..6b2a2e3a 100644 --- a/include/beman/execution/detail/promise_env.hpp +++ b/include/beman/execution/detail/task/promise_env.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/promise_env.hpp -*-C++-*- +// include/beman/execution/detail/task/promise_env.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_PROMISE_ENV -#define INCLUDED_BEMAN_EXECUTION_DETAIL_PROMISE_ENV +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_PROMISE_ENV +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_PROMISE_ENV #include #include diff --git a/include/beman/execution/detail/state_rep.hpp b/include/beman/execution/detail/task/state_rep.hpp similarity index 91% rename from include/beman/execution/detail/state_rep.hpp rename to include/beman/execution/detail/task/state_rep.hpp index 8d369924..c30d8ad6 100644 --- a/include/beman/execution/detail/state_rep.hpp +++ b/include/beman/execution/detail/task/state_rep.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/state_rep.hpp -*-C++-*- +// include/beman/execution/detail/task/state_rep.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_STATE_REP -#define INCLUDED_BEMAN_EXECUTION_DETAIL_STATE_REP +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STATE_REP +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STATE_REP #include #include diff --git a/include/beman/execution/detail/stop_source_of.hpp b/include/beman/execution/detail/task/stop_source.hpp similarity index 73% rename from include/beman/execution/detail/stop_source_of.hpp rename to include/beman/execution/detail/task/stop_source.hpp index 85d6e25e..2386859c 100644 --- a/include/beman/execution/detail/stop_source_of.hpp +++ b/include/beman/execution/detail/task/stop_source.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/stop_source_of.hpp -*-C++-*- +// include/beman/execution/detail/task/stop_source.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_STOP_SOURCE_OF -#define INCLUDED_BEMAN_EXECUTION_DETAIL_STOP_SOURCE_OF +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STOP_SOURCE +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STOP_SOURCE #include @@ -24,4 +24,4 @@ using stop_source_of_t = typename stop_source_of::type; // ---------------------------------------------------------------------------- -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_STOP_SOURCE_OF +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_STOP_SOURCE diff --git a/include/beman/execution/detail/sub_visit.hpp b/include/beman/execution/detail/task/sub_visit.hpp similarity index 88% rename from include/beman/execution/detail/sub_visit.hpp rename to include/beman/execution/detail/task/sub_visit.hpp index 19b9cb59..6587b25d 100644 --- a/include/beman/execution/detail/sub_visit.hpp +++ b/include/beman/execution/detail/task/sub_visit.hpp @@ -1,10 +1,10 @@ -// include/beman/execution/detail/sub_visit.hpp -*-C++-*- +// include/beman/execution/detail/task/sub_visit.hpp -*-C++-*- // ---------------------------------------------------------------------------- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // ---------------------------------------------------------------------------- -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_SUB_VISIT -#define INCLUDED_BEMAN_EXECUTION_DETAIL_SUB_VISIT +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SUB_VISIT +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SUB_VISIT #include #include diff --git a/include/beman/execution/task.hpp b/include/beman/execution/task.hpp new file mode 100644 index 00000000..f912ba27 --- /dev/null +++ b/include/beman/execution/task.hpp @@ -0,0 +1,22 @@ +// include/beman/execution/task.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_TASK +#define INCLUDED_BEMAN_EXECUTION_TASK + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_TASK diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 0a984af6..0663298f 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/execution.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/functional.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/stop_token.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/task.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/execution.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/stop_token.hpp PUBLIC @@ -25,7 +26,6 @@ target_sources( FILES ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/affine_on.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/allocator_aware_move.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/allocator_of.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/almost_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/apply_sender.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/as_awaitable.hpp @@ -47,7 +47,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/child_type.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/class_type.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/common.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signature.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signatures.hpp @@ -78,9 +77,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/env_of_t.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/env_promise.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/env_type.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/error_types_of.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/error_types_of_t.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/find_allocator.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/forward_like.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/forwarding_query.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/fwd_env.hpp @@ -98,7 +95,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_forward_progress_guarantee.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_stop_token.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/handle.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/has_as_awaitable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/has_completions.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/immovable.hpp @@ -115,7 +111,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/join_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/just.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/let.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/logger.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/make_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/make_sender.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/matching_sig.hpp @@ -140,8 +135,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/operation_state.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/operation_state_task.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/product_type.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/poly.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/promise_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/prop.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/query_with_default.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/queryable.hpp @@ -180,11 +173,9 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/spawn_get_allocator.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/start.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/starts_on.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/state_rep.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/state_type.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stop_callback_for_t.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stop_source.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stop_source_of.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stop_token_of_t.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stop_when.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stoppable_source.hpp @@ -192,13 +183,23 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stopped_as_error.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stopped_as_optional.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/store_receiver.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sub_visit.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/suppress_pop.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/suppress_push.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/suspend_complete.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sync_wait.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sync_wait_with_variant.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/tag_of_t.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/allocator_of.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/completion.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/error_types_of.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/find_allocator.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/handle.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/logger.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/poly.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/promise_env.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/state_rep.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/stop_source.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/sub_visit.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/then.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/transform_sender.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/type_list.hpp From ded17afe59f40f8f6df21f5b3c3992b5628521a0 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Thu, 21 May 2026 16:31:47 -0500 Subject: [PATCH 02/10] remove double error_types_of.hpp --- .../beman/execution/detail/error_types_of.hpp | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 include/beman/execution/detail/error_types_of.hpp diff --git a/include/beman/execution/detail/error_types_of.hpp b/include/beman/execution/detail/error_types_of.hpp deleted file mode 100644 index ea130048..00000000 --- a/include/beman/execution/detail/error_types_of.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// include/beman/execution/detail/error_types_of.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CONTEXT_ERROR_TYPES_OF -#define INCLUDED_BEMAN_EXECUTION_DETAIL_CONTEXT_ERROR_TYPES_OF - -#include -#include - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -template -struct error_types_of { - using type = ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>; -}; -template - requires requires { typename Context::error_types; } -struct error_types_of { - using type = typename Context::error_types; -}; -template -using error_types_of_t = typename error_types_of::type; -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CONTEXT_ERROR_TYPES_OF From 4448d21b9db0612a18e89c9128ccf8ede283db83 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Thu, 21 May 2026 17:39:09 -0500 Subject: [PATCH 03/10] add allocator_support before update --- .../detail/task/allocator_support.hpp | 87 +++++++++++++++++++ include/beman/execution/task.hpp | 1 + src/beman/execution/CMakeLists.txt | 1 + tests/beman/execution/CMakeLists.txt | 1 + .../execution/task-allocator_support.test.cpp | 62 +++++++++++++ 5 files changed, 152 insertions(+) create mode 100644 include/beman/execution/detail/task/allocator_support.hpp create mode 100644 tests/beman/execution/task-allocator_support.test.cpp diff --git a/include/beman/execution/detail/task/allocator_support.hpp b/include/beman/execution/detail/task/allocator_support.hpp new file mode 100644 index 00000000..48956963 --- /dev/null +++ b/include/beman/execution/detail/task/allocator_support.hpp @@ -0,0 +1,87 @@ +// include/beman/execution/detail/task/allocator_support.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_SUPPORT +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_SUPPORT + +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +/*! + * \brief Utility adding allocator support to type by embedding the allocator + * \headerfile beman/execution/task.hpp + * + * To add allocator support using this class just publicly inherit from + * allocator_support. This utility is probably + * only useful for coroutine promise types. + * + * This struct is a massive hack, primarily support allocators for coroutines. + * The memory for coroutines is implicitly managed and there isn't a way to + * provide the memory directly. Instead, the promise_type can overload an + * operator new and somehow determine an allocator based on the arguments + * passed to the coroutine. Even worse, the operator delete only gets passed + * a pointer to delete and a size. To determine the correct allocator the + * operator delete needs to located it based on this information. Putting + * the allocator after actually used memory causes the address sanitizer to + * object! So, the current strategy is to embed space for the allocator + * into the object and pull it out from there. + */ +template +struct allocator_support { + using allocator_traits = std::allocator_traits; + + static std::size_t offset(std::size_t size) { + return (size + alignof(Allocator) - 1u) & ~(alignof(Allocator) - 1u); + } + static Allocator* get_allocator(void* ptr, std::size_t size) { + ptr = static_cast(ptr) + offset(size); + return ::std::launder(reinterpret_cast(ptr)); + } + + template + static void* operator new(std::size_t size, [[maybe_unused]] A&&... a) { + if constexpr (::std::same_as>) { + Allocator alloc{}; + return allocator_traits::allocate(alloc, size); + } else { + Allocator alloc{::beman::execution::detail::find_allocator(a...)}; + void* ptr{allocator_traits::allocate(alloc, allocator_support::offset(size) + sizeof(Allocator))}; + try { + new (allocator_support::get_allocator(ptr, size)) Allocator(alloc); + } catch (...) { + allocator_traits::deallocate( + alloc, static_cast(ptr), allocator_support::offset(size) + sizeof(Allocator)); + throw; + } + return ptr; + } + } + template + static void operator delete(void* ptr, std::size_t size, const A&...) { + allocator_support::operator delete(ptr, size); + } + static void operator delete(void* ptr, std::size_t size) { + if constexpr (::std::same_as>) { + Allocator alloc{}; + allocator_traits::deallocate(alloc, static_cast(ptr), size); + } else { + Allocator* aptr{allocator_support::get_allocator(ptr, size)}; + Allocator alloc{*aptr}; + aptr->~Allocator(); + allocator_traits::deallocate( + alloc, static_cast(ptr), allocator_support::offset(size) + sizeof(Allocator)); + } + } +}; +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/task.hpp b/include/beman/execution/task.hpp index f912ba27..6f3c475f 100644 --- a/include/beman/execution/task.hpp +++ b/include/beman/execution/task.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 0663298f..102cbeaf 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -190,6 +190,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sync_wait_with_variant.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/tag_of_t.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/allocator_of.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/allocator_support.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/completion.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/error_types_of.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/find_allocator.hpp diff --git a/tests/beman/execution/CMakeLists.txt b/tests/beman/execution/CMakeLists.txt index 08530378..5f30e54d 100644 --- a/tests/beman/execution/CMakeLists.txt +++ b/tests/beman/execution/CMakeLists.txt @@ -10,6 +10,7 @@ list(APPEND unsupported_execution_tests exec-split.test) list( APPEND execution_tests allocator-requirements-general.test + task-allocator_support.test exec-affine-on.test exec-associate.test exec-awaitable.test diff --git a/tests/beman/execution/task-allocator_support.test.cpp b/tests/beman/execution/task-allocator_support.test.cpp new file mode 100644 index 00000000..3cc6a7d2 --- /dev/null +++ b/tests/beman/execution/task-allocator_support.test.cpp @@ -0,0 +1,62 @@ +// tests/beman/execution/task-allocator_support.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable : 4291) +#endif + +// ---------------------------------------------------------------------------- + +namespace { +struct test_resource : std::pmr::memory_resource { + std::size_t outstanding{}; + + auto do_allocate(std::size_t size, std::size_t) -> void* override { + this->outstanding += size; + return ::operator new(size); + } + auto do_deallocate(void* ptr, std::size_t size, std::size_t) -> void override { + ::operator delete(ptr); + this->outstanding -= size; + } + auto do_is_equal(const std::pmr::memory_resource& other) const noexcept -> bool override { + auto* tr{dynamic_cast(&other)}; + return tr == this; + } +}; + +struct some_data { + double data{}; +}; + +template +struct allocator_aware : some_data, test_detail::allocator_support { + allocator_aware() : some_data() {} +}; +} // namespace + +// ---------------------------------------------------------------------------- + +TEST(allocator_support) { + using type = allocator_aware>; + [[maybe_unused]] std::unique_ptr unused(new type{}); + + test_resource resource{}; + ASSERT(resource.outstanding == 0u); + type* ptr{new (std::allocator_arg, &resource) type{}}; + ASSERT(resource.outstanding != 0u); + ptr->~type(); + ASSERT(resource.outstanding != 0u); +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif + type::operator delete(ptr, sizeof(type), std::allocator_arg, &resource); + ASSERT(resource.outstanding == 0u); +} From 56d07f146a0748ed7feec6b17e7ce3e80aecb82f Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Thu, 21 May 2026 22:20:41 -0500 Subject: [PATCH 04/10] update allocator_support P3980R1 --- .../detail/task/allocator_support.hpp | 151 +++++++++++++----- .../execution/task-allocator_support.test.cpp | 78 ++++++++- 2 files changed, 184 insertions(+), 45 deletions(-) diff --git a/include/beman/execution/detail/task/allocator_support.hpp b/include/beman/execution/detail/task/allocator_support.hpp index 48956963..dc2c2b88 100644 --- a/include/beman/execution/detail/task/allocator_support.hpp +++ b/include/beman/execution/detail/task/allocator_support.hpp @@ -4,16 +4,53 @@ #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_SUPPORT #define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_ALLOCATOR_SUPPORT -#include -#include #include #include #include #include +#include +#include // ---------------------------------------------------------------------------- namespace beman::execution::detail { +struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) allocator_support_allocation_unit { + std::byte bytes[__STDCPP_DEFAULT_NEW_ALIGNMENT__]; +}; + +static_assert(sizeof(allocator_support_allocation_unit) == __STDCPP_DEFAULT_NEW_ALIGNMENT__); +static_assert(alignof(allocator_support_allocation_unit) == __STDCPP_DEFAULT_NEW_ALIGNMENT__); + +struct allocator_support_header { + void (*deallocate)(void*, std::size_t) noexcept; + std::size_t count; + std::size_t palloc_offset; +}; + +template +using allocator_support_alloc_t = std::remove_cvref_t; + +template +using allocator_support_palloc_t = + typename std::allocator_traits>::template rebind_alloc< + allocator_support_allocation_unit>; + +template +concept allocator_support_allocator_like = requires { typename allocator_support_alloc_t::value_type; }; + +template +concept allocator_support_allocator_arg = + allocator_support_allocator_like && requires(allocator_support_alloc_t& alloc, std::size_t size) { + typename allocator_support_palloc_t; + typename std::allocator_traits>::pointer; + requires std::same_as>::pointer, + allocator_support_allocation_unit*>; + requires(alignof(allocator_support_palloc_t) <= alignof(allocator_support_allocation_unit)); + allocator_support_palloc_t(alloc); + std::allocator_traits>::allocate( + std::declval&>(), size); + }; + /*! * \brief Utility adding allocator support to type by embedding the allocator * \headerfile beman/execution/task.hpp @@ -25,59 +62,87 @@ namespace beman::execution::detail { * This struct is a massive hack, primarily support allocators for coroutines. * The memory for coroutines is implicitly managed and there isn't a way to * provide the memory directly. Instead, the promise_type can overload an - * operator new and somehow determine an allocator based on the arguments - * passed to the coroutine. Even worse, the operator delete only gets passed - * a pointer to delete and a size. To determine the correct allocator the - * operator delete needs to located it based on this information. Putting - * the allocator after actually used memory causes the address sanitizer to - * object! So, the current strategy is to embed space for the allocator - * into the object and pull it out from there. + * operator new and use a leading std::allocator_arg/allocator pair when it + * is present. Even worse, the operator delete only gets passed a pointer to + * delete and a size. To determine the correct allocator the operator delete + * stores a type-erased deallocation header and the rebound allocator in the + * allocation block. */ template struct allocator_support { - using allocator_traits = std::allocator_traits; + static std::size_t align_up(std::size_t value, std::size_t alignment) { + return ((value + alignment - 1u) / alignment) * alignment; + } - static std::size_t offset(std::size_t size) { - return (size + alignof(Allocator) - 1u) & ~(alignof(Allocator) - 1u); + static std::size_t header_offset(std::size_t size) { + return allocator_support::align_up(size, alignof(allocator_support_header)); } - static Allocator* get_allocator(void* ptr, std::size_t size) { - ptr = static_cast(ptr) + offset(size); - return ::std::launder(reinterpret_cast(ptr)); + + static allocator_support_header* get_header(void* ptr, std::size_t size) { + ptr = static_cast(ptr) + allocator_support::header_offset(size); + return ::std::launder(reinterpret_cast(ptr)); } - template - static void* operator new(std::size_t size, [[maybe_unused]] A&&... a) { - if constexpr (::std::same_as>) { - Allocator alloc{}; - return allocator_traits::allocate(alloc, size); - } else { - Allocator alloc{::beman::execution::detail::find_allocator(a...)}; - void* ptr{allocator_traits::allocate(alloc, allocator_support::offset(size) + sizeof(Allocator))}; - try { - new (allocator_support::get_allocator(ptr, size)) Allocator(alloc); - } catch (...) { - allocator_traits::deallocate( - alloc, static_cast(ptr), allocator_support::offset(size) + sizeof(Allocator)); - throw; - } - return ptr; + template + static void deallocate_with(void* ptr, std::size_t size) noexcept { + using palloc_traits = std::allocator_traits; + + allocator_support_header* header{allocator_support::get_header(ptr, size)}; + auto* palloc_ptr{ + ::std::launder(reinterpret_cast(static_cast(ptr) + header->palloc_offset))}; + PAlloc palloc{*palloc_ptr}; + std::size_t count{header->count}; + palloc_ptr->~PAlloc(); + palloc_traits::deallocate(palloc, static_cast(ptr), count); + } + + template + requires allocator_support_allocator_arg + static void* allocate(std::size_t size, Alloc alloc) { + using palloc_t = allocator_support_palloc_t; + using palloc_traits = std::allocator_traits; + + palloc_t palloc{alloc}; + std::size_t header_offset{allocator_support::header_offset(size)}; + std::size_t palloc_offset{allocator_support::align_up(header_offset + sizeof(allocator_support_header), + alignof(palloc_t))}; + std::size_t count{(palloc_offset + sizeof(palloc_t) + sizeof(allocator_support_allocation_unit) - 1u) / + sizeof(allocator_support_allocation_unit)}; + + allocator_support_allocation_unit* ptr{palloc_traits::allocate(palloc, count)}; + try { + new (static_cast(static_cast(ptr)) + header_offset) + allocator_support_header{&allocator_support::deallocate_with, count, palloc_offset}; + new (static_cast(static_cast(ptr)) + palloc_offset) palloc_t(palloc); + } catch (...) { + palloc_traits::deallocate(palloc, ptr, count); + throw; } + return ptr; + } + + static void* operator new(std::size_t size) { + return allocator_support::allocate(size, Allocator{}); } + + template + requires allocator_support_allocator_arg + static void* operator new(std::size_t size, std::allocator_arg_t, Alloc alloc, A&&...) { + return allocator_support::allocate(size, alloc); + } + + template + requires allocator_support_allocator_arg + static void* operator new(std::size_t size, const This&, std::allocator_arg_t, Alloc alloc, A&&...) { + return allocator_support::allocate(size, alloc); + } + template - static void operator delete(void* ptr, std::size_t size, const A&...) { + static void operator delete(void* ptr, std::size_t size, const A&...) noexcept { allocator_support::operator delete(ptr, size); } - static void operator delete(void* ptr, std::size_t size) { - if constexpr (::std::same_as>) { - Allocator alloc{}; - allocator_traits::deallocate(alloc, static_cast(ptr), size); - } else { - Allocator* aptr{allocator_support::get_allocator(ptr, size)}; - Allocator alloc{*aptr}; - aptr->~Allocator(); - allocator_traits::deallocate( - alloc, static_cast(ptr), allocator_support::offset(size) + sizeof(Allocator)); - } + static void operator delete(void* ptr, std::size_t size) noexcept { + allocator_support::get_header(ptr, size)->deallocate(ptr, size); } }; } // namespace beman::execution::detail diff --git a/tests/beman/execution/task-allocator_support.test.cpp b/tests/beman/execution/task-allocator_support.test.cpp index 3cc6a7d2..6e81f89f 100644 --- a/tests/beman/execution/task-allocator_support.test.cpp +++ b/tests/beman/execution/task-allocator_support.test.cpp @@ -36,27 +36,101 @@ struct some_data { double data{}; }; +struct allocation_counter { + std::size_t outstanding{}; +}; + +template +struct tracking_allocator { + using value_type = T; + + allocation_counter* counter{}; + + explicit tracking_allocator(allocation_counter& c) noexcept : counter(&c) {} + + template + tracking_allocator(const tracking_allocator& other) noexcept : counter(other.counter) {} + + auto allocate(std::size_t count) -> T* { + this->counter->outstanding += count * sizeof(T); + return static_cast(::operator new(count * sizeof(T), std::align_val_t(alignof(T)))); + } + + auto deallocate(T* ptr, std::size_t count) noexcept -> void { + ::operator delete(ptr, std::align_val_t(alignof(T))); + this->counter->outstanding -= count * sizeof(T); + } + + template + auto operator==(const tracking_allocator& other) const noexcept -> bool { + return this->counter == other.counter; + } +}; + template struct allocator_aware : some_data, test_detail::allocator_support { allocator_aware() : some_data() {} }; + +template +concept supports_misplaced_allocator = requires(test_resource& resource) { + T::operator new(sizeof(T), 0, 1, std::allocator_arg, std::pmr::polymorphic_allocator{&resource}); +}; + +template +concept supports_resource_pointer_allocator = requires(test_resource& resource) { + T::operator new(sizeof(T), std::allocator_arg, &resource); +}; + +template +concept constructs_pmr_byte_allocator = requires(Alloc& alloc) { + std::pmr::polymorphic_allocator{alloc}; +}; } // namespace // ---------------------------------------------------------------------------- TEST(allocator_support) { using type = allocator_aware>; + static_assert(requires { type::operator new(sizeof(type)); }); + static_assert(requires(test_resource& resource) { + type::operator new(sizeof(type), std::allocator_arg, std::pmr::polymorphic_allocator{&resource}); + }); + static_assert(requires(const some_data& object, test_resource& resource) { + type::operator new( + sizeof(type), object, std::allocator_arg, std::pmr::polymorphic_allocator{&resource}); + }); + static_assert(requires(allocation_counter& counter) { + type::operator new(sizeof(type), std::allocator_arg, tracking_allocator{counter}); + }); + static_assert(not constructs_pmr_byte_allocator>); + static_assert(not supports_misplaced_allocator); + static_assert(not supports_resource_pointer_allocator); + [[maybe_unused]] std::unique_ptr unused(new type{}); test_resource resource{}; + std::pmr::polymorphic_allocator allocator{&resource}; ASSERT(resource.outstanding == 0u); - type* ptr{new (std::allocator_arg, &resource) type{}}; + type* ptr{new (std::allocator_arg, allocator) type{}}; ASSERT(resource.outstanding != 0u); ptr->~type(); ASSERT(resource.outstanding != 0u); #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wmismatched-new-delete" #endif - type::operator delete(ptr, sizeof(type), std::allocator_arg, &resource); + type::operator delete(ptr, sizeof(type), std::allocator_arg, allocator); + ASSERT(resource.outstanding == 0u); + + some_data object{}; + void* raw{type::operator new(sizeof(type), object, std::allocator_arg, allocator)}; + ASSERT(resource.outstanding != 0u); + type::operator delete(raw, sizeof(type), object, std::allocator_arg, allocator); ASSERT(resource.outstanding == 0u); + + allocation_counter counter{}; + void* custom_raw{type::operator new(sizeof(type), std::allocator_arg, tracking_allocator{counter})}; + ASSERT(counter.outstanding != 0u); + type::operator delete(custom_raw, sizeof(type), std::allocator_arg, tracking_allocator{counter}); + ASSERT(counter.outstanding == 0u); } From 6c00d7a8b613588acf30d2a281c523d8286700f2 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Sat, 23 May 2026 17:08:37 -0500 Subject: [PATCH 05/10] added task_scheduler and infallible_scheduler --- .../detail/task/infallible_scheduler.hpp | 33 +++ .../execution/detail/task/task_scheduler.hpp | 195 +++++++++++++ include/beman/execution/task.hpp | 2 + src/beman/execution/CMakeLists.txt | 2 + tests/beman/execution/CMakeLists.txt | 2 + .../task-infallible_scheduler.test.cpp | 59 ++++ tests/beman/execution/task_scheduler.test.cpp | 268 ++++++++++++++++++ 7 files changed, 561 insertions(+) create mode 100644 include/beman/execution/detail/task/infallible_scheduler.hpp create mode 100644 include/beman/execution/detail/task/task_scheduler.hpp create mode 100644 tests/beman/execution/task-infallible_scheduler.test.cpp create mode 100644 tests/beman/execution/task_scheduler.test.cpp diff --git a/include/beman/execution/detail/task/infallible_scheduler.hpp b/include/beman/execution/detail/task/infallible_scheduler.hpp new file mode 100644 index 00000000..ec5b3935 --- /dev/null +++ b/include/beman/execution/detail/task/infallible_scheduler.hpp @@ -0,0 +1,33 @@ +// include/beman/execution/detail/task/infallible_scheduler.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_INFALLIBLE_SCHEDULER +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_INFALLIBLE_SCHEDULER + +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template +concept completes_with = + ::std::same_as<::beman::execution::completion_signatures, + ::beman::execution:: + completion_signatures_of_t())), Env>>; + +template +concept infallible_scheduler = + (::beman::execution::scheduler) && + (::beman::execution::detail::completes_with || + (!::beman::execution::unstoppable_token<::beman::execution::stop_token_of_t> && + (::beman::execution::detail:: + completes_with || + ::beman::execution::detail:: + completes_with))); +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/detail/task/task_scheduler.hpp b/include/beman/execution/detail/task/task_scheduler.hpp new file mode 100644 index 00000000..12d6511c --- /dev/null +++ b/include/beman/execution/detail/task/task_scheduler.hpp @@ -0,0 +1,195 @@ +// include/beman/execution/detail/task/task_scheduler.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SCHEDULER +#define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SCHEDULER + +#include +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +/*! + * \brief Type-erasing scheduler + * \headerfile beman/execution/task.hpp + * + * The class `task_scheduler` is used to type-erase any infallible scheduler class. + */ +class task_scheduler { + struct state_base { + virtual ~state_base() = default; + virtual void complete_value() = 0; + }; + + struct inner_state { + struct receiver { + using receiver_concept = ::beman::execution::receiver_tag; + state_base* state; + void set_value() && noexcept { this->state->complete_value(); } + }; + static_assert(::beman::execution::receiver); + + struct base { + virtual ~base() = default; + virtual void start() = 0; + }; + template <::beman::execution::sender Sender> + struct concrete : base { + using state_t = decltype(::beman::execution::connect(::std::declval(), ::std::declval())); + state_t state; + + template <::beman::execution::sender S> + concrete(S&& s, state_base* b) : state(::beman::execution::connect(::std::forward(s), receiver{b})) {} + void start() override { ::beman::execution::start(state); } + }; + + ::beman::execution::detail::poly state; + + template <::beman::execution::sender S> + inner_state(S&& s, state_base* b) + : state(static_cast*>(nullptr), ::std::forward(s), b) {} + + void start() { this->state->start(); } + }; + + template <::beman::execution::receiver Receiver> + struct state : state_base { + using operation_state_concept = ::beman::execution::operation_state_tag; + ::std::remove_cvref_t receiver; + inner_state s; + + template <::beman::execution::receiver R, typename PS> + state(R&& r, PS& ps) : receiver(::std::forward(r)), s(ps->connect(this)) {} + void start() & noexcept { this->s.start(); } + void complete_value() override { ::beman::execution::set_value(::std::move(this->receiver)); } + }; + + class sender; + class env { + friend class sender; + + private: + const sender* sndr; + explicit env(const sender* s) : sndr(s) {} + + public: + task_scheduler + query(const ::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>&) const noexcept { + return this->sndr->inner_sender->get_completion_scheduler(); + } + }; + + class sender { + friend class env; + + private: + struct base { + virtual ~base() = default; + virtual base* move(void*) = 0; + virtual base* clone(void*) const = 0; + virtual inner_state connect(state_base*) = 0; + virtual task_scheduler get_completion_scheduler() const = 0; + }; + template <::beman::execution::scheduler Scheduler> + struct concrete : base { + using sender_type = decltype(::beman::execution::schedule(::std::declval())); + sender_type sender; + + template <::beman::execution::scheduler S> + explicit concrete(S&& s) : sender(::beman::execution::schedule(::std::forward(s))) {} + base* move(void* buffer) override { return new (buffer) concrete(::std::move(*this)); } + base* clone(void* buffer) const override { return new (buffer) concrete(*this); } + inner_state connect(state_base* b) override { return inner_state(::std::move(sender), b); } + task_scheduler get_completion_scheduler() const override { + return task_scheduler(::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + ::beman::execution::get_env(this->sender))); + } + }; + ::beman::execution::detail::poly inner_sender; + + public: + using sender_concept = ::beman::execution::sender_tag; + using completion_signatures = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>; + + template + static consteval auto get_completion_signatures() noexcept -> completion_signatures { + return {}; + } + + template <::beman::execution::scheduler S> + explicit sender(S&& s) : inner_sender(static_cast*>(nullptr), ::std::forward(s)) {} + sender(sender&&) = default; + sender(const sender&) = default; + + template <::beman::execution::receiver R> + auto connect(R&& r) -> state { + return state(::std::forward(r), this->inner_sender); + } + + auto get_env() const noexcept -> env { return env(this); } + }; + + struct base { + virtual ~base() = default; + virtual sender schedule() = 0; + virtual base* move(void*) = 0; + virtual base* clone(void*) const = 0; + virtual bool equals(const base*) const = 0; + }; + template <::beman::execution::scheduler Scheduler> + struct concrete : base { + Scheduler scheduler; + + template + requires ::beman::execution::scheduler<::std::remove_cvref_t> + explicit concrete(S&& s) : scheduler(::std::forward(s)) {} + sender schedule() override { return sender(this->scheduler); } + base* move(void* buffer) override { return new (buffer) concrete(::std::move(*this)); } + base* clone(void* buffer) const override { return new (buffer) concrete(*this); } + bool equals(const base* o) const override { + auto other{dynamic_cast(o)}; + return other ? this->scheduler == other->scheduler : false; + } + }; + + ::beman::execution::detail::poly scheduler; + + public: + using scheduler_concept = ::beman::execution::scheduler_tag; + + template > + requires(not ::std::same_as>) && + ::beman::execution::scheduler<::std::remove_cvref_t> && + ::beman::execution::detail::infallible_scheduler<::std::remove_cvref_t, ::beman::execution::env<>> + explicit task_scheduler(S&& s, Allocator = {}) + : scheduler(static_cast>*>(nullptr), ::std::forward(s)) {} + task_scheduler(task_scheduler&&) = default; + task_scheduler(const task_scheduler&) = default; + template + task_scheduler(const task_scheduler& other, Allocator) : scheduler(other.scheduler) {} + auto operator=(const task_scheduler&) -> task_scheduler& = default; + ~task_scheduler() = default; + + auto schedule() -> sender { return this->scheduler->schedule(); } + auto operator==(const task_scheduler&) const -> bool = default; + + template + requires(not ::std::same_as) && ::beman::execution::scheduler + auto operator==(const Sched& other) const -> bool { + return *this == task_scheduler(other); + } +}; +static_assert(::beman::execution::scheduler); + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/task.hpp b/include/beman/execution/task.hpp index 6f3c475f..a6a776b5 100644 --- a/include/beman/execution/task.hpp +++ b/include/beman/execution/task.hpp @@ -11,12 +11,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include // ---------------------------------------------------------------------------- diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 102cbeaf..8c24d76e 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -195,12 +195,14 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/error_types_of.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/find_allocator.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/handle.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/infallible_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/logger.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/poly.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/promise_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/state_rep.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/stop_source.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/sub_visit.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/task/task_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/then.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/transform_sender.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/type_list.hpp diff --git a/tests/beman/execution/CMakeLists.txt b/tests/beman/execution/CMakeLists.txt index 5f30e54d..d887c6a7 100644 --- a/tests/beman/execution/CMakeLists.txt +++ b/tests/beman/execution/CMakeLists.txt @@ -11,6 +11,8 @@ list( APPEND execution_tests allocator-requirements-general.test task-allocator_support.test + task-infallible_scheduler.test + task_scheduler.test exec-affine-on.test exec-associate.test exec-awaitable.test diff --git a/tests/beman/execution/task-infallible_scheduler.test.cpp b/tests/beman/execution/task-infallible_scheduler.test.cpp new file mode 100644 index 00000000..a5711d8d --- /dev/null +++ b/tests/beman/execution/task-infallible_scheduler.test.cpp @@ -0,0 +1,59 @@ +// tests/beman/execution/task-infallible_scheduler.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +// ---------------------------------------------------------------------------- + +namespace { +template +struct sender { + using sender_concept = test_std::sender_tag; + using completion_signatures = test_std::completion_signatures; + + struct env { + auto query(const test_std::get_completion_scheduler_t&) const noexcept -> Scheduler { + return {}; + } + }; + + template + static consteval auto get_completion_signatures() noexcept -> completion_signatures { + return {}; + } + static constexpr auto get_env() noexcept -> env { return {}; } +}; + +template +struct scheduler { + using scheduler_concept = test_std::scheduler_tag; + + auto schedule() const noexcept -> sender { return {}; } + auto operator==(const scheduler&) const -> bool = default; +}; + +struct non_scheduler {}; + +struct stoppable_env { + auto query(const test_std::get_stop_token_t&) const noexcept -> test_std::inplace_stop_token { return {}; } +}; +} // namespace + +// ---------------------------------------------------------------------------- + +TEST(task_infallible_scheduler) { + using value_scheduler = scheduler; + using stoppable_scheduler = scheduler; + using reversed_scheduler = scheduler; + using error_scheduler = scheduler; + using default_unstoppable_env = test_std::env<>; + + static_assert(test_detail::completes_with); + static_assert(test_detail::infallible_scheduler); + static_assert(!test_detail::infallible_scheduler); + static_assert(test_detail::infallible_scheduler); + static_assert(test_detail::infallible_scheduler); + static_assert(!test_detail::infallible_scheduler); + static_assert(!test_detail::infallible_scheduler); +} diff --git a/tests/beman/execution/task_scheduler.test.cpp b/tests/beman/execution/task_scheduler.test.cpp new file mode 100644 index 00000000..34df17e8 --- /dev/null +++ b/tests/beman/execution/task_scheduler.test.cpp @@ -0,0 +1,268 @@ +// tests/beman/execution/task_scheduler.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace { +void unexpected_call_assert(const char* msg) { ASSERT(nullptr == msg); } + +struct thread_context { + enum class complete : char { success, never }; + struct base { + base* next{}; + base() = default; + base(base&&) = delete; + base(const base&) = delete; + virtual ~base() = default; + auto operator=(base&&) = delete; + auto operator=(const base&) = delete; + virtual void complete() = 0; + }; + + ::std::mutex mutex; + ::std::condition_variable condition; + bool done{false}; + base* work{}; + ::std::thread thread; + + auto get_work() -> base* { + ::std::unique_lock guard(this->mutex); + condition.wait(guard, [this] { return this->done || this->work; }); + base* rc{this->work}; + if (rc) { + this->work = rc->next; + } + return rc; + } + + auto enqueue(base* w) -> void { + { + ::std::lock_guard guard(this->mutex); + w->next = this->work; + this->work = w; + } + this->condition.notify_one(); + } + + thread_context() + : thread([this] { + while (auto w{this->get_work()}) { + w->complete(); + } + }) {} + thread_context(thread_context&&) = delete; + thread_context(const thread_context&) = delete; + ~thread_context() { + this->stop(); + this->thread.join(); + } + auto operator=(thread_context&&) -> thread_context& = delete; + auto operator=(const thread_context&) -> thread_context& = delete; + + struct scheduler { + using scheduler_concept = test_std::scheduler_tag; + thread_context* context; + complete cmpl{complete::success}; + auto operator==(const scheduler&) const -> bool = default; + + template + struct state : base { + struct stopper { + state* st; + auto operator()() noexcept -> void { + auto self{this->st}; + self->callback.reset(); + test_std::set_stopped(::std::move(self->receiver)); + } + }; + using operation_state_concept = test_std::operation_state_tag; + using token_t = decltype(test_std::get_stop_token(test_std::get_env(::std::declval()))); + using callback_t = test_std::stop_callback_for_t; + + thread_context* ctxt; + ::std::remove_cvref_t receiver; + thread_context::complete cmpl; + ::std::optional callback; + + template + state(auto c, R&& r, thread_context::complete cm) : ctxt(c), receiver(::std::forward(r)), cmpl(cm) {} + auto start() & noexcept -> void { + callback.emplace(test_std::get_stop_token(test_std::get_env(this->receiver)), stopper{this}); + if (cmpl != thread_context::complete::never) { + this->ctxt->enqueue(this); + } + } + void complete() override { + this->callback.reset(); + test_std::set_value(::std::move(this->receiver)); + } + }; + + struct env { + thread_context* ctxt; + auto query(const test_std::get_completion_scheduler_t&) const noexcept -> scheduler { + return scheduler{ctxt}; + } + }; + + struct sender { + using sender_concept = test_std::sender_tag; + using completion_signatures = test_std::completion_signatures; + + template + static consteval auto get_completion_signatures() -> completion_signatures { + return {}; + } + + thread_context* ctxt; + thread_context::complete cmpl; + + template + auto connect(Receiver&& receiver) -> state { + static_assert(test_std::operation_state>); + return state(this->ctxt, ::std::forward(receiver), this->cmpl); + } + auto get_env() const noexcept -> env { return {this->ctxt}; } + }; + static_assert(test_std::sender); + + auto schedule() noexcept -> sender { return sender{this->context, this->cmpl}; } + }; + static_assert(test_std::scheduler); + + auto get_scheduler(complete cmpl = complete::success) -> scheduler { return scheduler{this, cmpl}; } + + auto stop() -> void { + { + ::std::lock_guard guard(this->mutex); + this->done = true; + } + this->condition.notify_one(); + } +}; +static_assert(test_detail::infallible_scheduler>); + +enum class stop_result : char { none, success, failure, stopped }; + +template +struct stop_env { + Token token; + auto query(test_std::get_stop_token_t) const noexcept { return this->token; } +}; +template +stop_env(Token&&) -> stop_env<::std::remove_cvref_t>; + +template +struct stop_receiver { + using receiver_concept = test_std::receiver_tag; + Token token; + stop_result& result; + ::std::latch* completed{}; + + auto get_env() const noexcept { return stop_env{this->token}; } + + auto set_value(auto&&...) && noexcept -> void { + this->result = stop_result::success; + if (this->completed) { + this->completed->count_down(); + } + } + auto set_error(auto&&) && noexcept -> void { + this->result = stop_result::failure; + if (this->completed) { + this->completed->count_down(); + } + } + auto set_stopped() && noexcept -> void { + this->result = stop_result::stopped; + if (this->completed) { + this->completed->count_down(); + } + } +}; +template +stop_receiver(Token&&, stop_result&, ::std::latch* = nullptr) -> stop_receiver<::std::remove_cvref_t>; +static_assert(test_std::receiver>); +} // namespace + +// ---------------------------------------------------------------------------- + +TEST(task_scheduler) { + try { + static_assert(test_std::scheduler); + + thread_context ctxt1; + thread_context ctxt2; + + ASSERT(ctxt1.get_scheduler() == ctxt1.get_scheduler()); + ASSERT(ctxt2.get_scheduler() == ctxt2.get_scheduler()); + ASSERT(ctxt1.get_scheduler() != ctxt2.get_scheduler()); + + test_detail::task_scheduler sched1(ctxt1.get_scheduler()); + test_detail::task_scheduler sched2(ctxt2.get_scheduler()); + ASSERT(sched1 == sched1); + ASSERT(sched2 == sched2); + ASSERT(sched1 != sched2); + + test_detail::task_scheduler copy(sched1); + ASSERT(copy == sched1); + ASSERT(copy != sched2); + test_detail::task_scheduler move(::std::move(copy)); + ASSERT(move == sched1); + ASSERT(move != sched2); + + copy = sched2; + ASSERT(copy == sched2); + ASSERT(copy != sched1); + + move = ::std::move(copy); + ASSERT(move == sched2); + ASSERT(move != sched1); + + ::std::atomic<::std::thread::id> id1{}; + ::std::atomic<::std::thread::id> id2{}; + test_std::sync_wait(test_std::schedule(sched1) | test_std::then([&id1] { id1 = ::std::this_thread::get_id(); })); + test_std::sync_wait(test_std::schedule(sched2) | test_std::then([&id2] { id2 = ::std::this_thread::get_id(); })); + ASSERT(id1 != id2); + test_std::sync_wait(test_std::schedule(test_detail::task_scheduler(sched1)) | + test_std::then([&id1] { ASSERT(id1 == ::std::this_thread::get_id()); })); + test_std::sync_wait(test_std::schedule(test_detail::task_scheduler(sched2)) | + test_std::then([&id2] { ASSERT(id2 == ::std::this_thread::get_id()); })); + + { + test_std::inplace_stop_source source; + stop_result result{stop_result::none}; + auto state{test_std::connect(test_std::schedule(ctxt1.get_scheduler(thread_context::complete::never)), + stop_receiver{source.get_token(), result})}; + ASSERT(result == stop_result::none); + test_std::start(state); + ASSERT(result == stop_result::none); + source.request_stop(); + ASSERT(result == stop_result::stopped); + } + { + ::std::latch completed{1}; + stop_result result{stop_result::none}; + auto state{test_std::connect( + test_std::schedule(test_detail::task_scheduler(ctxt1.get_scheduler(thread_context::complete::success))), + stop_receiver{test_std::never_stop_token(), result, &completed})}; + ASSERT(result == stop_result::none); + test_std::start(state); + completed.wait(); + ASSERT(result == stop_result::success); + } + } catch (...) { + unexpected_call_assert("no exception should escape to main"); + } +} From 2a1a968324817ec482370f2e50ffb92190e3c0f3 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Sat, 23 May 2026 18:06:51 -0500 Subject: [PATCH 06/10] fixed missing modules import --- .../detail/task/infallible_scheduler.hpp | 27 ++++++++++++++- .../execution/detail/task/task_scheduler.hpp | 34 ++++++++++++++++++- .../task-infallible_scheduler.test.cpp | 5 +++ tests/beman/execution/task_scheduler.test.cpp | 5 +++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/include/beman/execution/detail/task/infallible_scheduler.hpp b/include/beman/execution/detail/task/infallible_scheduler.hpp index ec5b3935..a218fe52 100644 --- a/include/beman/execution/detail/task/infallible_scheduler.hpp +++ b/include/beman/execution/detail/task/infallible_scheduler.hpp @@ -4,9 +4,34 @@ #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_INFALLIBLE_SCHEDULER #define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_INFALLIBLE_SCHEDULER -#include +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else #include #include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.completion_signatures; +import beman.execution.detail.completion_signatures_of_t; +import beman.execution.detail.env; +import beman.execution.detail.schedule; +import beman.execution.detail.scheduler; +import beman.execution.detail.set_stopped; +import beman.execution.detail.set_value; +import beman.execution.detail.stop_token_of_t; +import beman.execution.detail.unstoppable_token; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/task/task_scheduler.hpp b/include/beman/execution/detail/task/task_scheduler.hpp index 12d6511c..a2a9083c 100644 --- a/include/beman/execution/detail/task/task_scheduler.hpp +++ b/include/beman/execution/detail/task/task_scheduler.hpp @@ -4,13 +4,45 @@ #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SCHEDULER #define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_SCHEDULER -#include +#include #include #include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else #include #include #include #include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.completion_signatures; +import beman.execution.detail.connect; +import beman.execution.detail.env; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.get_env; +import beman.execution.detail.operation_state; +import beman.execution.detail.receiver; +import beman.execution.detail.schedule; +import beman.execution.detail.scheduler; +import beman.execution.detail.scheduler_tag; +import beman.execution.detail.sender; +import beman.execution.detail.set_value; +import beman.execution.detail.start; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // ---------------------------------------------------------------------------- diff --git a/tests/beman/execution/task-infallible_scheduler.test.cpp b/tests/beman/execution/task-infallible_scheduler.test.cpp index a5711d8d..9fe39812 100644 --- a/tests/beman/execution/task-infallible_scheduler.test.cpp +++ b/tests/beman/execution/task-infallible_scheduler.test.cpp @@ -2,6 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#ifdef BEMAN_HAS_MODULES +import beman.execution; +#else +#include +#endif #include // ---------------------------------------------------------------------------- diff --git a/tests/beman/execution/task_scheduler.test.cpp b/tests/beman/execution/task_scheduler.test.cpp index 34df17e8..4bcf33eb 100644 --- a/tests/beman/execution/task_scheduler.test.cpp +++ b/tests/beman/execution/task_scheduler.test.cpp @@ -2,6 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#ifdef BEMAN_HAS_MODULES +import beman.execution; +#else +#include +#endif #include #include #include From b736bdda3ba42782302c7d620bc259855920cde3 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Sat, 23 May 2026 18:37:00 -0500 Subject: [PATCH 07/10] reorder imports for task_scheduler.test --- tests/beman/execution/task_scheduler.test.cpp | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/tests/beman/execution/task_scheduler.test.cpp b/tests/beman/execution/task_scheduler.test.cpp index 4bcf33eb..c7cec720 100644 --- a/tests/beman/execution/task_scheduler.test.cpp +++ b/tests/beman/execution/task_scheduler.test.cpp @@ -1,21 +1,39 @@ // tests/beman/execution/task_scheduler.test.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include -#ifdef BEMAN_HAS_MODULES -import beman.execution; -#else -#include -#endif -#include #include -#include +#include #include #include +#include #include +#include #include #include +#include #include +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include // ---------------------------------------------------------------------------- From d19b37d4dbfd88d28dd6dd64e1fd8f9e159a5530 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Sat, 23 May 2026 18:51:55 -0500 Subject: [PATCH 08/10] fix some errors in format --- .../task-infallible_scheduler.test.cpp | 1 + tests/beman/execution/task_scheduler.test.cpp | 29 ++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/beman/execution/task-infallible_scheduler.test.cpp b/tests/beman/execution/task-infallible_scheduler.test.cpp index 9fe39812..e1e95f4a 100644 --- a/tests/beman/execution/task-infallible_scheduler.test.cpp +++ b/tests/beman/execution/task-infallible_scheduler.test.cpp @@ -1,6 +1,7 @@ // tests/beman/execution/task-infallible_scheduler.test.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #ifdef BEMAN_HAS_MODULES import beman.execution; diff --git a/tests/beman/execution/task_scheduler.test.cpp b/tests/beman/execution/task_scheduler.test.cpp index c7cec720..69614b27 100644 --- a/tests/beman/execution/task_scheduler.test.cpp +++ b/tests/beman/execution/task_scheduler.test.cpp @@ -110,13 +110,13 @@ struct thread_context { } }; using operation_state_concept = test_std::operation_state_tag; - using token_t = decltype(test_std::get_stop_token(test_std::get_env(::std::declval()))); - using callback_t = test_std::stop_callback_for_t; + using token_t = decltype(test_std::get_stop_token(test_std::get_env(::std::declval()))); + using callback_t = test_std::stop_callback_for_t; - thread_context* ctxt; + thread_context* ctxt; ::std::remove_cvref_t receiver; - thread_context::complete cmpl; - ::std::optional callback; + thread_context::complete cmpl; + ::std::optional callback; template state(auto c, R&& r, thread_context::complete cm) : ctxt(c), receiver(::std::forward(r)), cmpl(cm) {} @@ -134,7 +134,8 @@ struct thread_context { struct env { thread_context* ctxt; - auto query(const test_std::get_completion_scheduler_t&) const noexcept -> scheduler { + auto query(const test_std::get_completion_scheduler_t&) const noexcept + -> scheduler { return scheduler{ctxt}; } }; @@ -189,8 +190,8 @@ stop_env(Token&&) -> stop_env<::std::remove_cvref_t>; template struct stop_receiver { using receiver_concept = test_std::receiver_tag; - Token token; - stop_result& result; + Token token; + stop_result& result; ::std::latch* completed{}; auto get_env() const noexcept { return stop_env{this->token}; } @@ -255,8 +256,10 @@ TEST(task_scheduler) { ::std::atomic<::std::thread::id> id1{}; ::std::atomic<::std::thread::id> id2{}; - test_std::sync_wait(test_std::schedule(sched1) | test_std::then([&id1] { id1 = ::std::this_thread::get_id(); })); - test_std::sync_wait(test_std::schedule(sched2) | test_std::then([&id2] { id2 = ::std::this_thread::get_id(); })); + test_std::sync_wait(test_std::schedule(sched1) | + test_std::then([&id1] { id1 = ::std::this_thread::get_id(); })); + test_std::sync_wait(test_std::schedule(sched2) | + test_std::then([&id2] { id2 = ::std::this_thread::get_id(); })); ASSERT(id1 != id2); test_std::sync_wait(test_std::schedule(test_detail::task_scheduler(sched1)) | test_std::then([&id1] { ASSERT(id1 == ::std::this_thread::get_id()); })); @@ -277,9 +280,9 @@ TEST(task_scheduler) { { ::std::latch completed{1}; stop_result result{stop_result::none}; - auto state{test_std::connect( - test_std::schedule(test_detail::task_scheduler(ctxt1.get_scheduler(thread_context::complete::success))), - stop_receiver{test_std::never_stop_token(), result, &completed})}; + auto state{test_std::connect(test_std::schedule(test_detail::task_scheduler( + ctxt1.get_scheduler(thread_context::complete::success))), + stop_receiver{test_std::never_stop_token(), result, &completed})}; ASSERT(result == stop_result::none); test_std::start(state); completed.wait(); From 49d88564327a1e8e1a06daab0067d4effc52caf6 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Sat, 23 May 2026 20:00:30 -0500 Subject: [PATCH 09/10] fix some errors --- .../execution/detail/task/allocator_support.hpp | 15 ++++++--------- include/beman/execution/detail/task/poly.hpp | 5 +++++ .../execution/detail/task/task_scheduler.hpp | 8 ++++---- .../execution/task-infallible_scheduler.test.cpp | 7 ++++++- tests/beman/execution/task_scheduler.test.cpp | 9 +++++++-- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/beman/execution/detail/task/allocator_support.hpp b/include/beman/execution/detail/task/allocator_support.hpp index dc2c2b88..da1ba67a 100644 --- a/include/beman/execution/detail/task/allocator_support.hpp +++ b/include/beman/execution/detail/task/allocator_support.hpp @@ -31,9 +31,8 @@ template using allocator_support_alloc_t = std::remove_cvref_t; template -using allocator_support_palloc_t = - typename std::allocator_traits>::template rebind_alloc< - allocator_support_allocation_unit>; +using allocator_support_palloc_t = typename std::allocator_traits< + allocator_support_alloc_t>::template rebind_alloc; template concept allocator_support_allocator_like = requires { typename allocator_support_alloc_t::value_type; }; @@ -88,7 +87,7 @@ struct allocator_support { using palloc_traits = std::allocator_traits; allocator_support_header* header{allocator_support::get_header(ptr, size)}; - auto* palloc_ptr{ + auto* palloc_ptr{ ::std::launder(reinterpret_cast(static_cast(ptr) + header->palloc_offset))}; PAlloc palloc{*palloc_ptr}; std::size_t count{header->count}; @@ -104,8 +103,8 @@ struct allocator_support { palloc_t palloc{alloc}; std::size_t header_offset{allocator_support::header_offset(size)}; - std::size_t palloc_offset{allocator_support::align_up(header_offset + sizeof(allocator_support_header), - alignof(palloc_t))}; + std::size_t palloc_offset{ + allocator_support::align_up(header_offset + sizeof(allocator_support_header), alignof(palloc_t))}; std::size_t count{(palloc_offset + sizeof(palloc_t) + sizeof(allocator_support_allocation_unit) - 1u) / sizeof(allocator_support_allocation_unit)}; @@ -121,9 +120,7 @@ struct allocator_support { return ptr; } - static void* operator new(std::size_t size) { - return allocator_support::allocate(size, Allocator{}); - } + static void* operator new(std::size_t size) { return allocator_support::allocate(size, Allocator{}); } template requires allocator_support_allocator_arg diff --git a/include/beman/execution/detail/task/poly.hpp b/include/beman/execution/detail/task/poly.hpp index 9fd5cfb7..0ff5d18b 100644 --- a/include/beman/execution/detail/task/poly.hpp +++ b/include/beman/execution/detail/task/poly.hpp @@ -4,11 +4,16 @@ #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_POLY #define INCLUDED_BEMAN_EXECUTION_DETAIL_TASK_POLY +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else #include #include #include #include #include +#endif // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/task/task_scheduler.hpp b/include/beman/execution/detail/task/task_scheduler.hpp index a2a9083c..48299a93 100644 --- a/include/beman/execution/detail/task/task_scheduler.hpp +++ b/include/beman/execution/detail/task/task_scheduler.hpp @@ -74,7 +74,8 @@ class task_scheduler { }; template <::beman::execution::sender Sender> struct concrete : base { - using state_t = decltype(::beman::execution::connect(::std::declval(), ::std::declval())); + using state_t = + decltype(::beman::execution::connect(::std::declval(), ::std::declval())); state_t state; template <::beman::execution::sender S> @@ -85,8 +86,7 @@ class task_scheduler { ::beman::execution::detail::poly state; template <::beman::execution::sender S> - inner_state(S&& s, state_base* b) - : state(static_cast*>(nullptr), ::std::forward(s), b) {} + inner_state(S&& s, state_base* b) : state(static_cast*>(nullptr), ::std::forward(s), b) {} void start() { this->state->start(); } }; @@ -207,7 +207,7 @@ class task_scheduler { template task_scheduler(const task_scheduler& other, Allocator) : scheduler(other.scheduler) {} auto operator=(const task_scheduler&) -> task_scheduler& = default; - ~task_scheduler() = default; + ~task_scheduler() = default; auto schedule() -> sender { return this->scheduler->schedule(); } auto operator==(const task_scheduler&) const -> bool = default; diff --git a/tests/beman/execution/task-infallible_scheduler.test.cpp b/tests/beman/execution/task-infallible_scheduler.test.cpp index e1e95f4a..9a88cbe4 100644 --- a/tests/beman/execution/task-infallible_scheduler.test.cpp +++ b/tests/beman/execution/task-infallible_scheduler.test.cpp @@ -1,8 +1,13 @@ // tests/beman/execution/task-infallible_scheduler.test.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include +#include #include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif #ifdef BEMAN_HAS_MODULES import beman.execution; #else diff --git a/tests/beman/execution/task_scheduler.test.cpp b/tests/beman/execution/task_scheduler.test.cpp index 69614b27..0c5dee5b 100644 --- a/tests/beman/execution/task_scheduler.test.cpp +++ b/tests/beman/execution/task_scheduler.test.cpp @@ -1,18 +1,23 @@ // tests/beman/execution/task_scheduler.test.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else #include #include +#include #include #include #include #include -#include #include #include #include #include -#include +#endif #ifdef BEMAN_HAS_MODULES import beman.execution; #else From e827e588b3b995af009b715ba2d5664d02682c92 Mon Sep 17 00:00:00 2001 From: JorgeV92 Date: Sat, 23 May 2026 20:13:47 -0500 Subject: [PATCH 10/10] fix format --- tests/beman/execution/task-allocator_support.test.cpp | 11 ++++------- tests/beman/execution/task_scheduler.test.cpp | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/beman/execution/task-allocator_support.test.cpp b/tests/beman/execution/task-allocator_support.test.cpp index 6e81f89f..5ce33d4f 100644 --- a/tests/beman/execution/task-allocator_support.test.cpp +++ b/tests/beman/execution/task-allocator_support.test.cpp @@ -78,14 +78,11 @@ concept supports_misplaced_allocator = requires(test_resource& resource) { }; template -concept supports_resource_pointer_allocator = requires(test_resource& resource) { - T::operator new(sizeof(T), std::allocator_arg, &resource); -}; +concept supports_resource_pointer_allocator = + requires(test_resource& resource) { T::operator new(sizeof(T), std::allocator_arg, &resource); }; template -concept constructs_pmr_byte_allocator = requires(Alloc& alloc) { - std::pmr::polymorphic_allocator{alloc}; -}; +concept constructs_pmr_byte_allocator = requires(Alloc& alloc) { std::pmr::polymorphic_allocator{alloc}; }; } // namespace // ---------------------------------------------------------------------------- @@ -109,7 +106,7 @@ TEST(allocator_support) { [[maybe_unused]] std::unique_ptr unused(new type{}); - test_resource resource{}; + test_resource resource{}; std::pmr::polymorphic_allocator allocator{&resource}; ASSERT(resource.outstanding == 0u); type* ptr{new (std::allocator_arg, allocator) type{}}; diff --git a/tests/beman/execution/task_scheduler.test.cpp b/tests/beman/execution/task_scheduler.test.cpp index 0c5dee5b..4dc61c8f 100644 --- a/tests/beman/execution/task_scheduler.test.cpp +++ b/tests/beman/execution/task_scheduler.test.cpp @@ -286,8 +286,8 @@ TEST(task_scheduler) { ::std::latch completed{1}; stop_result result{stop_result::none}; auto state{test_std::connect(test_std::schedule(test_detail::task_scheduler( - ctxt1.get_scheduler(thread_context::complete::success))), - stop_receiver{test_std::never_stop_token(), result, &completed})}; + ctxt1.get_scheduler(thread_context::complete::success))), + stop_receiver{test_std::never_stop_token(), result, &completed})}; ASSERT(result == stop_result::none); test_std::start(state); completed.wait();