From a2ca563b3ec4953881dd457eefdff5371764c6cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Thu, 5 Mar 2026 01:30:37 +0100 Subject: [PATCH 01/16] started to implement the changes for P3826 --- Makefile | 19 +++- .../detail/get_completion_domain.hpp | 42 ++++++++ include/beman/execution/detail/hide_query.hpp | 48 +++++++++ .../execution/detail/indeterminate_domain.hpp | 21 ++++ include/beman/execution/detail/try_query.hpp | 42 ++++++++ include/beman/execution/execution.hpp | 2 + src/beman/execution/CMakeLists.txt | 50 ++++++---- src/beman/execution/execution.cppm | 98 ++++++++++--------- .../execution/get_completion_domain.cppm | 12 +++ src/beman/execution/hide_query.cppm | 11 +++ src/beman/execution/indeterminate_domain.cppm | 11 +++ src/beman/execution/try_query.cppm | 11 +++ tests/beman/execution/CMakeLists.txt | 13 +++ .../execution/exec-queries-expos.test.cpp | 96 ++++++++++++++++++ .../execution/exec.get.compl.domain.test.cpp | 32 ++++++ tests/beman/execution/execution-syn.test.cpp | 40 ++++++++ 16 files changed, 478 insertions(+), 70 deletions(-) create mode 100644 include/beman/execution/detail/get_completion_domain.hpp create mode 100644 include/beman/execution/detail/hide_query.hpp create mode 100644 include/beman/execution/detail/indeterminate_domain.hpp create mode 100644 include/beman/execution/detail/try_query.hpp create mode 100644 src/beman/execution/get_completion_domain.cppm create mode 100644 src/beman/execution/hide_query.cppm create mode 100644 src/beman/execution/indeterminate_domain.cppm create mode 100644 src/beman/execution/try_query.cppm create mode 100644 tests/beman/execution/exec-queries-expos.test.cpp create mode 100644 tests/beman/execution/exec.get.compl.domain.test.cpp diff --git a/Makefile b/Makefile index 0ad2487e..ec086b8b 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ SANITIZERS := run # SANITIZERS += asan # TODO: tsan msan # endif -.PHONY: default release debug doc run update check ce todo distclean clean codespell clang-tidy build test install all format unstage $(SANITIZERS) module build-module test-module build-interface run-ci +.PHONY: default release debug doc run update check ce todo distclean clean codespell clang-tidy build test install all format unstage $(SANITIZERS) module build-module test-module build-interface run-ci dev dev-test dev-build dev-config SYSROOT ?= TOOLCHAIN ?= @@ -118,6 +118,23 @@ doc: ./bin/mk-doc.py docs/*.mds doxygen docs/Doxyfile +LLVM_VERSION=22.1.0 +DEV_DIR=build/dev-$(shell uname -s) +TESTCASE = * +DEV_TEST_OPTION=-DBEMAN_EXECUTION_TEST_CASE=$(TESTCASE) + +dev-config: + PATH=/opt/llvm-$(LLVM_VERSION)/bin:$$PATH CXX=clang++ cmake -B $(DEV_DIR) -G Ninja -DBEMAN_EXECUTION_BUILD_EXAMPLES=OFF -DBEMAN_EXECUTION_INSTALL_CONFIG_FILE_PACKAGE=OFF $(DEV_TEST_OPTION) + +dev-build: dev-config + PATH=/opt/llvm-$(LLVM_VERSION)/bin:$$PATH CXX=clang++ cmake --build $(DEV_DIR) + +dev-test: dev-build + PATH=/opt/llvm-$(LLVM_VERSION)/bin:$$PATH CXX=clang++ ctest --test-dir $(DEV_DIR) -R beman.execution.$(TESTCASE).test + +dev: dev-test + + # $(SANITIZERS): # $(MAKE) SANITIZER=$@ diff --git a/include/beman/execution/detail/get_completion_domain.hpp b/include/beman/execution/detail/get_completion_domain.hpp new file mode 100644 index 00000000..930318ee --- /dev/null +++ b/include/beman/execution/detail/get_completion_domain.hpp @@ -0,0 +1,42 @@ +// include/beman/execution/detail/get_completion_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.set_error; +import beman.execution.detail.set_stopped; +import beman.execution.detail.set_value; +#else +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template + requires(::std::same_as || ::std::same_as || + ::std::same_as || + ::std::same_as) +struct get_completion_domain_t {}; +} // namespace beman::execution::detail + +namespace beman::execution { +template +using get_completion_domain_t = detail::get_completion_domain_t; +template +inline constexpr get_completion_domain_t get_completion_domain{}; +} // namespace beman::execution + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/detail/hide_query.hpp b/include/beman/execution/detail/hide_query.hpp new file mode 100644 index 00000000..ebb0d74b --- /dev/null +++ b/include/beman/execution/detail/hide_query.hpp @@ -0,0 +1,48 @@ +// include/beman/execution/detail/hide_query.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_QUERY +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_QUERY + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.queryable; +import beman.execution.detail.get_domain; +import beman.execution.detail.get_scheduler; +#else +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template <::beman::execution::detail::queryable Q> +struct hide_query_t { + template + auto query(Tag&& tag, Args&&... args) const noexcept -> decltype(auto) { + return q.query(::std::forward(tag), ::std::forward(args)...); + } + template + auto query(::beman::execution::get_domain_t, Args&&... args) const noexcept -> void = delete; + template + auto query(::beman::execution::get_scheduler_t, Args&&... args) const noexcept -> void = delete; + + const Q& q; +}; + +template <::beman::execution::detail::queryable Q> +auto hide_query(const Q& q) noexcept { + return ::beman::execution::detail::hide_query_t{q}; +} +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/detail/indeterminate_domain.hpp b/include/beman/execution/detail/indeterminate_domain.hpp new file mode 100644 index 00000000..e0be40fa --- /dev/null +++ b/include/beman/execution/detail/indeterminate_domain.hpp @@ -0,0 +1,21 @@ +// include/beman/execution/detail/indeterminate_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template +struct indeterminate_domain; +} + +namespace beman::execution { +template +using indeterminate_domain = detail::indeterminate_domain; +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/detail/try_query.hpp b/include/beman/execution/detail/try_query.hpp new file mode 100644 index 00000000..352c4698 --- /dev/null +++ b/include/beman/execution/detail/try_query.hpp @@ -0,0 +1,42 @@ +// include/beman/execution/detail/try_query.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_TRY_QUERY +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_TRY_QUERY + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.queryable; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template <::beman::execution::detail::queryable Q, typename Tag, typename... Args> + requires requires(const Q& q, Tag&& tag, Args&&... args) { + q.query(::std::forward(tag), ::std::forward(args)...); + } +auto try_query(const Q& q, Tag&& tag, Args&&... args) noexcept -> decltype(auto) { + return q.query(::std::forward(tag), ::std::forward(args)...); +} + +template <::beman::execution::detail::queryable Q, typename Tag, typename... Args> + requires( + not requires(const Q& q, Tag&& tag, Args&&... args) { + q.query(::std::forward(tag), ::std::forward(args)...); + } && requires(const Q& q, Tag&& tag) { q.query(::std::forward(tag)); }) +auto try_query(const Q& q, Tag&& tag, Args&&...) noexcept -> decltype(auto) { + return q.query(::std::forward(tag)); +} +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/execution.hpp b/include/beman/execution/execution.hpp index b0225977..6d6f5e54 100644 --- a/include/beman/execution/execution.hpp +++ b/include/beman/execution/execution.hpp @@ -20,6 +20,7 @@ import beman.execution.detail.counting_scope; import beman.execution.detail.env; import beman.execution.detail.forwarding_query; import beman.execution.detail.get_allocator; +import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_delegation_scheduler; @@ -73,6 +74,7 @@ import beman.execution.detail.write_env; #include #include #include +#include #include #include #include diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 1950de1d..48e6015f 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -82,6 +82,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_allocator.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_await_completion_adaptor.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_awaiter.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_completion_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_completion_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_completion_signatures.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_delegation_scheduler.hpp @@ -93,8 +94,10 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_stop_token.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/hide_query.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/immovable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/impls_for.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indeterminate_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indices_for.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indirect_meta_apply.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/inplace_stop_source.hpp @@ -183,6 +186,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/tag_of_t.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/try_query.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/type_list.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/unspecified_promise.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/unstoppable_token.hpp @@ -206,8 +210,6 @@ if(BEMAN_USE_MODULES) PUBLIC FILE_SET CXX_MODULES FILES - execution.cppm - execution-detail.cppm affine_on.cppm allocator_aware_move.cppm almost_scheduler.cppm @@ -232,19 +234,19 @@ if(BEMAN_USE_MODULES) class_type.cppm completion_domain.cppm completion_signature.cppm + completion_signatures.cppm completion_signatures_for.cppm completion_signatures_of_t.cppm - completion_signatures.cppm completion_tag.cppm - connect_all_result.cppm + connect.cppm connect_all.cppm + connect_all_result.cppm connect_awaitable.cppm connect_result_t.cppm - connect.cppm continues_on.cppm + counting_scope.cppm counting_scope_base.cppm counting_scope_join.cppm - counting_scope.cppm decayed_same_as.cppm decayed_tuple.cppm decayed_type_list.cppm @@ -255,11 +257,13 @@ if(BEMAN_USE_MODULES) dependent_sender_error.cppm emplace_from.cppm enable_sender.cppm + env.cppm env_of_t.cppm env_promise.cppm env_type.cppm - env.cppm error_types_of_t.cppm + execution-detail.cppm + execution.cppm forward_like.cppm forwarding_query.cppm fwd_env.cppm @@ -267,19 +271,22 @@ if(BEMAN_USE_MODULES) get_allocator.cppm get_await_completion_adaptor.cppm get_awaiter.cppm + get_completion_domain.cppm get_completion_scheduler.cppm get_completion_signatures.cppm get_delegation_scheduler.cppm + get_domain.cppm get_domain_early.cppm get_domain_late.cppm - get_domain.cppm get_env.cppm get_scheduler.cppm get_stop_token.cppm has_as_awaitable.cppm has_completions.cppm + hide_query.cppm immovable.cppm impls_for.cppm + indeterminate_domain.cppm indices_for.cppm indirect_meta_apply.cppm inplace_stop_source.cppm @@ -296,8 +303,8 @@ if(BEMAN_USE_MODULES) make_sender.cppm matching_sig.cppm meta_combine.cppm - meta_contains.cppm meta_contain_same.cppm + meta_contains.cppm meta_filter.cppm meta_prepend.cppm meta_size.cppm @@ -307,58 +314,58 @@ if(BEMAN_USE_MODULES) movable_value.cppm nested_sender_has_affine_on.cppm never_stop_token.cppm - notify.cppm non_assignable.cppm nostopstate.cppm nothrow_callable.cppm - on_stop_request.cppm + notify.cppm on.cppm - operation_state_task.cppm + on_stop_request.cppm operation_state.cppm + operation_state_task.cppm product_type.cppm prop.cppm query_with_default.cppm queryable.cppm read_env.cppm - receiver_of.cppm receiver.cppm + receiver_of.cppm run_loop.cppm sched_attrs.cppm sched_env.cppm + schedule.cppm schedule_from.cppm schedule_result_t.cppm - schedule.cppm - scheduler_t.cppm scheduler.cppm + scheduler_t.cppm scope_association.cppm scope_token.cppm - sender_adaptor_closure.cppm + sender.cppm sender_adaptor.cppm + sender_adaptor_closure.cppm sender_awaitable.cppm sender_decompose.cppm sender_for.cppm sender_has_affine_on.cppm sender_in.cppm - sender.cppm sends_stopped.cppm set_error.cppm set_stopped.cppm set_value.cppm simple_allocator.cppm simple_counting_scope.cppm - single_sender_value_type.cppm single_sender.cppm + single_sender_value_type.cppm + spawn.cppm spawn_future.cppm spawn_get_allocator.cppm - spawn.cppm start.cppm starts_on.cppm state_type.cppm - stoppable_callback_for.cppm stop_callback_for_t.cppm stop_source.cppm stop_token_of_t.cppm stop_when.cppm + stoppable_callback_for.cppm stoppable_source.cppm stoppable_token.cppm stopped_as_error.cppm @@ -368,6 +375,7 @@ if(BEMAN_USE_MODULES) tag_of_t.cppm then.cppm transform_sender.cppm + try_query.cppm type_list.cppm unspecified_promise.cppm unstoppable_token.cppm @@ -376,8 +384,8 @@ if(BEMAN_USE_MODULES) valid_specialization.cppm value_types_of_t.cppm variant_or_empty.cppm - when_all_with_variant.cppm when_all.cppm + when_all_with_variant.cppm with_await_transform.cppm with_awaitable_senders.cppm write_env.cppm diff --git a/src/beman/execution/execution.cppm b/src/beman/execution/execution.cppm index f78a6fb7..6e76ab7e 100644 --- a/src/beman/execution/execution.cppm +++ b/src/beman/execution/execution.cppm @@ -7,76 +7,78 @@ module; export module beman.execution; -import beman.execution.detail.affine_on; -import beman.execution.detail.apply_sender; -import beman.execution.detail.as_awaitable; +//-dk:TODO import beman.execution.detail.split; +export import beman.execution.detail.affine_on; export import beman.execution.detail.associate; // [exec.associate] -import beman.execution.detail.bulk; -import beman.execution.detail.check_type_alias_exist; +export import beman.execution.detail.bulk; export import beman.execution.detail.completion_signatures; // [exec.util.cmplsig] export import beman.execution.detail.completion_signatures_of_t; // [exec.getcomplsigs], completion signatures -import beman.execution.detail.connect; +export import beman.execution.detail.connect; export import beman.execution.detail.connect_result_t; // [exec.connect], the connect sender algorithm -import beman.execution.detail.continues_on; -import beman.execution.detail.counting_scope; -import beman.execution.detail.default_domain; +export import beman.execution.detail.continues_on; +export import beman.execution.detail.counting_scope; +export import beman.execution.detail.default_domain; export import beman.execution.detail.env; export import beman.execution.detail.env_of_t; export import beman.execution.detail.error_types_of_t; // [exec.getcomplsigs], completion signatures -import beman.execution.detail.forwarding_query; -import beman.execution.detail.get_allocator; -import beman.execution.detail.get_await_completion_adaptor; +export import beman.execution.detail.forwarding_query; +export import beman.execution.detail.get_allocator; +export import beman.execution.detail.get_completion_domain; export import beman.execution.detail.get_completion_scheduler; export import beman.execution.detail.get_completion_signatures; // [exec.getcomplsigs], completion signatures -import beman.execution.detail.get_delegation_scheduler; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -import beman.execution.detail.get_scheduler; -import beman.execution.detail.get_stop_token; +export import beman.execution.detail.get_delegation_scheduler; +export import beman.execution.detail.get_domain; +export import beman.execution.detail.get_env; +export import beman.execution.detail.get_scheduler; +export import beman.execution.detail.get_stop_token; +export import beman.execution.detail.indeterminate_domain; export import beman.execution.detail.inplace_stop_source; // [stopsource.inplace], class inplace_stop_source -import beman.execution.detail.into_variant; +export import beman.execution.detail.into_variant; export import beman.execution.detail.just; -import beman.execution.detail.let; -import beman.execution.detail.never_stop_token; -import beman.execution.detail.nostopstate; -import beman.execution.detail.on; +export import beman.execution.detail.let; +export import beman.execution.detail.never_stop_token; +export import beman.execution.detail.on; export import beman.execution.detail.operation_state; // [exec.opstate], operation states -import beman.execution.detail.prop; -import beman.execution.detail.read_env; -import beman.execution.detail.run_loop; -import beman.execution.detail.schedule; -import beman.execution.detail.schedule_from; +export import beman.execution.detail.prop; +export import beman.execution.detail.read_env; +export import beman.execution.detail.run_loop; +export import beman.execution.detail.schedule; +export import beman.execution.detail.schedule_from; export import beman.execution.detail.schedule_result_t; export import beman.execution.detail.scheduler; // [exec.sched], schedulers export import beman.execution.detail.scheduler_t; export import beman.execution.detail.scope_association; // [exec.scope.concepts] export import beman.execution.detail.scope_token; // [exec.scope.concepts] -import beman.execution.detail.sender_adaptor_closure; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.set_value; -import beman.execution.detail.simple_counting_scope; -import beman.execution.detail.spawn; -import beman.execution.detail.spawn_future; -//-dk:TODO import beman.execution.detail.split; -import beman.execution.detail.start; -import beman.execution.detail.starts_on; +export import beman.execution.detail.set_error; +export import beman.execution.detail.set_stopped; +export import beman.execution.detail.set_value; +export import beman.execution.detail.simple_counting_scope; +export import beman.execution.detail.spawn; +export import beman.execution.detail.spawn_future; +export import beman.execution.detail.start; +export import beman.execution.detail.starts_on; export import beman.execution.detail.stop_callback_for_t; export import beman.execution.detail.stop_source; // [stopsource], class stop_source -import beman.execution.detail.stop_token_of_t; -import beman.execution.detail.stoppable_source; -import beman.execution.detail.stopped_as_error; -import beman.execution.detail.stopped_as_optional; -import beman.execution.detail.sync_wait; +export import beman.execution.detail.stop_token_of_t; +export import beman.execution.detail.stoppable_source; +export import beman.execution.detail.stopped_as_error; +export import beman.execution.detail.stopped_as_optional; +export import beman.execution.detail.sync_wait; export import beman.execution.detail.tag_of_t; // [exec.getcomplsigs], completion signatures -import beman.execution.detail.then; -import beman.execution.detail.transform_sender; -import beman.execution.detail.valid_completion_for; +export import beman.execution.detail.then; export import beman.execution.detail.value_types_of_t; // [exec.getcomplsigs], completion signatures -import beman.execution.detail.when_all; -import beman.execution.detail.when_all_with_variant; +export import beman.execution.detail.when_all; +export import beman.execution.detail.when_all_with_variant; export import beman.execution.detail.with_awaitable_senders; // [exec.with.awaitable.senders] -import beman.execution.detail.write_env; +export import beman.execution.detail.write_env; +import beman.execution.detail.apply_sender; +import beman.execution.detail.as_awaitable; +import beman.execution.detail.check_type_alias_exist; +import beman.execution.detail.get_await_completion_adaptor; +import beman.execution.detail.nostopstate; +import beman.execution.detail.sender_adaptor_closure; +import beman.execution.detail.transform_sender; +import beman.execution.detail.valid_completion_for; // [stoptoken.concepts], stop token concepts export import beman.execution.detail.stoppable_token; diff --git a/src/beman/execution/get_completion_domain.cppm b/src/beman/execution/get_completion_domain.cppm new file mode 100644 index 00000000..98d1fc8b --- /dev/null +++ b/src/beman/execution/get_completion_domain.cppm @@ -0,0 +1,12 @@ +module; +// src/beman/execution/get_completion_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.get_completion_domain; + +namespace beman::execution { +export using beman::execution::get_completion_domain_t; +export using beman::execution::get_completion_domain; +} // namespace beman::execution diff --git a/src/beman/execution/hide_query.cppm b/src/beman/execution/hide_query.cppm new file mode 100644 index 00000000..f01128f6 --- /dev/null +++ b/src/beman/execution/hide_query.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/hide_query.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.hide_query; + +namespace beman::execution::detail { +export using beman::execution::detail::hide_query; +} // namespace beman::execution::detail diff --git a/src/beman/execution/indeterminate_domain.cppm b/src/beman/execution/indeterminate_domain.cppm new file mode 100644 index 00000000..cb66d9b1 --- /dev/null +++ b/src/beman/execution/indeterminate_domain.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/indeterminate_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.indeterminate_domain; + +namespace beman::execution { +export using beman::execution::indeterminate_domain; +} // namespace beman::execution diff --git a/src/beman/execution/try_query.cppm b/src/beman/execution/try_query.cppm new file mode 100644 index 00000000..f0f4c4ee --- /dev/null +++ b/src/beman/execution/try_query.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/try_query.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.try_query; + +namespace beman::execution::detail { +export using beman::execution::detail::try_query; +} // namespace beman::execution::detail diff --git a/tests/beman/execution/CMakeLists.txt b/tests/beman/execution/CMakeLists.txt index f950efd7..94076dc8 100644 --- a/tests/beman/execution/CMakeLists.txt +++ b/tests/beman/execution/CMakeLists.txt @@ -35,6 +35,7 @@ list( exec-opstate-start.test exec-opstate.test exec-prop.test + exec-queries-expos.test exec-read-env.test exec-recv-concepts.test exec-recv.test @@ -111,6 +112,18 @@ list( utilities.test ) +option( + BEMAN_EXECUTION_TEST_CASE + "The name of the test ase to build. Values: e.g., stoptoken-never." + "" +) + +if(BEMAN_EXECUTION_TEST_CASE) + if(NOT ${BEMAN_EXECUTION_TEST_CASE} STREQUAL "*") + set(execution_tests ${BEMAN_EXECUTION_TEST_CASE}.test) + endif() +endif() + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) foreach(test ${execution_tests}) diff --git a/tests/beman/execution/exec-queries-expos.test.cpp b/tests/beman/execution/exec-queries-expos.test.cpp new file mode 100644 index 00000000..87f5df34 --- /dev/null +++ b/tests/beman/execution/exec-queries-expos.test.cpp @@ -0,0 +1,96 @@ +// tests/beman/execution/exec-queries-expos.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_domain; +import beman.execution.detail.get_scheduler; +import beman.execution.detail.hide_query; +import beman.execution.detail.try_query; +#else +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace { +template <::std::size_t> +struct arg { + int value{}; +}; +template <::std::size_t> +struct get_arg {}; + +struct test_queryable { + int query(get_arg<0>) const noexcept { return 42; } + + int query(get_arg<1>) const noexcept { return 43; } + int query(get_arg<1>, arg<0>) const noexcept { return 44; } + + int query(get_arg<2>, arg<0>) const noexcept { return 45; } + int query(get_arg<2>, arg<0>, arg<1>) const noexcept { return 46; } + + int query(test_std::get_domain_t) const noexcept { return 47; } + int query(test_std::get_domain_t, arg<0>) const noexcept { return 48; } + int query(test_std::get_domain_t, arg<0>, arg<1>) const noexcept { return 49; } + + int query(test_std::get_scheduler_t) const noexcept { return 50; } + int query(test_std::get_scheduler_t, arg<0>) const noexcept { return 51; } + int query(test_std::get_scheduler_t, arg<0>, arg<1>) const noexcept { return 52; } +}; + +template +auto test_try_query_exists(int expect, Q q, Tag&& tag, Args&&... args) -> void { + static_assert(Value == + requires { test_detail::try_query(q, ::std::forward(tag), ::std::forward(args)...); }); + if constexpr (Value) { + ASSERT(expect == test_detail::try_query(q, ::std::forward(tag), ::std::forward(args)...)); + } +} + +auto test_try_query() -> void { + test_try_query_exists(42, test_queryable{}, get_arg<0>{}); + test_try_query_exists(42, test_queryable{}, get_arg<0>{}, arg<0>{}); + test_try_query_exists(42, test_queryable{}, get_arg<0>{}, arg<0>{}, arg<1>{}); + + test_try_query_exists(43, test_queryable{}, get_arg<1>{}); + test_try_query_exists(44, test_queryable{}, get_arg<1>{}, arg<0>{}); + test_try_query_exists(43, test_queryable{}, get_arg<1>{}, arg<0>{}, arg<1>{}); + + test_try_query_exists(0, test_queryable{}, get_arg<2>{}); + test_try_query_exists(45, test_queryable{}, get_arg<2>{}, arg<0>{}); + test_try_query_exists(46, test_queryable{}, get_arg<2>{}, arg<0>{}, arg<1>{}); +} + +template +auto test_hide_query_exists(int expect, Q q, Tag&& tag, Args&&... args) -> void { + static_assert(Value == requires { + test_detail::hide_query(q).query(::std::forward(tag), ::std::forward(args)...); + }); + if constexpr (Value) { + ASSERT(expect == test_detail::hide_query(q).query(::std::forward(tag), ::std::forward(args)...)); + } +} + +auto test_hide_query() -> void { + test_hide_query_exists(42, test_queryable{}, get_arg<0>{}); + test_hide_query_exists(44, test_queryable{}, get_arg<1>{}, arg<0>{}); + test_hide_query_exists(46, test_queryable{}, get_arg<2>{}, arg<0>{}, arg<1>{}); + + test_hide_query_exists(47, test_queryable{}, test_std::get_domain); + test_hide_query_exists(48, test_queryable{}, test_std::get_domain, arg<0>{}); + test_hide_query_exists(49, test_queryable{}, test_std::get_domain, arg<0>{}, arg<1>{}); + + test_hide_query_exists(50, test_queryable{}, test_std::get_scheduler); + test_hide_query_exists(51, test_queryable{}, test_std::get_scheduler, arg<0>{}); + test_hide_query_exists(52, test_queryable{}, test_std::get_scheduler, arg<0>{}, arg<1>{}); +} +} // namespace + +TEST(exec_queries_expos) { + test_try_query(); + test_hide_query(); +} diff --git a/tests/beman/execution/exec.get.compl.domain.test.cpp b/tests/beman/execution/exec.get.compl.domain.test.cpp new file mode 100644 index 00000000..d1957302 --- /dev/null +++ b/tests/beman/execution/exec.get.compl.domain.test.cpp @@ -0,0 +1,32 @@ +// tests/beman/execution/exec.get.compl.domain.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.set_error; +import beman.execution.detail.set_stopped; +import beman.execution.detail.set_value; +#else +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace { +template +void test_get_completion_domain_template() { + static_assert(Value == requires { beman::execution::get_completion_domain; }); +} +} // namespace + +TEST(exec_with_awaitable_senders) { + test_get_completion_domain_template(); + test_get_completion_domain_template(); + test_get_completion_domain_template(); + test_get_completion_domain_template(); + //-dk:TODO test compilation failure: test_get_completion_domain_template(); +} diff --git a/tests/beman/execution/execution-syn.test.cpp b/tests/beman/execution/execution-syn.test.cpp index d3711046..ccd37e29 100644 --- a/tests/beman/execution/execution-syn.test.cpp +++ b/tests/beman/execution/execution-syn.test.cpp @@ -8,6 +8,17 @@ import beman.execution; import beman.execution.detail; #else +#include +#include +#include +#include +#include +#include +//-dk:TODO #include +#include +#include +#include +#include #include #include #include @@ -31,6 +42,28 @@ import beman.execution.detail; namespace { auto use(auto&&) -> void {} + +auto test_queries() -> void { + // std + static_assert( + std::same_as>); + static_assert(std::same_as>); + static_assert(std::same_as>); + + // std::execution + static_assert(std::same_as>); + static_assert(std::same_as>); + static_assert(std::same_as>); + static_assert( + std::same_as, + std::remove_cvref_t)>>); + static_assert(std::same_as, + std::remove_cvref_t)>>); + static_assert(std::same_as>); +} + struct scheduler { struct env { template @@ -381,9 +414,15 @@ auto test_sender_adaptor() -> void { auto test_as_awaitable() -> void { static_assert(std::same_as); } + +auto test_exec_env() -> void { + test::type_exists>(); + test::type_exists>(); +} } // namespace TEST(execution_syn) { + test_queries(); test_schedule_result_t(); test_env_of_t(); test_decayed_tuple(); @@ -397,4 +436,5 @@ TEST(execution_syn) { test_sender_adaptor_closure(); test_sender_adaptor(); test_as_awaitable(); + test_exec_env(); } From 8f60dd2d4fee6df3a61441a5cd88950a13476a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Thu, 5 Mar 2026 17:32:24 +0100 Subject: [PATCH 02/16] some progress on get_completion_domain --- .../detail/get_completion_domain.hpp | 35 ++++- .../detail/get_completion_scheduler.hpp | 15 +- tests/beman/execution/CMakeLists.txt | 1 + .../execution/exec-get-compl-domain.test.cpp | 142 ++++++++++++++++++ .../execution/exec.get.compl.domain.test.cpp | 32 ---- 5 files changed, 185 insertions(+), 40 deletions(-) create mode 100644 tests/beman/execution/exec-get-compl-domain.test.cpp delete mode 100644 tests/beman/execution/exec.get.compl.domain.test.cpp diff --git a/include/beman/execution/detail/get_completion_domain.hpp b/include/beman/execution/detail/get_completion_domain.hpp index 930318ee..0419ec18 100644 --- a/include/beman/execution/detail/get_completion_domain.hpp +++ b/include/beman/execution/detail/get_completion_domain.hpp @@ -9,15 +9,27 @@ import std; #else #include +#include +#include #endif #if BEMAN_HAS_MODULES +import beman.execution.detail.default_domain; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.queryable; +import beman.execution.detail.scheduler; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; +import beman.execution.detail.try_query; #else +#include +#include +#include +#include #include #include #include +#include #endif // ---------------------------------------------------------------------------- @@ -27,7 +39,28 @@ template requires(::std::same_as || ::std::same_as || ::std::same_as || ::std::same_as) -struct get_completion_domain_t {}; +struct get_completion_domain_t { + template + auto operator()(Q&& q, E&&... e) const { + using domain = decltype([&]{ + if constexpr (requires{ ::beman::execution::detail::try_query(::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); }) { + return ::beman::execution::detail::try_query(::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); + } else if constexpr (::std::same_as) { + return get_completion_domain_t<::beman::execution::set_value_t>()(::std::forward(q), ::std::forward(e)...); + } + else if constexpr (::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), get_completion_domain_t<::beman::execution::set_value_t>{}, ::std::forward(q), ::std::forward(e)...)) { + return ::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), get_completion_domain_t<::beman::execution::set_value_t>{}, ::std::forward(q), ::std::forward(e)...); + } else if constexpr (::beman::execution::scheduler && 0u != sizeof...(E)) { + return ::beman::execution::default_domain{}; + } + else { + static_assert(::std::same_as, "get_completion_domain requires the environment to be queryable for get_completion_domain or get_completion_scheduler"); + } + }()); + static_assert(noexcept(domain{}), "the domain's default constructor has to be noexcept"); + return domain{}; + } +}; } // namespace beman::execution::detail namespace beman::execution { diff --git a/include/beman/execution/detail/get_completion_scheduler.hpp b/include/beman/execution/detail/get_completion_scheduler.hpp index f5d95e46..4a9b771d 100644 --- a/include/beman/execution/detail/get_completion_scheduler.hpp +++ b/include/beman/execution/detail/get_completion_scheduler.hpp @@ -79,17 +79,18 @@ struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { auto operator()(Env&&) const noexcept = BEMAN_EXECUTION_DELETE("The environment's query(get_completion_scheduler_t) has to return a scheduler"); - template + template requires requires(const get_completion_scheduler_t& self, const get_completion_scheduler_t<::beman::execution::set_value_t>& value_self, - const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept -> ::beman::execution::detail::almost_scheduler; + const ::std::remove_cvref_t& env, + const ::std::remove_cvref_t&... e) { + { env.query(self, e...) } noexcept -> ::beman::execution::detail::almost_scheduler; { - ::beman::execution::get_env(::beman::execution::schedule(env.query(self))).query(value_self) - } -> ::beman::execution::detail::decayed_same_as; + ::beman::execution::get_env(::beman::execution::schedule(env.query(self))).query(value_self, e...) + } -> ::beman::execution::detail::decayed_same_as; } - auto operator()(Env&& env) const noexcept { - return ::std::as_const(env).query(*this); + auto operator()(Env&& env, E&&... e) const noexcept { + return ::std::as_const(env).query(*this, e...); } }; diff --git a/tests/beman/execution/CMakeLists.txt b/tests/beman/execution/CMakeLists.txt index 94076dc8..137a3871 100644 --- a/tests/beman/execution/CMakeLists.txt +++ b/tests/beman/execution/CMakeLists.txt @@ -22,6 +22,7 @@ list( exec-general.test exec-getcomplsigs.test exec-get-allocator.test + exec-get-compl-domain.test exec-get-compl-sched.test exec-get-delegation-scheduler.test exec-get-domain.test diff --git a/tests/beman/execution/exec-get-compl-domain.test.cpp b/tests/beman/execution/exec-get-compl-domain.test.cpp new file mode 100644 index 00000000..c801acfe --- /dev/null +++ b/tests/beman/execution/exec-get-compl-domain.test.cpp @@ -0,0 +1,142 @@ +// tests/beman/execution/exec-get-compl-domain.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.set_error; +import beman.execution.detail.set_stopped; +import beman.execution.detail.set_value; +import beman.execution.detail.operation_state; +import beman.execution.detail.sender; +import beman.execution.detail.scheduler; +import beman.execution.detail.scheduler_t; +import beman.execution.detail.get_env; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.schedule; +import beman.execution.detail.get_completion_signatures; +import beman.execution.detail.completion_signatures; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace { + struct throwing_domain { + throwing_domain() noexcept(false) = default; + }; + template + struct domain { + int value{}; + auto operator==(const domain&) const -> bool = default; + }; + + template struct test_env {}; + +template +void test_get_completion_domain_template() { + static_assert(Value == requires { beman::execution::get_completion_domain; }); +} + +template +auto test_get_completion_domain_tag() { + struct queryable_tag { + auto query(test_std::get_completion_domain_t, test_env<0>) const { return domain<0>{42}; } + auto query(test_std::get_completion_domain_t, test_env<1>) const { return domain<1>{42}; } + auto query(test_std::get_completion_domain_t) const { return domain<2>{42}; } + auto query(test_std::get_completion_domain_t, test_env<3>) const { return throwing_domain{}; } + }; + + static_assert(std::same_as(queryable_tag{}, test_env<0>{})), domain<0>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<0>{}) == domain<0>{}); + static_assert(std::same_as(queryable_tag{}, test_env<1>{})), domain<1>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<1>{}) == domain<1>{}); + static_assert(std::same_as(queryable_tag{})), domain<2>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}) == domain<2>{}); + static_assert(std::same_as(queryable_tag{}, test_env<2>{})), domain<2>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<2>{}) == domain<2>{}); +} + + template + struct scheduler { + using scheduler_concept = test_std::scheduler_t; + struct state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept {} + }; + struct env { + auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } + }; + struct sender { + using sender_concept = test_std::sender_t; + static consteval auto get_completion_signatures() { return test_std::completion_signatures(); } + auto connect(auto&&) const { return state{}; } + auto get_env() const noexcept { return env{}; } + }; + auto schedule() const { return sender{}; } + + bool operator==(const scheduler&) const = default; + + auto query(test_std::get_completion_domain_t, test_env<0>) const { return domain<0>{42}; } + auto query(test_std::get_completion_domain_t, test_env<1>) const { return domain<1>{42}; } + auto query(test_std::get_completion_domain_t) const { return domain<2>{42}; } + auto query(test_std::get_completion_domain_t, test_env<3>) const { return throwing_domain{}; } + }; + static_assert(beman::execution::scheduler>); + +template +auto test_get_completion_domain_tag_via_scheduler() { + struct initial_queryable{ + auto query(test_std::get_completion_scheduler_t, test_env<0>) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t, test_env<1>) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t, test_env<2>) const noexcept { return scheduler{}; } + }; + + test_std::get_completion_scheduler(initial_queryable{}); + initial_queryable().query(test_std::get_completion_scheduler, test_env<0>{}); + //-dk:TODO test_std::get_completion_scheduler(initial_queryable{}, test_env<0>{}); + + //static_assert(std::same_as(initial_queryable{}, test_env<0>{})), domain<0>>); + #if 0 + ASSERT(beman::execution::get_completion_domain(initial_queryable{}, test_env<0>{}) == domain<0>{}); + static_assert(std::same_as(initial_queryable{}, test_env<1>{})), domain<1>>); + ASSERT(beman::execution::get_completion_domain(initial_queryable{}, test_env<1>{}) == domain<1>{}); + static_assert(std::same_as(initial_queryable{})), domain<2>>); + ASSERT(beman::execution::get_completion_domain(initial_queryable{}) == domain<2>{}); + static_assert(std::same_as(initial_queryable{}, test_env<2>{})), domain<2>>); + ASSERT(beman::execution::get_completion_domain(initial_queryable{}, test_env<2>{}) == domain<2>{}); + #endif +} +} // namespace + +TEST(exec_with_awaitable_senders) { + test_get_completion_domain_template(); + test_get_completion_domain_template(); + test_get_completion_domain_template(); + test_get_completion_domain_template(); + //-dk:TODO test compilation failure: test_get_completion_domain_template(); + + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + + test_get_completion_domain_tag_via_scheduler(); +} diff --git a/tests/beman/execution/exec.get.compl.domain.test.cpp b/tests/beman/execution/exec.get.compl.domain.test.cpp deleted file mode 100644 index d1957302..00000000 --- a/tests/beman/execution/exec.get.compl.domain.test.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// tests/beman/execution/exec.get.compl.domain.test.cpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.get_completion_domain; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.set_value; -#else -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace { -template -void test_get_completion_domain_template() { - static_assert(Value == requires { beman::execution::get_completion_domain; }); -} -} // namespace - -TEST(exec_with_awaitable_senders) { - test_get_completion_domain_template(); - test_get_completion_domain_template(); - test_get_completion_domain_template(); - test_get_completion_domain_template(); - //-dk:TODO test compilation failure: test_get_completion_domain_template(); -} From 19f3f169036470403a5b98220b5d7ae3d36ae58a Mon Sep 17 00:00:00 2001 From: Cra3z Date: Thu, 23 Apr 2026 17:53:07 +0800 Subject: [PATCH 03/16] Refactor transform_sender and sender-algorithms --- include/beman/execution/detail/affine_on.hpp | 11 +- include/beman/execution/detail/associate.hpp | 13 +- include/beman/execution/detail/bulk.hpp | 28 +- .../execution/detail/call_with_default.hpp | 44 ++++ .../beman/execution/detail/common_domain.hpp | 51 ++++ .../beman/execution/detail/compl_domain.hpp | 55 ++++ .../execution/detail/completion_domain.hpp | 66 +---- include/beman/execution/detail/connect.hpp | 5 +- .../beman/execution/detail/continues_on.hpp | 240 ++++++++++++++---- .../beman/execution/detail/default_domain.hpp | 72 ++---- include/beman/execution/detail/env.hpp | 33 ++- .../detail/get_completion_domain.hpp | 63 +++-- .../detail/get_completion_signatures.hpp | 4 +- include/beman/execution/detail/get_domain.hpp | 45 ++-- .../beman/execution/detail/get_scheduler.hpp | 14 +- .../detail/{hide_query.hpp => hide_sched.hpp} | 26 +- .../execution/detail/indeterminate_domain.hpp | 79 +++++- .../beman/execution/detail/inline_attrs.hpp | 46 ++++ .../execution/detail/inline_scheduler.hpp | 13 +- .../beman/execution/detail/into_variant.hpp | 8 +- include/beman/execution/detail/let.hpp | 9 +- .../execution/detail/not_a_scheduler.hpp | 33 +++ include/beman/execution/detail/on.hpp | 35 ++- include/beman/execution/detail/prop.hpp | 2 +- .../beman/execution/detail/schedule_from.hpp | 230 ++--------------- include/beman/execution/detail/scheduler.hpp | 12 +- include/beman/execution/detail/split.hpp | 6 +- include/beman/execution/detail/starts_on.hpp | 26 +- .../execution/detail/stopped_as_error.hpp | 10 +- .../execution/detail/stopped_as_optional.hpp | 8 +- include/beman/execution/detail/sync_wait.hpp | 6 +- .../detail/sync_wait_with_variant.hpp | 3 +- include/beman/execution/detail/then.hpp | 12 +- .../execution/detail/transform_sender.hpp | 155 ++++------- include/beman/execution/detail/when_all.hpp | 21 +- .../detail/when_all_with_variant.hpp | 14 +- src/beman/execution/CMakeLists.txt | 4 +- src/beman/execution/hide_query.cppm | 11 - src/beman/execution/hide_sched.cppm | 11 + .../execution/exec-queries-expos.test.cpp | 6 +- 40 files changed, 801 insertions(+), 729 deletions(-) create mode 100644 include/beman/execution/detail/call_with_default.hpp create mode 100644 include/beman/execution/detail/common_domain.hpp create mode 100644 include/beman/execution/detail/compl_domain.hpp rename include/beman/execution/detail/{hide_query.hpp => hide_sched.hpp} (66%) create mode 100644 include/beman/execution/detail/inline_attrs.hpp create mode 100644 include/beman/execution/detail/not_a_scheduler.hpp delete mode 100644 src/beman/execution/hide_query.cppm create mode 100644 src/beman/execution/hide_sched.cppm diff --git a/include/beman/execution/detail/affine_on.hpp b/include/beman/execution/detail/affine_on.hpp index 9c2210a5..aec16339 100644 --- a/include/beman/execution/detail/affine_on.hpp +++ b/include/beman/execution/detail/affine_on.hpp @@ -21,7 +21,6 @@ import beman.execution.detail.env; import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; import beman.execution.detail.get_completion_signatures; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_scheduler; import beman.execution.detail.get_stop_token; import beman.execution.detail.make_sender; @@ -38,14 +37,13 @@ import beman.execution.detail.sender_has_affine_on; import beman.execution.detail.set_value; import beman.execution.detail.store_receiver; import beman.execution.detail.tag_of_t; -import beman.execution.detail.transform_sender; import beman.execution.detail.unstoppable; import beman.execution.detail.write_env; #else +#include #include #include #include -#include #include #include #include @@ -60,7 +58,6 @@ import beman.execution.detail.write_env; #include #include #include -#include #include #include #endif @@ -100,10 +97,8 @@ struct affine_on_t : ::beman::execution::sender_adaptor_closure { */ template <::beman::execution::sender Sender> auto operator()(Sender&& sender) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sender), - ::beman::execution::detail::make_sender( - *this, ::beman::execution::env<>{}, ::std::forward(sender))); + return ::beman::execution::detail::make_sender( + *this, ::beman::execution::env<>{}, ::std::forward(sender)); } /** diff --git a/include/beman/execution/detail/associate.hpp b/include/beman/execution/detail/associate.hpp index 8b567d01..5dada5ae 100644 --- a/include/beman/execution/detail/associate.hpp +++ b/include/beman/execution/detail/associate.hpp @@ -22,7 +22,6 @@ import beman.execution.detail.completion_signatures_for; import beman.execution.detail.default_impls; import beman.execution.detail.env; import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.nothrow_callable; @@ -32,19 +31,16 @@ import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; import beman.execution.detail.start; -import beman.execution.detail.transform_sender; import beman.execution.detail.valid_completion_signatures; #else #include #include -#include #include #include #include #include #include #include -#include #endif // ---------------------------------------------------------------------------- @@ -108,12 +104,9 @@ associate_data(Token, Sender&&) -> associate_data; struct associate_t { template <::beman::execution::sender Sender, ::beman::execution::scope_token Token> auto operator()(Sender&& sender, Token token) const { - auto domain(::beman::execution::detail::get_domain_early(sender)); - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::associate_data(::std::move(token), ::std::forward(sender)))); + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::associate_data(::std::move(token), ::std::forward(sender))); } template <::beman::execution::scope_token Token> diff --git a/include/beman/execution/detail/bulk.hpp b/include/beman/execution/detail/bulk.hpp index 12b3f4ec..ce60da69 100644 --- a/include/beman/execution/detail/bulk.hpp +++ b/include/beman/execution/detail/bulk.hpp @@ -21,7 +21,6 @@ import beman.execution.detail.completion_signatures_of_t; import beman.execution.detail.default_impls; import beman.execution.detail.execution_policy; import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; import beman.execution.detail.meta.unique; @@ -31,7 +30,6 @@ import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; import beman.execution.detail.set_error; import beman.execution.detail.set_value; -import beman.execution.detail.transform_sender; #else #include #include @@ -39,7 +37,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #include #include #include @@ -49,7 +46,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #endif // ---------------------------------------------------------------------------- @@ -120,13 +116,11 @@ struct bulk_algo_t : ::beman::execution::sender_adaptor_closure> && ::std::integral && ::std::copy_constructible<::std::decay_t>) auto operator()(Sender&& sndr, Policy&& policy, Shape shape, F&& f) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ - ::std::forward(policy), shape, ::std::forward(f)}, - ::std::forward(sndr))); + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ + ::std::forward(policy), shape, ::std::forward(f)}, + ::std::forward(sndr)); } private: @@ -210,13 +204,11 @@ struct bulk_t : ::beman::execution::sender_adaptor_closure { ::beman::execution::is_execution_policy_v<::std::remove_cvref_t> && ::std::integral && ::std::copy_constructible<::std::decay_t>) auto operator()(Sender&& sndr, Policy&& policy, Shape shape, F&& f) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ - ::std::forward(policy), shape, ::std::forward(f)}, - ::std::forward(sndr))); + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ + ::std::forward(policy), shape, ::std::forward(f)}, + ::std::forward(sndr)); } template <::beman::execution::detail::sender_for Sender, typename... Env> diff --git a/include/beman/execution/detail/call_with_default.hpp b/include/beman/execution/detail/call_with_default.hpp new file mode 100644 index 00000000..149c80b9 --- /dev/null +++ b/include/beman/execution/detail/call_with_default.hpp @@ -0,0 +1,44 @@ +// include/beman/execution/detail/call_with_default.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_WITH_DEFAULT +#define INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_WITH_DEFAULT + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +// call-with-default(fn, default, args...): +// If fn(args...) is well-formed, returns fn(args...). +// Otherwise, returns static_cast(default). +template + requires requires(Fn&& fn, Args&&... args) { + ::std::forward(fn)(::std::forward(args)...); + } +constexpr decltype(auto) call_with_default(Fn&& fn, Default&&, Args&&... args) noexcept( + noexcept(::std::forward(fn)(::std::forward(args)...))) { + return ::std::forward(fn)(::std::forward(args)...); +} + +template + requires(not requires(Fn&& fn, Args&&... args) { + ::std::forward(fn)(::std::forward(args)...); + }) +constexpr auto call_with_default(Fn&&, Default&& value, Args&&...) noexcept( + noexcept(static_cast(::std::forward(value)))) -> Default { + return static_cast(::std::forward(value)); +} + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_WITH_DEFAULT diff --git a/include/beman/execution/detail/common_domain.hpp b/include/beman/execution/detail/common_domain.hpp new file mode 100644 index 00000000..5dbc9396 --- /dev/null +++ b/include/beman/execution/detail/common_domain.hpp @@ -0,0 +1,51 @@ +// include/beman/execution/detail/common_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMMON_DOMAIN +#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMMON_DOMAIN + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.indeterminate_domain; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +// COMMON-DOMAIN(domains...): +// common_type_t() if well-formed, +// otherwise indeterminate_domain() where Ds is the pack of types +// consisting of decltype(auto(domains))... with duplicates removed. +template +struct common_domain_impl { + using type = ::beman::execution::indeterminate_domain; +}; + +template + requires requires { typename ::std::common_type_t; } +struct common_domain_impl { + using type = ::std::common_type_t; +}; + +template +using common_domain_t = typename common_domain_impl<::std::decay_t...>::type; + +template +constexpr auto common_domain(Domains&&...) noexcept { + return common_domain_t{}; +} + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMMON_DOMAIN diff --git a/include/beman/execution/detail/compl_domain.hpp b/include/beman/execution/detail/compl_domain.hpp new file mode 100644 index 00000000..eb233e13 --- /dev/null +++ b/include/beman/execution/detail/compl_domain.hpp @@ -0,0 +1,55 @@ +// include/beman/execution/detail/compl_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPL_DOMAIN +#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPL_DOMAIN + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_env; +import beman.execution.detail.indeterminate_domain; +#else +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +// COMPL-DOMAIN(Tag, sndr, envs): +// D() where D is the type of get_completion_domain(get_env(sndr), envs...) +// if that expression is well-formed or envs is empty pack, +// and indeterminate_domain<>() otherwise. +template +constexpr auto compl_domain(const Sndr& sndr, const Envs&... envs) noexcept { + if constexpr (requires { + ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), envs...); + }) { + return decltype( + ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), envs...)){}; + } else if constexpr (sizeof...(Envs) == 0) { + // If envs is empty, the expression should still be tried but may be ill-formed + // In that case, return indeterminate_domain + return ::beman::execution::indeterminate_domain<>{}; + } else { + return ::beman::execution::indeterminate_domain<>{}; + } +} + +template +using compl_domain_t = decltype(compl_domain(::std::declval(), ::std::declval()...)); + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMPL_DOMAIN diff --git a/include/beman/execution/detail/completion_domain.hpp b/include/beman/execution/detail/completion_domain.hpp index fa643c3d..b6a518da 100644 --- a/include/beman/execution/detail/completion_domain.hpp +++ b/include/beman/execution/detail/completion_domain.hpp @@ -12,70 +12,22 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.default_domain; -import beman.execution.detail.get_completion_scheduler; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -import beman.execution.detail.sender; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.set_value; +import beman.execution.detail.get_completion_domain; #else #include -#include -#include -#include -#include +#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { -struct completion_domain_undefined {}; -template -struct completion_domain_merge {}; -template -struct completion_domain_merge { - using type = T; -}; -template -struct completion_domain_merge { - using type = T; -}; -template -struct completion_domain_merge { - using type = T; -}; -template <> -struct completion_domain_merge { - using type = completion_domain_undefined; -}; - -/*! - * \brief Get a sender's completion domain or the specified default. - * \headerfile beman/execution/execution.hpp - * \internal - */ -template -constexpr auto completion_domain(const Sender& sender) noexcept { - - static_assert(::beman::execution::sender); - constexpr auto get = [](Tag, const Sender& sender) { - if constexpr (requires { - ::beman::execution::get_domain( - ::beman::execution::get_completion_scheduler(::beman::execution::get_env(sender))); - }) { - return ::beman::execution::get_domain( - ::beman::execution::get_completion_scheduler(::beman::execution::get_env(sender))); - } else { - return completion_domain_undefined{}; - } - }; - - using type = typename completion_domain_merge< - typename completion_domain_merge::type, - decltype(get(::beman::execution::set_value, sender))>::type; - return ::std::conditional_t<::std::same_as, Default, type>(); +template +constexpr auto completion_domain(const Sndr& sndr, const Env& env) noexcept { + if constexpr (requires { ::beman::execution::get_completion_domain<>(::beman::execution::get_env(sndr), env); }) { + return ::beman::execution::get_completion_domain<>(::beman::execution::get_env(sndr), env); + } else { + return ::beman::execution::default_domain(); + } } } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/connect.hpp b/include/beman/execution/detail/connect.hpp index 28de8f01..9a4f7a3d 100644 --- a/include/beman/execution/detail/connect.hpp +++ b/include/beman/execution/detail/connect.hpp @@ -14,13 +14,11 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.connect_awaitable; -import beman.execution.detail.get_domain_late; import beman.execution.detail.get_env; import beman.execution.detail.operation_state; import beman.execution.detail.transform_sender; #else #include -#include #include #include #include @@ -41,9 +39,8 @@ struct connect_t { static auto make_new_sender(Sender&& sender, Receiver&& receiver) //-dk:TODO this noexcept needs to get confirmed/fixed noexcept(true) -> decltype(auto) { + // P3826R5: transform_sender(sndr, get_env(rcvr)) return ::beman::execution::transform_sender( - decltype(::beman::execution::detail::get_domain_late(::std::forward(sender), - ::beman::execution::get_env(receiver))){}, ::std::forward(sender), ::beman::execution::get_env(receiver)); } diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index 98e2d19f..df4d0211 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -8,46 +8,80 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else +#include +#include +#include #include +#include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.as_tuple; import beman.execution.detail.basic_sender; -import beman.execution.detail.default_domain; +import beman.execution.detail.child_type; +import beman.execution.detail.completion_signatures; +import beman.execution.detail.completion_signatures_for; +import beman.execution.detail.completion_signatures_of_t; +import beman.execution.detail.connect; +import beman.execution.detail.connect_result_t; +import beman.execution.detail.decayed_tuple; import beman.execution.detail.default_impls; +import beman.execution.detail.env_of_t; +import beman.execution.detail.error_types_of_t; import beman.execution.detail.fwd_env; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; -import beman.execution.detail.get_domain_late; +import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_env; import beman.execution.detail.impls_for; import beman.execution.detail.join_env; import beman.execution.detail.make_sender; -import beman.execution.detail.query_with_default; +import beman.execution.detail.meta.combine; +import beman.execution.detail.meta.prepend; +import beman.execution.detail.meta.to; +import beman.execution.detail.meta.transform; +import beman.execution.detail.meta.unique; +import beman.execution.detail.receiver; import beman.execution.detail.sched_attrs; +import beman.execution.detail.schedule; import beman.execution.detail.schedule_from; +import beman.execution.detail.schedule_result_t; import beman.execution.detail.scheduler; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; -import beman.execution.detail.transform_sender; +import beman.execution.detail.sender_in; +import beman.execution.detail.set_error; +import beman.execution.detail.set_stopped; +import beman.execution.detail.start; #else -#include +#include +#include +#include +#include +#include #include +#include +#include #include -#include -#include #include #include #include #include -#include +#include +#include +#include +#include +#include #include +#include #include +#include #include #include #include #include -#include +#include +#include +#include +#include #endif // ---------------------------------------------------------------------------- @@ -55,32 +89,108 @@ import beman.execution.detail.transform_sender; #include namespace beman::execution::detail { -// specialize default_domain appropriately -/*! - * \brief The actual implementation of the continues_on customization point object - * \headerfile beman/execution/execution.hpp - * \internal - */ + +// P3826R5: continues_on schedules work dependent on the completion of a sender +// onto a scheduler's associated execution resource. +// continues_on(sndr, sch) = make_sender(continues_on, sch, schedule_from(sndr)) struct continues_on_t { - template <::beman::execution::detail::sender_for Sender, typename... Env> - static auto transform_sender(Sender&& sender, Env&&...) { - auto&& data{sender.template get<1>()}; - auto&& child{sender.template get<2>()}; - return ::beman::execution::schedule_from(std::move(data), std::move(child)); - } template <::beman::execution::scheduler Scheduler> auto operator()(Scheduler&& scheduler) const { return ::beman::execution::detail::make_sender_adaptor(*this, ::std::forward(scheduler)); } + + // P3826R5: continues_on(sndr, sch) = make_sender(continues_on, sch, schedule_from(sndr)) template <::beman::execution::sender Sender, ::beman::execution::scheduler Scheduler> auto operator()(Sender&& sender, Scheduler&& scheduler) const { - auto domain(::beman::execution::detail::get_domain_early(sender)); - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, std::forward(scheduler), ::std::forward(sender))); + return ::beman::execution::detail::make_sender( + *this, + ::std::forward(scheduler), + ::beman::execution::schedule_from(::std::forward(sender))); + } + + private: + template + struct get_signatures; + template + struct get_signatures< + ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, Scheduler, Sender>, + Env> { + using scheduler_sender = decltype(::beman::execution::schedule(::std::declval())); + template + using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; + using type = ::beman::execution::detail::meta::combine< + decltype(::beman::execution::get_completion_signatures()), + ::beman::execution::error_types_of_t, + ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; + }; + + public: + template + static consteval auto get_completion_signatures() { + return typename get_signatures<::std::remove_cvref_t, Env...>::type{}; } + + // P3826R5: impls_for has the scheduling machinery struct impls_for : ::beman::execution::detail::default_impls { + template + struct upstream_receiver { + using receiver_concept = ::beman::execution::receiver_t; + State* state; + + auto set_value() && noexcept -> void { + try { + ::std::visit( + [this](Tuple& result) noexcept -> void { + if constexpr (!::std::same_as<::std::monostate, Tuple>) { + ::std::apply( + [this](auto&& tag, auto&&... args) { + tag(::std::move(this->state->receiver), ::std::move(args)...); + }, + result); + } + }, + state->async_result); + } catch (...) { + ::beman::execution::set_error(::std::move(state->receiver), ::std::current_exception()); + } + } + + template + auto set_error(Error&& err) && noexcept -> void { + ::beman::execution::set_error(std::move(state->receiver), std::forward(err)); + } + + auto set_stopped() && noexcept -> void { + ::beman::execution::set_stopped(std::move(state->receiver)); + } + + auto get_env() const noexcept -> decltype(auto) { + return ::beman::execution::detail::fwd_env(::beman::execution::get_env(state->receiver)); + } + }; + + template + struct state_base { + Receiver receiver; + Variant async_result{}; + }; + + template + struct state_type : state_base { + using receiver_t = upstream_receiver>; + using operation_t = + ::beman::execution::connect_result_t<::beman::execution::schedule_result_t, receiver_t>; + operation_t op_state; + + static constexpr bool nothrow() { + return noexcept(::beman::execution::connect( + ::beman::execution::schedule(::std::declval()), receiver_t{nullptr})); + } + explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow()) + : state_base{rcvr}, + op_state(::beman::execution::connect(::beman::execution::schedule(sch), receiver_t{this})) {} + }; + struct get_attrs_impl { auto operator()(const auto& data, const auto& child) const noexcept -> decltype(auto) { return ::beman::execution::detail::join_env( @@ -89,38 +199,66 @@ struct continues_on_t { } }; static constexpr auto get_attrs{get_attrs_impl{}}; + + struct get_state_impl { + template + requires ::beman::execution::sender_in<::beman::execution::detail::child_type, + ::beman::execution::env_of_t> + auto operator()(Sender&& sender, Receiver& receiver) const { + auto sch{sender.template get<1>()}; + + using sched_t = ::std::remove_cvref_t; + using variant_t = ::beman::execution::detail::meta::unique< + ::beman::execution::detail::meta::prepend< + ::std::monostate, + ::beman::execution::detail::meta::transform< + ::beman::execution::detail::as_tuple_t, + ::beman::execution::detail::meta::to< + ::std::variant, + ::beman::execution::detail::meta::combine< + ::beman::execution::completion_signatures_of_t< + ::beman::execution::detail::child_type, + ::beman::execution::env_of_t>, + ::beman::execution::completion_signatures< + ::beman::execution::set_error_t(::std::exception_ptr), + ::beman::execution::set_stopped_t()>>>>>>; + + return state_type(sch, receiver); + }; + }; + static constexpr auto get_state{get_state_impl{}}; + + struct complete_impl { + template + auto operator()(auto, auto& state, auto& receiver, Tag, Args&&... args) const noexcept -> void { + using result_t = ::beman::execution::detail::decayed_tuple; + constexpr bool nothrow = ::std::is_nothrow_constructible_v; + + try { + [&]() noexcept(nothrow) { + state.async_result.template emplace(Tag(), std::forward(args)...); + }(); + } catch (...) { + if constexpr (not nothrow) + ::beman::execution::set_error(::std::move(receiver), ::std::current_exception()); + } + + if (state.async_result.index() == 0) + return; + + ::beman::execution::start(state.op_state); + } + }; + static constexpr auto complete{complete_impl{}}; }; }; -/*! - * \brief Get the sender's domain when the sender is continue_on - * \headerfile beman/execution/execution.hpp - * \internal - */ -#ifndef BEMAN_HAS_MODULES -#if 0 -template <::beman::execution::detail::sender_for<::beman::execution::detail::continues_on_t> Sender, typename Env> -auto get_domain_late(Sender&& sender, Env&&) { -#else -template -auto get_domain_late( - const ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>& sender, Env&&) { -#endif - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -#endif } // namespace beman::execution::detail #include namespace beman::execution { using continues_on_t = ::beman::execution::detail::continues_on_t; -/*! - * \brief Customization point object to create a `continues_on` sender. - * \headerfile beman/execution/execution.hpp - */ inline constexpr continues_on_t continues_on{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/default_domain.hpp b/include/beman/execution/detail/default_domain.hpp index faa29f8e..37cf86a7 100644 --- a/include/beman/execution/detail/default_domain.hpp +++ b/include/beman/execution/detail/default_domain.hpp @@ -14,81 +14,47 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.queryable; import beman.execution.detail.sender; -import beman.execution.detail.sender_decompose; import beman.execution.detail.tag_of_t; #else #include #include -#include #include #endif // ---------------------------------------------------------------------------- namespace beman::execution { -/*! - * \brief Domain type used when no domain is specified explicitly. - * \headerfile beman/execution/execution.hpp - * - * \details - * The default_domain tries to delegate any of the transformations to a member - * function of the - * tag type of the passed sender. If there is no corresponding member function - * no transformation is applied. - */ + struct default_domain { - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable... Env> - requires(sizeof...(Env) <= 1) && requires(Sender&& sender, Env&&... env) { - ::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...); + template + requires(sizeof...(Env) <= 1) && requires(Sender&& sender, const Env&... env) { + ::beman::execution::tag_of_t().transform_sender(Tag(), ::std::forward(sender), env...); } - static constexpr auto transform_sender(Sender&& sender, Env&&... env) noexcept( - noexcept(::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...))) + static constexpr auto transform_sender(Tag, Sender&& sender, const Env&... env) noexcept(noexcept( + ::beman::execution::tag_of_t().transform_sender(Tag(), ::std::forward(sender), env...))) -> ::beman::execution::sender decltype(auto) { - return ::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...); + return ::beman::execution::tag_of_t().transform_sender(Tag(), ::std::forward(sender), env...); } - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable... Env> - requires(sizeof...(Env) <= 1) && (not requires(Sender&& sender, Env&&... env) { - ::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...); + template + requires(sizeof...(Env) <= 1) && (not requires(Sender&& sender, const Env&... env) { + ::beman::execution::tag_of_t().transform_sender( + Tag(), ::std::forward(sender), env...); }) - static constexpr auto transform_sender(Sender&& sender, - Env&&...) noexcept(noexcept(::std::forward(sender))) + static constexpr auto + transform_sender(Tag, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward(sender))) -> ::beman::execution::sender decltype(auto) { return ::std::forward(sender); } - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env> - requires requires(Sender&& sender, Env&& env) { - ::beman::execution::tag_of_t().transform_env(::std::forward(sender), - ::std::forward(env)); - } - static constexpr auto transform_env(Sender&& sender, Env&& env) noexcept -> ::beman::execution::detail::queryable - decltype(auto) { - return ::beman::execution::tag_of_t().transform_env(::std::forward(sender), - ::std::forward(env)); - } - - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env> - requires(not requires(Sender&& sender, Env&& env) { - ::beman::execution::tag_of_t().transform_env(::std::forward(sender), - ::std::forward(env)); - }) - static constexpr auto transform_env(Sender&&, Env&& env) noexcept -> ::beman::execution::detail::queryable - decltype(auto) { - return static_cast(::std::forward(env)); - } - template - requires requires(Sender&& sender, Args&&... args) { - Tag().apply_sender(::std::forward(sender), ::std::forward(args)...); + requires requires(Tag tag, Sender&& sender, Args&&... args) { + tag.apply_sender(::std::forward(sender), ::std::forward(args)...); } - static constexpr auto apply_sender(Tag, Sender&& sender, Args&&... args) noexcept(noexcept( - Tag().apply_sender(::std::forward(sender), ::std::forward(args)...))) -> decltype(auto) { - return Tag().apply_sender(::std::forward(sender), ::std::forward(args)...); + static constexpr auto apply_sender(Tag tag, Sender&& sender, Args&&... args) noexcept( + noexcept(tag.apply_sender(::std::forward(sender), ::std::forward(args)...))) + -> decltype(auto) { + return tag.apply_sender(::std::forward(sender), ::std::forward(args)...); } }; } // namespace beman::execution diff --git a/include/beman/execution/detail/env.hpp b/include/beman/execution/detail/env.hpp index f1bd293f..ac496c40 100644 --- a/include/beman/execution/detail/env.hpp +++ b/include/beman/execution/detail/env.hpp @@ -26,8 +26,8 @@ struct env_base { Env env_; }; -template -concept has_query = requires(const E& e) { e.query(::std::declval()); }; +template +concept has_query = requires(const E& e) { e.query(::std::declval(), ::std::declval()...); }; template struct find_env; @@ -41,6 +41,23 @@ template struct find_env { using type = typename find_env::type; }; + +// find_env variant that supports additional args +template +struct args_list {}; + +template +struct find_env_with_args; +template + requires has_query +struct find_env_with_args, E0, E...> { + using type = E0; +}; +template + requires(not has_query) +struct find_env_with_args, E0, E...> { + using type = typename find_env_with_args, E...>::type; +}; } // namespace beman::execution::detail // ---------------------------------------------------------------------------- @@ -50,11 +67,13 @@ template <::beman::execution::detail::queryable... Envs> struct env : ::beman::execution::detail::env_base... { [[no_unique_address]] ::beman::execution::detail::non_assignable na_{}; - template - requires(::beman::execution::detail::has_query || ...) - constexpr auto query(Q q) const noexcept -> decltype(auto) { - using E = typename ::beman::execution::detail::find_env::type; - return q(static_cast&>(*this).env_); + template + requires(::beman::execution::detail::has_query || ...) + constexpr auto query(Q q, Args&&... args) const noexcept -> decltype(auto) { + using E = typename ::beman::execution::detail::find_env_with_args< + Q, ::beman::execution::detail::args_list, Envs...>::type; + return static_cast&>(*this).env_.query( + q, ::std::forward(args)...); } }; diff --git a/include/beman/execution/detail/get_completion_domain.hpp b/include/beman/execution/detail/get_completion_domain.hpp index 0419ec18..fe2a42cf 100644 --- a/include/beman/execution/detail/get_completion_domain.hpp +++ b/include/beman/execution/detail/get_completion_domain.hpp @@ -13,21 +13,21 @@ import std; #include #endif #if BEMAN_HAS_MODULES +import beman.execution.detail.completion_tag; import beman.execution.detail.default_domain; +import beman.execution.detail.forwarding_query; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.queryable; import beman.execution.detail.scheduler; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; import beman.execution.detail.try_query; #else +#include #include +#include #include #include #include -#include -#include #include #include #endif @@ -36,27 +36,42 @@ import beman.execution.detail.try_query; namespace beman::execution::detail { template - requires(::std::same_as || ::std::same_as || - ::std::same_as || - ::std::same_as) -struct get_completion_domain_t { + requires ::std::same_as || ::beman::execution::detail::completion_tag +struct get_completion_domain_t : ::beman::execution::forwarding_query_t { template - auto operator()(Q&& q, E&&... e) const { - using domain = decltype([&]{ - if constexpr (requires{ ::beman::execution::detail::try_query(::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); }) { - return ::beman::execution::detail::try_query(::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); - } else if constexpr (::std::same_as) { - return get_completion_domain_t<::beman::execution::set_value_t>()(::std::forward(q), ::std::forward(e)...); - } - else if constexpr (::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), get_completion_domain_t<::beman::execution::set_value_t>{}, ::std::forward(q), ::std::forward(e)...)) { - return ::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), get_completion_domain_t<::beman::execution::set_value_t>{}, ::std::forward(q), ::std::forward(e)...); - } else if constexpr (::beman::execution::scheduler && 0u != sizeof...(E)) { - return ::beman::execution::default_domain{}; - } - else { - static_assert(::std::same_as, "get_completion_domain requires the environment to be queryable for get_completion_domain or get_completion_scheduler"); - } - }()); + static auto impl(Q&& q, E&&... e) noexcept { + if constexpr (requires { + ::beman::execution::detail::try_query( + ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); + }) { + return ::beman::execution::detail::try_query( + ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); + } else if constexpr (::std::same_as) { + return get_completion_domain_t<::beman::execution::set_value_t>()(::std::forward(q), + ::std::forward(e)...); + } else if constexpr (requires { + ::beman::execution::detail::try_query( + ::beman::execution::get_completion_scheduler(q, e...), + get_completion_domain_t<::beman::execution::set_value_t>{}, + ::std::forward(q), + ::std::forward(e)...); + }) { + return ::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), + get_completion_domain_t<::beman::execution::set_value_t>{}, + ::std::forward(q), + ::std::forward(e)...); + } else if constexpr (::beman::execution::scheduler && 0u != sizeof...(E)) { + return ::beman::execution::default_domain{}; + } else { + static_assert(::std::same_as, + "get_completion_domain requires the environment to be queryable for get_completion_domain " + "or get_completion_scheduler"); + } + }; + + template <::beman::execution::detail::queryable Q, typename... E> + auto operator()(Q&&, E&&...) const noexcept { + using domain = decltype((impl)(::std::declval(), ::std::declval()...)); static_assert(noexcept(domain{}), "the domain's default constructor has to be noexcept"); return domain{}; } diff --git a/include/beman/execution/detail/get_completion_signatures.hpp b/include/beman/execution/detail/get_completion_signatures.hpp index 065a0721..74009235 100644 --- a/include/beman/execution/detail/get_completion_signatures.hpp +++ b/include/beman/execution/detail/get_completion_signatures.hpp @@ -18,7 +18,6 @@ import beman.execution.detail.await_result_type; import beman.execution.detail.completion_signatures; import beman.execution.detail.dependent_sender_error; import beman.execution.detail.env_promise; -import beman.execution.detail.get_domain_late; import beman.execution.detail.is_awaitable; import beman.execution.detail.is_constant; import beman.execution.detail.set_error; @@ -31,7 +30,6 @@ import beman.execution.detail.valid_completion_signatures; #include #include #include -#include #include #include #include @@ -51,8 +49,8 @@ struct get_completion_signatures_new_sender { template struct get_completion_signatures_new_sender { + // P3826R5: transform_sender(sndr, env) using type = decltype(::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_late(::std::declval(), ::std::declval()), ::std::declval(), ::std::declval())); }; diff --git a/include/beman/execution/detail/get_domain.hpp b/include/beman/execution/detail/get_domain.hpp index b16b25e1..ba573372 100644 --- a/include/beman/execution/detail/get_domain.hpp +++ b/include/beman/execution/detail/get_domain.hpp @@ -9,39 +9,42 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else +#include #include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.default_domain; import beman.execution.detail.forwarding_query; +import beman.execution.detail.get_scheduler; +import beman.execution.detail.hide_sched; +import beman.execution.detail.set_value; #else +#include #include +#include +#include +#include #endif // ---------------------------------------------------------------------------- namespace beman::execution { -struct get_domain_t { - template - requires(not requires(Object&& object, const get_domain_t& tag) { - ::std::forward(object).query(tag); - }) && (not requires(Object&& object, const get_domain_t& tag) { ::std::as_const(object).query(tag); }) - auto operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("object needs a query(get_domain_t) overload"); - template - requires(not requires(Object&& object, const get_domain_t& tag) { ::std::as_const(object).query(tag); }) - auto - operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("query(get_domain_t) overload needs to be const"); - template - requires(not requires(Object&& object, const get_domain_t& tag) { - { ::std::as_const(object).query(tag) } noexcept; - }) - auto - operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("query(get_domain_t) overload needs to be noexcept"); - - template - constexpr auto operator()(Object&& object) const noexcept { - return ::std::as_const(object).query(*this); +struct get_domain_t : ::beman::execution::forwarding_query_t { + template + constexpr auto operator()(Env&& env) const noexcept { + if constexpr (requires { ::std::as_const(env).query(*this); }) { + return ::std::as_const(env).query(*this); + } else if constexpr (requires { + ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( + ::beman::execution::get_scheduler(env), + ::beman::execution::detail::hide_sched(env)); + }) { + return ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( + ::beman::execution::get_scheduler(env), ::beman::execution::detail::hide_sched(env)); + } else { + return ::beman::execution::default_domain{}; + } } - constexpr auto query(const ::beman::execution::forwarding_query_t&) const noexcept -> bool { return true; } }; inline constexpr get_domain_t get_domain{}; diff --git a/include/beman/execution/detail/get_scheduler.hpp b/include/beman/execution/detail/get_scheduler.hpp index 914cd5ee..72d952f1 100644 --- a/include/beman/execution/detail/get_scheduler.hpp +++ b/include/beman/execution/detail/get_scheduler.hpp @@ -12,8 +12,14 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.forwarding_query; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.hide_sched; +import beman.execution.detail.set_value; #else #include +#include +#include +#include #endif // ---------------------------------------------------------------------------- @@ -23,12 +29,8 @@ struct get_scheduler_t : ::beman::execution::forwarding_query_t { template requires requires(const get_scheduler_t& self, Env&& env) { ::std::as_const(env).query(self); } auto operator()(Env&& env) const noexcept { - static_assert(noexcept(::std::as_const(env).query(*this))); - //-dk:TODO mandate that the result is a scheduler - // static_assert(::beman::execution::scheduler< - // decltype(::std::as_const(env).query(*this)) - // >) - return ::std::as_const(env).query(*this); + return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + ::std::as_const(env).query(get_scheduler_t{}), ::beman::execution::detail::hide_sched(env)); } }; diff --git a/include/beman/execution/detail/hide_query.hpp b/include/beman/execution/detail/hide_sched.hpp similarity index 66% rename from include/beman/execution/detail/hide_query.hpp rename to include/beman/execution/detail/hide_sched.hpp index ebb0d74b..3f88a824 100644 --- a/include/beman/execution/detail/hide_query.hpp +++ b/include/beman/execution/detail/hide_sched.hpp @@ -1,8 +1,8 @@ -// include/beman/execution/detail/hide_query.hpp -*-C++-*- +// include/beman/execution/detail/hide_sched.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_QUERY -#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_QUERY +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED #include #ifdef BEMAN_HAS_IMPORT_STD @@ -12,25 +12,29 @@ import std; #endif #if BEMAN_HAS_MODULES import beman.execution.detail.queryable; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_scheduler; #else #include -#include -#include #endif // ---------------------------------------------------------------------------- +namespace beman::execution { +struct get_domain_t; +struct get_scheduler_t; +} // namespace beman::execution + namespace beman::execution::detail { template <::beman::execution::detail::queryable Q> -struct hide_query_t { +struct hide_sched_t { template + requires requires { ::std::declval().query(::std::declval(), ::std::declval()...); } auto query(Tag&& tag, Args&&... args) const noexcept -> decltype(auto) { return q.query(::std::forward(tag), ::std::forward(args)...); } + template auto query(::beman::execution::get_domain_t, Args&&... args) const noexcept -> void = delete; + template auto query(::beman::execution::get_scheduler_t, Args&&... args) const noexcept -> void = delete; @@ -38,11 +42,11 @@ struct hide_query_t { }; template <::beman::execution::detail::queryable Q> -auto hide_query(const Q& q) noexcept { - return ::beman::execution::detail::hide_query_t{q}; +auto hide_sched(const Q& q) noexcept { + return ::beman::execution::detail::hide_sched_t{q}; } } // namespace beman::execution::detail // ---------------------------------------------------------------------------- -#endif +#endif // INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED diff --git a/include/beman/execution/detail/indeterminate_domain.hpp b/include/beman/execution/detail/indeterminate_domain.hpp index e0be40fa..ee977365 100644 --- a/include/beman/execution/detail/indeterminate_domain.hpp +++ b/include/beman/execution/detail/indeterminate_domain.hpp @@ -4,17 +4,80 @@ #ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN #define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN -// ---------------------------------------------------------------------------- +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.default_domain; +import beman.execution.detail.meta.unique; +import beman.execution.detail.queryable; +import beman.execution.detail.sender; +#else +#include +#include +#include +#include +#endif -namespace beman::execution::detail { -template -struct indeterminate_domain; -} +// ---------------------------------------------------------------------------- namespace beman::execution { -template -using indeterminate_domain = detail::indeterminate_domain; -} + +template +struct indeterminate_domain { + indeterminate_domain() = default; + + constexpr indeterminate_domain(const auto&) noexcept {} + + template + static constexpr auto transform_sender(Tag tag, Sndr&& sndr, const Env& env) noexcept( + noexcept(::beman::execution::default_domain{}.transform_sender(tag, ::std::forward(sndr), env))) + -> decltype(auto) { + constexpr auto make_new_sender = [&]() -> decltype(auto) { + return ::beman::execution::default_domain{}.transform_sender(tag, ::std::forward(sndr), env); + }; + (..., verify_mandates_<::std::decay_t, Domains, Tag, Sndr, Env>()); + return make_new_sender(); + } + + template + static consteval auto verify_mandates_() noexcept -> void { + if constexpr (requires { + ::std::declval().transform_sender( + ::std::declval(), ::std::declval(), ::std::declval()); + }) { + static_assert( + ::std::same_as<::std::decay_t().transform_sender( + ::std::declval(), ::std::declval(), ::std::declval()))>, + Expected>, + "indeterminate_domain: all possible domains must agree on the result " + "type of transform_sender, or be ill-formed for the given (Tag, Sndr, Env)"); + } + } +}; + +} // namespace beman::execution + +template +struct std::common_type<::beman::execution::indeterminate_domain, + ::beman::execution::indeterminate_domain> { + using type = + ::beman::execution::detail::meta::unique<::beman::execution::indeterminate_domain>; +}; + +template +struct std::common_type<::beman::execution::indeterminate_domain, D> { + using type = ::beman::execution::detail::meta::unique<::beman::execution::indeterminate_domain>; +}; + +template +struct std::common_type> + : ::std::common_type<::beman::execution::indeterminate_domain, D> {}; // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/inline_attrs.hpp b/include/beman/execution/detail/inline_attrs.hpp new file mode 100644 index 00000000..3a9750f8 --- /dev/null +++ b/include/beman/execution/detail/inline_attrs.hpp @@ -0,0 +1,46 @@ +// include/beman/execution/detail/inline_attrs.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_INLINE_ATTRS +#define INCLUDED_BEMAN_EXECUTION_DETAIL_INLINE_ATTRS + +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.get_domain; +import beman.execution.detail.get_scheduler; +#else +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +// inline-attrs per P3826R5 +// For a subexpression env: +// inline-attrs{}.query(get_completion_scheduler, env) = get_scheduler(env) +// inline-attrs{}.query(get_completion_domain, env) = get_domain(env) +template +struct inline_attrs { + template + requires requires(const Env& env) { ::beman::execution::get_scheduler(env); } + constexpr auto query(const ::beman::execution::get_completion_scheduler_t&, const Env& env) const noexcept { + return ::beman::execution::get_scheduler(env); + } + + template + requires requires(const Env& env) { ::beman::execution::get_domain(env); } + constexpr auto query(const auto& /*get_completion_domain_tag*/, const Env& env) const noexcept + -> decltype(::beman::execution::get_domain(env)) { + return ::beman::execution::get_domain(env); + } +}; + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_INLINE_ATTRS diff --git a/include/beman/execution/detail/inline_scheduler.hpp b/include/beman/execution/detail/inline_scheduler.hpp index ac2d364f..1e1b64ab 100644 --- a/include/beman/execution/detail/inline_scheduler.hpp +++ b/include/beman/execution/detail/inline_scheduler.hpp @@ -13,7 +13,6 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.sender; import beman.execution.detail.receiver; import beman.execution.detail.set_value; @@ -21,27 +20,23 @@ import beman.execution.detail.operation_state; import beman.execution.detail.scheduler; import beman.execution.detail.scheduler_t; import beman.execution.detail.completion_signatures; +import beman.execution.detail.inline_attrs; #else -#include #include #include #include #include #include #include +#include #endif namespace beman::execution { struct inline_scheduler { using scheduler_concept = ::beman::execution::scheduler_t; - struct env { - static auto - query(const ::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>&) noexcept - -> inline_scheduler { - return {}; - } - }; + // P3826R5: Use inline_attrs for sender env + using env = ::beman::execution::detail::inline_attrs<::beman::execution::set_value_t>; template <::beman::execution::receiver Rcvr> struct state { diff --git a/include/beman/execution/detail/into_variant.hpp b/include/beman/execution/detail/into_variant.hpp index 167e3892..2a73285c 100644 --- a/include/beman/execution/detail/into_variant.hpp +++ b/include/beman/execution/detail/into_variant.hpp @@ -25,7 +25,6 @@ import beman.execution.detail.dependent_sender_error; import beman.execution.detail.env; import beman.execution.detail.env_of_t; import beman.execution.detail.error_types_of_t; -import beman.execution.detail.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; @@ -35,7 +34,6 @@ import beman.execution.detail.sends_stopped; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; -import beman.execution.detail.transform_sender; import beman.execution.detail.value_types_of_t; import beman.execution.detail.variant_or_empty; #else @@ -48,7 +46,6 @@ import beman.execution.detail.variant_or_empty; #include #include #include -#include #include #include #include @@ -57,7 +54,6 @@ import beman.execution.detail.variant_or_empty; #include #include #include -#include #include #endif @@ -67,9 +63,7 @@ namespace beman::execution::detail { struct into_variant_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::sender Sender> auto operator()(Sender&& sender) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sender), - ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender))); + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)); } auto operator()() const noexcept { return ::beman::execution::detail::make_sender_adaptor(*this); } diff --git a/include/beman/execution/detail/let.hpp b/include/beman/execution/detail/let.hpp index c75065ce..951ba84c 100644 --- a/include/beman/execution/detail/let.hpp +++ b/include/beman/execution/detail/let.hpp @@ -35,7 +35,6 @@ import beman.execution.detail.get_env; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.join_env; import beman.execution.detail.make_env; @@ -55,7 +54,6 @@ import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; import beman.execution.detail.start; -import beman.execution.detail.transform_sender; import beman.execution.detail.type_list; #else #include @@ -69,7 +67,6 @@ import beman.execution.detail.type_list; #include #include #include -#include #include #include #include @@ -87,7 +84,6 @@ import beman.execution.detail.type_list; #include #include #include -#include #include #endif @@ -122,10 +118,7 @@ struct let_t { } template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun> auto operator()(Sender&& sender, Fun&& fun) const { - auto domain(::beman::execution::detail::get_domain_early(sender)); - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender(*this, ::std::forward(fun), std::forward(sender))); + return ::beman::execution::detail::make_sender(*this, ::std::forward(fun), std::forward(sender)); } template diff --git a/include/beman/execution/detail/not_a_scheduler.hpp b/include/beman/execution/detail/not_a_scheduler.hpp new file mode 100644 index 00000000..c70bb3fd --- /dev/null +++ b/include/beman/execution/detail/not_a_scheduler.hpp @@ -0,0 +1,33 @@ +// include/beman/execution/detail/not_a_scheduler.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_NOT_A_SCHEDULER +#define INCLUDED_BEMAN_EXECUTION_DETAIL_NOT_A_SCHEDULER + +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.scheduler_t; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +// Exposition-only not-a-scheduler type per P3826R5 +struct not_a_scheduler { + using scheduler_concept = ::beman::execution::scheduler_t; + + struct not_a_sender { + using sender_concept = void; // intentionally not a real sender + }; + + constexpr auto schedule() const noexcept -> not_a_sender { return {}; } +}; + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_NOT_A_SCHEDULER diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp index 84341323..6ca62d81 100644 --- a/include/beman/execution/detail/on.hpp +++ b/include/beman/execution/detail/on.hpp @@ -83,17 +83,17 @@ struct on_t : ::beman::execution::sender_adaptor_closure { } }; - template <::beman::execution::detail::sender_for OutSndr, typename Env> - auto transform_sender(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) { - struct not_a_scheduler {}; - // auto&& [_, data, child] = out_sndr; + // P3826R5: transform_sender now takes Tag as first param + template OutSndr, typename Env> + auto transform_sender(Tag, OutSndr&& out_sndr, const Env& env) const -> decltype(auto) { + struct not_a_scheduler_t {}; auto&& data = out_sndr.template get<1>(); auto&& child = out_sndr.template get<2>(); if constexpr (::beman::execution::scheduler) { auto sch{::beman::execution::detail::query_with_default( - ::beman::execution::get_scheduler, env, not_a_scheduler{})}; - if constexpr (::std::same_as) { + ::beman::execution::get_scheduler, env, not_a_scheduler_t{})}; + if constexpr (::std::same_as) { return env_needs_get_scheduler{}; } else { return ::beman::execution::continues_on( @@ -107,9 +107,9 @@ struct on_t : ::beman::execution::sender_adaptor_closure { ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>, ::beman::execution::get_env(child), ::beman::execution::detail::query_with_default( - ::beman::execution::get_scheduler, env, not_a_scheduler{}))}; + ::beman::execution::get_scheduler, env, not_a_scheduler_t{}))}; - if constexpr (::std::same_as) { + if constexpr (::std::same_as) { return env_needs_get_scheduler{}; } else { return ::beman::execution::write_env( @@ -138,23 +138,18 @@ struct on_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr> auto operator()(Sch&& sch, Sndr&& sndr) const { - auto domain{::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, sch, ::beman::execution::default_domain{})}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender(*this, ::std::forward(sch), ::std::forward(sndr))); + // P3826R5: No early customization + return ::beman::execution::detail::make_sender(*this, ::std::forward(sch), ::std::forward(sndr)); } template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr, ::beman::execution::detail::is_sender_adaptor_closure Closure> auto operator()(Sndr&& sndr, Sch&& sch, Closure&& closure) const { - auto domain{::beman::execution::detail::get_domain_early(sndr)}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::product_type{::std::forward(sch), ::std::forward(closure)}, - ::std::forward(sndr))); + // P3826R5: No early customization + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::product_type{::std::forward(sch), ::std::forward(closure)}, + ::std::forward(sndr)); } template <::beman::execution::scheduler Sch, ::beman::execution::detail::is_sender_adaptor_closure Closure> auto operator()(Sch&& sch, Closure&& closure) const { diff --git a/include/beman/execution/detail/prop.hpp b/include/beman/execution/detail/prop.hpp index a890006c..5918317f 100644 --- a/include/beman/execution/detail/prop.hpp +++ b/include/beman/execution/detail/prop.hpp @@ -52,7 +52,7 @@ struct beman::execution::prop { // auto operator=(prop&&) -> prop& = delete; // auto operator=(const prop&) -> prop& = delete; - constexpr auto query(Query) const noexcept -> const Value& { return this->value_; } + constexpr auto query(Query, auto&&...) const noexcept -> const Value& { return this->value_; } }; // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/schedule_from.hpp b/include/beman/execution/detail/schedule_from.hpp index cbbb67eb..c647251e 100644 --- a/include/beman/execution/detail/schedule_from.hpp +++ b/include/beman/execution/detail/schedule_from.hpp @@ -8,244 +8,54 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else -#include -#include -#include #include -#include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.as_tuple; -import beman.execution.detail.basic_sender; -import beman.execution.detail.child_type; -import beman.execution.detail.completion_signatures; -import beman.execution.detail.completion_signatures_for; -import beman.execution.detail.completion_signatures_of_t; -import beman.execution.detail.connect; -import beman.execution.detail.connect_result_t; -import beman.execution.detail.decayed_tuple; -import beman.execution.detail.default_domain; import beman.execution.detail.default_impls; -import beman.execution.detail.env_of_t; -import beman.execution.detail.error_types_of_t; import beman.execution.detail.fwd_env; -import beman.execution.detail.get_completion_signatures; -import beman.execution.detail.get_domain; import beman.execution.detail.get_env; -import beman.execution.detail.impls_for; -import beman.execution.detail.join_env; import beman.execution.detail.make_sender; -import beman.execution.detail.meta.combine; -import beman.execution.detail.meta.prepend; -import beman.execution.detail.meta.to; -import beman.execution.detail.meta.transform; -import beman.execution.detail.meta.unique; -import beman.execution.detail.query_with_default; -import beman.execution.detail.receiver; -import beman.execution.detail.sched_attrs; -import beman.execution.detail.schedule; -import beman.execution.detail.schedule_result_t; -import beman.execution.detail.scheduler; +import beman.execution.detail.product_type; import beman.execution.detail.sender; -import beman.execution.detail.sender_in; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.start; -import beman.execution.detail.transform_sender; #else -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { + +// P3826R5: schedule_from(sndr) = make_sender(schedule_from, {}, sndr) +// schedule_from(sndr) is semantically equivalent to sndr. +// It exists so it can be customized by schedulers to control how to +// transition off their execution contexts. struct schedule_from_t { - template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender> - auto operator()(Scheduler&& scheduler, Sender&& sender) const { - auto domain{::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, ::std::forward(scheduler), ::std::forward(sender))); + template <::beman::execution::sender Sender> + auto operator()(Sender&& sender) const { + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::product_type<>{}, + ::std::forward(sender)); } - private: - template - struct get_signatures; - template - struct get_signatures< - ::beman::execution::detail::basic_sender<::beman::execution::detail::schedule_from_t, Scheduler, Sender>, - Env> { - using scheduler_sender = decltype(::beman::execution::schedule(::std::declval())); - template - using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; - using type = ::beman::execution::detail::meta::combine< - decltype(::beman::execution::get_completion_signatures()), - ::beman::execution::error_types_of_t, - ::beman::execution::completion_signatures<::beman::execution::set_error_t( - ::std::exception_ptr)> //-dk:TODO this one should be deduced - >; - }; - - public: - template - static consteval auto get_completion_signatures() { - return typename get_signatures, Env...>::type{}; + // Legacy 2-arg overload for backward compatibility during transition + template + auto operator()(Scheduler&& /*scheduler*/, Sender&& sender) const { + // P3826R5: The new schedule_from only takes a sender. + // The old schedule_from(sch, sndr) behavior is now in continues_on. + return (*this)(::std::forward(sender)); } - - struct impls_for : ::beman::execution::detail::default_impls { - template - struct upstream_receiver { - using receiver_concept = ::beman::execution::receiver_t; - State* state; - - auto set_value() && noexcept -> void { - try { - ::std::visit( - [this](Tuple& result) noexcept -> void { - if constexpr (!::std::same_as<::std::monostate, Tuple>) { - ::std::apply( - [this](auto&& tag, auto&&... args) { - tag(::std::move(this->state->receiver), ::std::move(args)...); - }, - result); - } - }, - state->async_result); - } catch (...) { - ::beman::execution::set_error(::std::move(state->receiver), ::std::current_exception()); - } - } - - template - auto set_error(Error&& err) && noexcept -> void { - ::beman::execution::set_error(std::move(state->receiver), std::forward(err)); - } - - auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(std::move(state->receiver)); } - - auto get_env() const noexcept -> decltype(auto) { - return ::beman::execution::detail::fwd_env(::beman::execution::get_env(state->receiver)); - } - }; - template - struct state_base { - Receiver receiver; - Variant async_result{}; - }; - template - struct state_type : state_base { - using receiver_t = upstream_receiver>; - using operation_t = - ::beman::execution::connect_result_t<::beman::execution::schedule_result_t, receiver_t>; - operation_t op_state; - - static constexpr bool nothrow() { - return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval()), - receiver_t{nullptr})); - } - explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow()) - : state_base{rcvr}, - op_state(::beman::execution::connect(::beman::execution::schedule(sch), receiver_t{this})) {} - }; - - struct get_attrs_impl { - - auto operator()(const auto& data, const auto& child) const noexcept -> decltype(auto) { - return ::beman::execution::detail::join_env( - ::beman::execution::detail::sched_attrs(data), - ::beman::execution::detail::fwd_env(::beman::execution::get_env(child))); - } - }; - static constexpr auto get_attrs{get_attrs_impl{}}; - struct get_state_impl { - template - requires ::beman::execution::sender_in<::beman::execution::detail::child_type, - ::beman::execution::env_of_t> - auto operator()(Sender&& sender, Receiver& receiver) const //-dk:TODO noexcept(see below) - { - auto sch{sender.template get<1>()}; - - using sched_t = ::std::remove_cvref_t; - using variant_t = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend< - ::std::monostate, - ::beman::execution::detail::meta::transform< - ::beman::execution::detail::as_tuple_t, - ::beman::execution::detail::meta::to< - ::std::variant, - ::beman::execution::detail::meta::combine< - ::beman::execution::completion_signatures_of_t< - ::beman::execution::detail::child_type, - ::beman::execution::env_of_t>, - //-dk:TODO get proper error completion signatures - ::beman::execution::completion_signatures<::beman::execution::set_error_t( - ::std::exception_ptr), - ::beman::execution::set_stopped_t()>>>>>>; - - return state_type(sch, receiver); - }; - }; - static constexpr auto get_state{get_state_impl{}}; - struct complete_impl { - template - auto operator()(auto, auto& state, auto& receiver, Tag, Args&&... args) const noexcept -> void { - using result_t = ::beman::execution::detail::decayed_tuple; - constexpr bool nothrow = ::std::is_nothrow_constructible_v; - - try { - [&]() noexcept(nothrow) { - state.async_result.template emplace(Tag(), std::forward(args)...); - }(); - } catch (...) { - if constexpr (not nothrow) - ::beman::execution::set_error(::std::move(receiver), ::std::current_exception()); - } - - if (state.async_result.index() == 0) - return; - - ::beman::execution::start(state.op_state); - } - }; - static constexpr auto complete{complete_impl{}}; - }; }; } // namespace beman::execution::detail namespace beman::execution { -using schedule_from_t = beman::execution::detail::schedule_from_t; +using schedule_from_t = ::beman::execution::detail::schedule_from_t; inline constexpr ::beman::execution::schedule_from_t schedule_from{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/scheduler.hpp b/include/beman/execution/detail/scheduler.hpp index 5ddd4cde..643eb3b6 100644 --- a/include/beman/execution/detail/scheduler.hpp +++ b/include/beman/execution/detail/scheduler.hpp @@ -31,13 +31,15 @@ import beman.execution.detail.set_value; // ---------------------------------------------------------------------------- namespace beman::execution { +// P3826R5: Removed the required expression +// get_completion_scheduler(get_env(schedule(sch))) -> same_as +// from the scheduler concept. It is now a semantic requirement: +// If that expression is well-formed, it shall compare equal to sch. template concept scheduler = ::beman::execution::detail::almost_scheduler && requires(Scheduler&& sched) { - { - ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( - ::beman::execution::get_env(::beman::execution::schedule(::std::forward(sched)))) - } -> ::beman::execution::detail::decayed_same_as; -}; + { ::beman::execution::schedule(::std::forward(sched)) } -> ::beman::execution::sender; +} && ::std::equality_comparable<::std::remove_cvref_t> && + ::std::copyable<::std::remove_cvref_t>; } // namespace beman::execution // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/split.hpp b/include/beman/execution/detail/split.hpp index a573736d..810009c0 100644 --- a/include/beman/execution/detail/split.hpp +++ b/include/beman/execution/detail/split.hpp @@ -24,7 +24,6 @@ import beman.execution.detail.connect_result_t; import beman.execution.detail.default_impls; import beman.execution.detail.emplace_from; import beman.execution.detail.error_types_of_t; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_stop_token; import beman.execution.detail.impls_for; import beman.execution.detail.inplace_stop_source; @@ -50,7 +49,6 @@ import beman.execution.detail.value_types_of_t; #include #include #include -#include #include #include #include @@ -378,9 +376,7 @@ struct split_t { template requires beman::execution::sender_in::split_env> auto operator()(Sender&& sender) const { - auto domain{::beman::execution::detail::get_domain_early(sender)}; - return ::beman::execution::transform_sender( - domain, ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender))); + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)); } private: diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index bc0bc56a..d9fc44f0 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -31,7 +31,9 @@ import beman.execution.detail.transform_sender; #include #include #include +#include #include +#include #include #include #include @@ -46,30 +48,24 @@ import beman.execution.detail.transform_sender; namespace beman::execution::detail { struct starts_on_t { - template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename Env> - auto transform_env(Sender&& sender, Env&& env) const noexcept { - auto&& scheduler{sender.template get<1>()}; - return ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(scheduler), - ::beman::execution::detail::fwd_env(env)); - } - template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename... Env> - auto transform_sender(Sender&& sender, Env&&...) const noexcept { + // P3826R5: transform_sender now takes Tag as first param + template Sender, + typename Env> + auto transform_sender(Tag, Sender&& sender, const Env&) const noexcept { auto&& scheduler{sender.template get<1>()}; auto&& new_sender{sender.template get<2>()}; return ::beman::execution::let_value( - ::beman::execution::schedule(scheduler), + ::beman::execution::continues_on(::beman::execution::just(), scheduler), [new_sender = ::beman::execution::detail::forward_like(new_sender)]() mutable noexcept( ::std::is_nothrow_constructible_v<::std::decay_t>) { return ::std::move(new_sender); }); } + // P3826R5: No early customization - just return make_sender directly template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender> auto operator()(Scheduler&& scheduler, Sender&& sender) const { - auto domain{::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, ::std::forward(scheduler), ::std::forward(sender))); + return ::beman::execution::detail::make_sender( + *this, ::std::forward(scheduler), ::std::forward(sender)); } }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/stopped_as_error.hpp b/include/beman/execution/detail/stopped_as_error.hpp index f1ef5965..2f6ee763 100644 --- a/include/beman/execution/detail/stopped_as_error.hpp +++ b/include/beman/execution/detail/stopped_as_error.hpp @@ -14,7 +14,6 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; import beman.execution.detail.just; import beman.execution.detail.let; import beman.execution.detail.make_sender; @@ -22,10 +21,8 @@ import beman.execution.detail.movable_value; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; -import beman.execution.detail.transform_sender; #else #include -#include #include #include #include @@ -33,7 +30,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #endif namespace beman::execution::detail { @@ -53,10 +49,8 @@ struct stopped_as_error_t : ::beman::execution::sender_adaptor_closure auto operator()(Sndr&& sndr, Error error) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender( - stopped_as_error_t{}, std::move(error), ::std::forward(sndr))); + return ::beman::execution::detail::make_sender( + stopped_as_error_t{}, std::move(error), ::std::forward(sndr)); } template <::beman::execution::detail::movable_value Error> diff --git a/include/beman/execution/detail/stopped_as_optional.hpp b/include/beman/execution/detail/stopped_as_optional.hpp index 0f78efee..0d43d708 100644 --- a/include/beman/execution/detail/stopped_as_optional.hpp +++ b/include/beman/execution/detail/stopped_as_optional.hpp @@ -17,7 +17,6 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.child_type; import beman.execution.detail.fwd_env; -import beman.execution.detail.get_domain_early; import beman.execution.detail.just; import beman.execution.detail.let; import beman.execution.detail.make_sender; @@ -27,11 +26,9 @@ import beman.execution.detail.sender_for; import beman.execution.detail.single_sender; import beman.execution.detail.single_sender_value_type; import beman.execution.detail.then; -import beman.execution.detail.transform_sender; #else #include #include -#include #include #include #include @@ -41,7 +38,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #endif namespace beman::execution::detail { @@ -66,9 +62,7 @@ struct stopped_as_optional_t : ::beman::execution::sender_adaptor_closure auto operator()(Sndr&& sndr) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender(stopped_as_optional_t{}, {}, ::std::forward(sndr))); + return ::beman::execution::detail::make_sender(stopped_as_optional_t{}, {}, ::std::forward(sndr)); } auto operator()() const noexcept { return ::beman::execution::detail::make_sender_adaptor(*this); } diff --git a/include/beman/execution/detail/sync_wait.hpp b/include/beman/execution/detail/sync_wait.hpp index 253b52d6..ae18f3da 100644 --- a/include/beman/execution/detail/sync_wait.hpp +++ b/include/beman/execution/detail/sync_wait.hpp @@ -115,14 +115,14 @@ struct sync_wait_t { typename ::beman::execution::detail::sync_wait_result_type; { ::beman::execution::apply_sender( - ::beman::execution::detail::get_domain_early(std::forward(sender)), + ::beman::execution::default_domain{}, self, ::std::forward(sender)) } -> ::std::same_as<::beman::execution::detail::sync_wait_result_type>; } auto operator()(Sender&& sender) const { - auto domain{::beman::execution::detail::get_domain_early(sender)}; - return ::beman::execution::apply_sender(domain, *this, ::std::forward(sender)); + // P3826R5: Use default_domain for apply_sender + return ::beman::execution::apply_sender(::beman::execution::default_domain{}, *this, ::std::forward(sender)); } }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/sync_wait_with_variant.hpp b/include/beman/execution/detail/sync_wait_with_variant.hpp index cf2753fc..4e329d2d 100644 --- a/include/beman/execution/detail/sync_wait_with_variant.hpp +++ b/include/beman/execution/detail/sync_wait_with_variant.hpp @@ -59,8 +59,9 @@ struct sync_wait_with_variant_t { template requires requires { typename ::beman::execution::detail::sync_wait_with_variant_result_type; } auto operator()(Sndr&& sndr) const { + // P3826R5: Use default_domain for apply_sender return ::beman::execution::apply_sender( - ::beman::execution::detail::get_domain_early(sndr), *this, ::std::forward(sndr)); + ::beman::execution::default_domain{}, *this, ::std::forward(sndr)); } }; diff --git a/include/beman/execution/detail/then.hpp b/include/beman/execution/detail/then.hpp index 2f4b239d..6e6feffd 100644 --- a/include/beman/execution/detail/then.hpp +++ b/include/beman/execution/detail/then.hpp @@ -24,7 +24,6 @@ import beman.execution.detail.default_impls; import beman.execution.detail.dependent_sender; import beman.execution.detail.dependent_sender_error; import beman.execution.detail.env; -import beman.execution.detail.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; @@ -37,7 +36,7 @@ import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; -import beman.execution.detail.transform_sender; +import beman.execution.detail.sender_adaptor_closure; #else #include #include @@ -47,7 +46,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #include #include #include @@ -61,7 +59,7 @@ import beman.execution.detail.transform_sender; #include #include #include -#include +#include #endif // ---------------------------------------------------------------------------- @@ -117,10 +115,8 @@ struct then_t : ::beman::execution::sender_adaptor_closure> { } template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun> auto operator()(Sender&& sender, Fun&& fun) const { - auto domain{::beman::execution::detail::get_domain_early(sender)}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender(*this, ::std::forward(fun), ::std::forward(sender))); + // P3826R5: No early customization - just return make_sender directly + return ::beman::execution::detail::make_sender(*this, ::std::forward(fun), ::std::forward(sender)); } template <::beman::execution::sender Sender, typename Env> requires ::beman::execution::detail::nested_sender_has_affine_on diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index 491172e5..fee07be5 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -1,5 +1,5 @@ -// include/beman/execution/detail/transform_sender.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// include/beman/execution/detail/transform_sender.hpp _*_C++_*_ +// SPDX_License_Identifier: Apache_2.0 WITH LLVM_exception #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TRANSFORM_SENDER #define INCLUDED_BEMAN_EXECUTION_DETAIL_TRANSFORM_SENDER @@ -9,127 +9,76 @@ import std; #else #include +#include #include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.completion_domain; import beman.execution.detail.default_domain; +import beman.execution.detail.env_of_t; +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_domain; +import beman.execution.detail.get_env; 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 #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain, Sender&& sender, const Env&...) noexcept -> ::beman::execution::sender auto { - return ::std::forward(sender); -} -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (!::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept -> ::beman::execution::sender - decltype(auto) { - return ::beman::execution::detail::transform_sender( - dom, dom.transform_sender(::std::forward(sender), env...), env...); +template +auto transformed_sndr(Domain dom, Tag tag, Sndr&& sndr, const Env& env) -> decltype(auto) { + if constexpr (requires { dom.transform_sender(tag, ::std::forward(sndr), env); }) { + return dom.transform_sender(tag, ::std::forward(sndr), env); + } else { + return ::beman::execution::default_domain().transform_sender(tag, ::std::forward(sndr), env); + } } -template - requires(not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && ::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>> -constexpr auto - transform_sender(Domain, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward(sender))) - -> ::beman::execution::sender auto { - return sender; -} +template +struct transform_sndr_recurse { + constexpr transform_sndr_recurse(Domain, Tag) noexcept {} -template - requires(not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && - (!::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept(noexcept( - ::beman::execution::default_domain{}.transform_sender(::std::declval(), ::std::declval()...))) - -> ::beman::execution::sender decltype(auto) { - return ::beman::execution::detail::transform_sender( - dom, ::beman::execution::default_domain{}.transform_sender(::std::forward(sender), env...), env...); -} + template + auto operator()(Sndr&& sndr, const Env& env) -> decltype(auto) { + auto&& new_sndr = ::beman::execution::detail::transformed_sndr(Domain(), ::std::forward(sndr), env); + if constexpr (::std::same_as<::std::decay_t, ::std::decay_t>) { + return std::forward(new_sndr); + } else { + if constexpr (::std::same_as) { + auto new_dom = ::beman::execution::get_domain(env); + return transform_sndr_recurse{new_dom, Tag()}(::std::forward(new_sndr), env); + } else { + auto new_dom = ::beman::execution::detail::completion_domain(new_sndr, env); + return transform_sndr_recurse{new_dom, Tag()}(::std::forward(new_sndr), env); + } + } + } +}; } // namespace beman::execution::detail namespace beman::execution { -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain, Sender&& sender, const Env&...) noexcept -> ::beman::execution::sender - decltype(auto) { - return ::std::forward(sender); -} - -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (!::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept -> ::beman::execution::sender - auto { - return ::beman::execution::detail::transform_sender( - dom, dom.transform_sender(::std::forward(sender), env...), env...); -} - -template - requires(sizeof...(Env) < 2) && (not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && - ::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>> -constexpr auto - transform_sender(Domain, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward(sender))) - -> ::beman::execution::sender decltype(auto) { - return ::std::forward(sender); -} - -template - requires(sizeof...(Env) < 2) && (not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && - (!::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept( - noexcept(::beman::execution::detail::transform_sender( - dom, - ::beman::execution::default_domain{}.transform_sender(::std::declval(), ::std::declval()...), - env...))) -> ::beman::execution::sender decltype(auto) { - return ::beman::execution::detail::transform_sender( - dom, ::beman::execution::default_domain{}.transform_sender(::std::forward(sender), env...), env...); +template <::beman::execution::sender Sndr, typename Env> +auto transform_sender(Sndr&& sndr, const Env& env) -> ::beman::execution::sender decltype(auto) { + auto starting_domain = ::beman::execution::get_domain(env); + auto completion_domain = ::beman::execution::detail::completion_domain(sndr, env); + auto starting_transform = + ::beman::execution::detail::transform_sndr_recurse(starting_domain, ::beman::execution::start); + auto complete_transform = + ::beman::execution::detail::transform_sndr_recurse(completion_domain, ::beman::execution::set_value); + return starting_transform(complete_transform(::std::forward(sndr), env), env); } } // namespace beman::execution diff --git a/include/beman/execution/detail/when_all.hpp b/include/beman/execution/detail/when_all.hpp index ec6ab4be..caa28ea0 100644 --- a/include/beman/execution/detail/when_all.hpp +++ b/include/beman/execution/detail/when_all.hpp @@ -135,16 +135,11 @@ static_assert(std::same_as<::beman::execution::inplace_stop_token, ::std::declval>>()))>); struct when_all_t { + // P3826R5: No early customization - just return make_sender directly template <::beman::execution::sender... Sender> - requires(0u != sizeof...(Sender)) && (... && beman::execution::detail::valid_when_all_sender) && - requires(Sender&&... s) { - typename ::std::common_type_t; - } + requires(0u != sizeof...(Sender)) && (... && beman::execution::detail::valid_when_all_sender) auto operator()(Sender&&... sender) const { - using common_t = - typename ::std::common_type_t; - return ::beman::execution::transform_sender( - common_t(), ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...)); + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...); } private: @@ -186,13 +181,9 @@ struct when_all_t { struct impls_for : ::beman::execution::detail::default_impls { struct get_attrs_impl { - auto operator()(auto&&, auto&&... sender) const { - using common_t = - typename ::std::common_type_t; - if constexpr (::std::same_as) - return ::beman::execution::env<>{}; - else - return ::beman::execution::detail::make_env(::beman::execution::get_domain, common_t{}); + // P3826R5: get_attrs no longer computes domain from get_domain_early + auto operator()(auto&&, auto&&...) const { + return ::beman::execution::env<>{}; } }; static constexpr auto get_attrs{get_attrs_impl{}}; diff --git a/include/beman/execution/detail/when_all_with_variant.hpp b/include/beman/execution/detail/when_all_with_variant.hpp index 11eaf69d..53fe0815 100644 --- a/include/beman/execution/detail/when_all_with_variant.hpp +++ b/include/beman/execution/detail/when_all_with_variant.hpp @@ -35,9 +35,11 @@ import beman.execution.detail.when_all; namespace beman::execution::detail { struct when_all_with_variant_t { - // template <::beman::execution::detail::sender_for Sender> - template <::beman::execution::sender Sender> - auto transform_sender(Sender&& sender, auto&&...) const noexcept { + // P3826R5: transform_sender now takes Tag as first param + template Sender, + typename Env> + auto transform_sender(Tag, Sender&& sender, const Env&) const noexcept { return ::std::forward(sender).apply([](auto&&, auto&&, auto&&... child) { return ::beman::execution::when_all( ::beman::execution::into_variant(::beman::execution::detail::forward_like(child))...); @@ -46,10 +48,8 @@ struct when_all_with_variant_t { template <::beman::execution::sender... Sender> auto operator()(Sender&&... sender) const { - using domain_t = - typename ::std::common_type_t; - return ::beman::execution::transform_sender( - domain_t{}, ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...)); + // P3826R5: No early customization + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...); } }; } // namespace beman::execution::detail diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index a2c368ed..d170294d 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -97,7 +97,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_stop_token.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/hide_query.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/hide_sched.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/immovable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/impls_for.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indeterminate_domain.hpp @@ -294,7 +294,7 @@ if(BEMAN_USE_MODULES) get_stop_token.cppm has_as_awaitable.cppm has_completions.cppm - hide_query.cppm + hide_sched.cppm immovable.cppm impls_for.cppm indeterminate_domain.cppm diff --git a/src/beman/execution/hide_query.cppm b/src/beman/execution/hide_query.cppm deleted file mode 100644 index f01128f6..00000000 --- a/src/beman/execution/hide_query.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/hide_query.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.hide_query; - -namespace beman::execution::detail { -export using beman::execution::detail::hide_query; -} // namespace beman::execution::detail diff --git a/src/beman/execution/hide_sched.cppm b/src/beman/execution/hide_sched.cppm new file mode 100644 index 00000000..2a2dac47 --- /dev/null +++ b/src/beman/execution/hide_sched.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/hide_sched.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.hide_sched; + +namespace beman::execution::detail { +export using beman::execution::detail::hide_sched; +} // namespace beman::execution::detail diff --git a/tests/beman/execution/exec-queries-expos.test.cpp b/tests/beman/execution/exec-queries-expos.test.cpp index 87f5df34..01df2157 100644 --- a/tests/beman/execution/exec-queries-expos.test.cpp +++ b/tests/beman/execution/exec-queries-expos.test.cpp @@ -10,7 +10,7 @@ import beman.execution.detail.try_query; #else #include #include -#include +#include #include #endif @@ -68,10 +68,10 @@ auto test_try_query() -> void { template auto test_hide_query_exists(int expect, Q q, Tag&& tag, Args&&... args) -> void { static_assert(Value == requires { - test_detail::hide_query(q).query(::std::forward(tag), ::std::forward(args)...); + test_detail::hide_sched(q).query(::std::forward(tag), ::std::forward(args)...); }); if constexpr (Value) { - ASSERT(expect == test_detail::hide_query(q).query(::std::forward(tag), ::std::forward(args)...)); + ASSERT(expect == test_detail::hide_sched(q).query(::std::forward(tag), ::std::forward(args)...)); } } From ebde6457fdcb64fb6dc59b45ca29738776131014 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Fri, 24 Apr 2026 11:14:11 +0800 Subject: [PATCH 04/16] Fix some errors --- .../execution/detail/completion_domain.hpp | 2 + .../beman/execution/detail/default_domain.hpp | 3 +- .../detail/get_completion_domain.hpp | 16 ++- .../detail/get_completion_scheduler.hpp | 114 ++++++++---------- .../detail/get_completion_signatures.hpp | 1 - include/beman/execution/detail/get_domain.hpp | 2 + .../beman/execution/detail/get_scheduler.hpp | 2 +- include/beman/execution/detail/hide_sched.hpp | 1 + .../beman/execution/detail/inline_attrs.hpp | 9 +- .../execution/detail/inline_scheduler.hpp | 1 - .../execution/detail/not_a_scheduler.hpp | 33 ----- include/beman/execution/detail/scheduler.hpp | 17 +-- include/beman/execution/detail/starts_on.hpp | 5 +- include/beman/execution/detail/sync_wait.hpp | 6 +- .../detail/sync_wait_with_variant.hpp | 4 +- .../execution/detail/transform_sender.hpp | 9 +- src/beman/execution/CMakeLists.txt | 6 +- src/beman/execution/continues_on.cppm | 24 ---- src/beman/execution/inline_attrs.cppm | 11 ++ 19 files changed, 99 insertions(+), 167 deletions(-) delete mode 100644 include/beman/execution/detail/not_a_scheduler.hpp create mode 100644 src/beman/execution/inline_attrs.cppm diff --git a/include/beman/execution/detail/completion_domain.hpp b/include/beman/execution/detail/completion_domain.hpp index b6a518da..40b7aa8f 100644 --- a/include/beman/execution/detail/completion_domain.hpp +++ b/include/beman/execution/detail/completion_domain.hpp @@ -13,9 +13,11 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.default_domain; import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_env; #else #include #include +#include #endif // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/default_domain.hpp b/include/beman/execution/detail/default_domain.hpp index 37cf86a7..d96cb06b 100644 --- a/include/beman/execution/detail/default_domain.hpp +++ b/include/beman/execution/detail/default_domain.hpp @@ -52,8 +52,7 @@ struct default_domain { tag.apply_sender(::std::forward(sender), ::std::forward(args)...); } static constexpr auto apply_sender(Tag tag, Sender&& sender, Args&&... args) noexcept( - noexcept(tag.apply_sender(::std::forward(sender), ::std::forward(args)...))) - -> decltype(auto) { + noexcept(tag.apply_sender(::std::forward(sender), ::std::forward(args)...))) -> decltype(auto) { return tag.apply_sender(::std::forward(sender), ::std::forward(args)...); } }; diff --git a/include/beman/execution/detail/get_completion_domain.hpp b/include/beman/execution/detail/get_completion_domain.hpp index fe2a42cf..d368bb8f 100644 --- a/include/beman/execution/detail/get_completion_domain.hpp +++ b/include/beman/execution/detail/get_completion_domain.hpp @@ -35,6 +35,8 @@ import beman.execution.detail.try_query; // ---------------------------------------------------------------------------- namespace beman::execution::detail { +struct no_completion_domain {}; + template requires ::std::same_as || ::beman::execution::detail::completion_tag struct get_completion_domain_t : ::beman::execution::forwarding_query_t { @@ -47,8 +49,8 @@ struct get_completion_domain_t : ::beman::execution::forwarding_query_t { return ::beman::execution::detail::try_query( ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); } else if constexpr (::std::same_as) { - return get_completion_domain_t<::beman::execution::set_value_t>()(::std::forward(q), - ::std::forward(e)...); + return get_completion_domain_t<::beman::execution::set_value_t>::impl(::std::forward(q), + ::std::forward(e)...); } else if constexpr (requires { ::beman::execution::detail::try_query( ::beman::execution::get_completion_scheduler(q, e...), @@ -63,15 +65,17 @@ struct get_completion_domain_t : ::beman::execution::forwarding_query_t { } else if constexpr (::beman::execution::scheduler && 0u != sizeof...(E)) { return ::beman::execution::default_domain{}; } else { - static_assert(::std::same_as, - "get_completion_domain requires the environment to be queryable for get_completion_domain " - "or get_completion_scheduler"); + return ::beman::execution::detail::no_completion_domain{}; } }; + template + using domain_of = decltype((impl)(::std::declval(), ::std::declval()...)); + template <::beman::execution::detail::queryable Q, typename... E> + requires(!::std::same_as, ::beman::execution::detail::no_completion_domain>) auto operator()(Q&&, E&&...) const noexcept { - using domain = decltype((impl)(::std::declval(), ::std::declval()...)); + using domain = domain_of; static_assert(noexcept(domain{}), "the domain's default constructor has to be noexcept"); return domain{}; } diff --git a/include/beman/execution/detail/get_completion_scheduler.hpp b/include/beman/execution/detail/get_completion_scheduler.hpp index 4a9b771d..23717339 100644 --- a/include/beman/execution/detail/get_completion_scheduler.hpp +++ b/include/beman/execution/detail/get_completion_scheduler.hpp @@ -14,86 +14,76 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.almost_scheduler; import beman.execution.detail.completion_tag; -import beman.execution.detail.decayed_same_as; import beman.execution.detail.forwarding_query; -import beman.execution.detail.get_env; -import beman.execution.detail.schedule; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; +import beman.execution.detail.scheduler; import beman.execution.detail.set_value; #else -#include #include -#include #include -#include -#include -#include -#include +#include #include #endif // ---------------------------------------------------------------------------- -namespace beman::execution { -template -struct get_completion_scheduler_t; +namespace beman::execution::detail { +template +auto recurse_query(Scheduler sch, const Envs&... envs) noexcept; -template -struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { - template - requires(not requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - env.query(self); - }) - auto operator()(Env&&) const noexcept = - BEMAN_EXECUTION_DELETE("The environment needs a query(get_completion_scheduler_t) member"); +template <::beman::execution::detail::completion_tag Tag> +struct get_completion_scheduler_t; - template - requires(requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - env.query(self); - } && (not requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept; - })) - auto operator()(Env&&) const noexcept = - BEMAN_EXECUTION_DELETE("The environment's query(get_completion_scheduler_t) has to be noexcept"); +template +concept has_completion_scheduler = requires { + ::beman::execution::detail::recurse_query( + ::std::declval().query(::std::declval<::beman::execution::detail::get_completion_scheduler_t>(), + ::std::declval()...), + ::std::declval()...); +} || (::beman::execution::scheduler && sizeof...(E) > 0); - template - requires( - requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - env.query(self); - } && - requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept; - } && - (not requires(const get_completion_scheduler_t& self, - const get_completion_scheduler_t<::beman::execution::set_value_t>& value_self, - const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept -> ::beman::execution::detail::almost_scheduler; - { - ::beman::execution::get_env(::beman::execution::schedule(env.query(self))) - .query(value_self) - } -> ::beman::execution::detail::decayed_same_as; - })) - auto operator()(Env&&) const noexcept = - BEMAN_EXECUTION_DELETE("The environment's query(get_completion_scheduler_t) has to return a scheduler"); +template <::beman::execution::detail::completion_tag Tag> +struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { + template + requires ::beman::execution::detail::has_completion_scheduler + auto operator()(const Q& q, const E&... e) const noexcept; +}; - template - requires requires(const get_completion_scheduler_t& self, - const get_completion_scheduler_t<::beman::execution::set_value_t>& value_self, - const ::std::remove_cvref_t& env, - const ::std::remove_cvref_t&... e) { - { env.query(self, e...) } noexcept -> ::beman::execution::detail::almost_scheduler; - { - ::beman::execution::get_env(::beman::execution::schedule(env.query(self))).query(value_self, e...) - } -> ::beman::execution::detail::decayed_same_as; +template +auto recurse_query(Scheduler sch, const Envs&... envs) noexcept { + get_completion_scheduler_t<::beman::execution::set_value_t> get_compl_sch{}; + if constexpr (requires { ::std::as_const(sch).query(get_compl_sch, envs...); }) { + auto sch2 = ::std::as_const(sch).query(get_compl_sch, envs...); + if constexpr (::std::same_as) { + while (sch != sch2) { + sch = ::std::exchange(sch2, ::std::as_const(sch2).query(get_compl_sch, envs...)); + } + return sch; + } else { + return (recurse_query)(sch2, envs...); } - auto operator()(Env&& env, E&&... e) const noexcept { - return ::std::as_const(env).query(*this, e...); + } else { + return sch; } -}; +} + +template <::beman::execution::detail::completion_tag Tag> +template + requires ::beman::execution::detail::has_completion_scheduler +auto get_completion_scheduler_t::operator()(const Q& q, const E&... e) const noexcept { + if constexpr (requires { ::beman::execution::detail::recurse_query(q.query(*this, e...), e...); }) { + return ::beman::execution::detail::recurse_query(q.query(*this, e...), e...); + } else { + static_assert(::beman::execution::scheduler && sizeof...(E) > 0); + return q; + } +} +} // namespace beman::execution::detail + +namespace beman::execution { +template <::beman::execution::detail::completion_tag Tag> +using get_completion_scheduler_t = ::beman::execution::detail::get_completion_scheduler_t; template <::beman::execution::detail::completion_tag Tag> inline constexpr get_completion_scheduler_t get_completion_scheduler{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/get_completion_signatures.hpp b/include/beman/execution/detail/get_completion_signatures.hpp index 74009235..aceb6533 100644 --- a/include/beman/execution/detail/get_completion_signatures.hpp +++ b/include/beman/execution/detail/get_completion_signatures.hpp @@ -49,7 +49,6 @@ struct get_completion_signatures_new_sender { template struct get_completion_signatures_new_sender { - // P3826R5: transform_sender(sndr, env) using type = decltype(::beman::execution::transform_sender( ::std::declval(), ::std::declval())); diff --git a/include/beman/execution/detail/get_domain.hpp b/include/beman/execution/detail/get_domain.hpp index ba573372..6c2322ff 100644 --- a/include/beman/execution/detail/get_domain.hpp +++ b/include/beman/execution/detail/get_domain.hpp @@ -15,12 +15,14 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.default_domain; import beman.execution.detail.forwarding_query; +import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_scheduler; import beman.execution.detail.hide_sched; import beman.execution.detail.set_value; #else #include #include +#include #include #include #include diff --git a/include/beman/execution/detail/get_scheduler.hpp b/include/beman/execution/detail/get_scheduler.hpp index 72d952f1..963c69f2 100644 --- a/include/beman/execution/detail/get_scheduler.hpp +++ b/include/beman/execution/detail/get_scheduler.hpp @@ -30,7 +30,7 @@ struct get_scheduler_t : ::beman::execution::forwarding_query_t { requires requires(const get_scheduler_t& self, Env&& env) { ::std::as_const(env).query(self); } auto operator()(Env&& env) const noexcept { return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( - ::std::as_const(env).query(get_scheduler_t{}), ::beman::execution::detail::hide_sched(env)); + ::std::as_const(env).query(*this), ::beman::execution::detail::hide_sched(env)); } }; diff --git a/include/beman/execution/detail/hide_sched.hpp b/include/beman/execution/detail/hide_sched.hpp index 3f88a824..09a432ca 100644 --- a/include/beman/execution/detail/hide_sched.hpp +++ b/include/beman/execution/detail/hide_sched.hpp @@ -9,6 +9,7 @@ import std; #else #include +#include #endif #if BEMAN_HAS_MODULES import beman.execution.detail.queryable; diff --git a/include/beman/execution/detail/inline_attrs.hpp b/include/beman/execution/detail/inline_attrs.hpp index 3a9750f8..5e2988f4 100644 --- a/include/beman/execution/detail/inline_attrs.hpp +++ b/include/beman/execution/detail/inline_attrs.hpp @@ -6,10 +6,12 @@ #include #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_domain; import beman.execution.detail.get_scheduler; #else +#include #include #include #include @@ -19,10 +21,6 @@ import beman.execution.detail.get_scheduler; namespace beman::execution::detail { -// inline-attrs per P3826R5 -// For a subexpression env: -// inline-attrs{}.query(get_completion_scheduler, env) = get_scheduler(env) -// inline-attrs{}.query(get_completion_domain, env) = get_domain(env) template struct inline_attrs { template @@ -33,8 +31,7 @@ struct inline_attrs { template requires requires(const Env& env) { ::beman::execution::get_domain(env); } - constexpr auto query(const auto& /*get_completion_domain_tag*/, const Env& env) const noexcept - -> decltype(::beman::execution::get_domain(env)) { + constexpr auto query(const ::beman::execution::get_completion_domain_t&, const Env& env) const noexcept { return ::beman::execution::get_domain(env); } }; diff --git a/include/beman/execution/detail/inline_scheduler.hpp b/include/beman/execution/detail/inline_scheduler.hpp index 1e1b64ab..eca5164a 100644 --- a/include/beman/execution/detail/inline_scheduler.hpp +++ b/include/beman/execution/detail/inline_scheduler.hpp @@ -35,7 +35,6 @@ namespace beman::execution { struct inline_scheduler { using scheduler_concept = ::beman::execution::scheduler_t; - // P3826R5: Use inline_attrs for sender env using env = ::beman::execution::detail::inline_attrs<::beman::execution::set_value_t>; template <::beman::execution::receiver Rcvr> diff --git a/include/beman/execution/detail/not_a_scheduler.hpp b/include/beman/execution/detail/not_a_scheduler.hpp deleted file mode 100644 index c70bb3fd..00000000 --- a/include/beman/execution/detail/not_a_scheduler.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// include/beman/execution/detail/not_a_scheduler.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_NOT_A_SCHEDULER -#define INCLUDED_BEMAN_EXECUTION_DETAIL_NOT_A_SCHEDULER - -#include -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.scheduler_t; -#else -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { - -// Exposition-only not-a-scheduler type per P3826R5 -struct not_a_scheduler { - using scheduler_concept = ::beman::execution::scheduler_t; - - struct not_a_sender { - using sender_concept = void; // intentionally not a real sender - }; - - constexpr auto schedule() const noexcept -> not_a_sender { return {}; } -}; - -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_NOT_A_SCHEDULER diff --git a/include/beman/execution/detail/scheduler.hpp b/include/beman/execution/detail/scheduler.hpp index 643eb3b6..465304d7 100644 --- a/include/beman/execution/detail/scheduler.hpp +++ b/include/beman/execution/detail/scheduler.hpp @@ -14,32 +14,21 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.almost_scheduler; -import beman.execution.detail.decayed_same_as; -import beman.execution.detail.get_completion_scheduler; -import beman.execution.detail.get_env; import beman.execution.detail.schedule; -import beman.execution.detail.set_value; +import beman.execution.detail.sender; #else #include -#include -#include -#include #include -#include +#include #endif // ---------------------------------------------------------------------------- namespace beman::execution { -// P3826R5: Removed the required expression -// get_completion_scheduler(get_env(schedule(sch))) -> same_as -// from the scheduler concept. It is now a semantic requirement: -// If that expression is well-formed, it shall compare equal to sch. template concept scheduler = ::beman::execution::detail::almost_scheduler && requires(Scheduler&& sched) { { ::beman::execution::schedule(::std::forward(sched)) } -> ::beman::execution::sender; -} && ::std::equality_comparable<::std::remove_cvref_t> && - ::std::copyable<::std::remove_cvref_t>; +} && ::std::equality_comparable<::std::remove_cvref_t> && ::std::copyable<::std::remove_cvref_t>; } // namespace beman::execution // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index d9fc44f0..a7e0a3f6 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -12,11 +12,13 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.continues_on; import beman.execution.detail.default_domain; import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; import beman.execution.detail.get_domain; import beman.execution.detail.join_env; +import beman.execution.detail.just; import beman.execution.detail.let; import beman.execution.detail.make_sender; import beman.execution.detail.query_with_default; @@ -27,6 +29,7 @@ import beman.execution.detail.sender; import beman.execution.detail.sender_for; import beman.execution.detail.transform_sender; #else +#include #include #include #include @@ -48,7 +51,6 @@ import beman.execution.detail.transform_sender; namespace beman::execution::detail { struct starts_on_t { - // P3826R5: transform_sender now takes Tag as first param template Sender, typename Env> @@ -61,7 +63,6 @@ struct starts_on_t { ::std::is_nothrow_constructible_v<::std::decay_t>) { return ::std::move(new_sender); }); } - // P3826R5: No early customization - just return make_sender directly template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender> auto operator()(Scheduler&& scheduler, Sender&& sender) const { return ::beman::execution::detail::make_sender( diff --git a/include/beman/execution/detail/sync_wait.hpp b/include/beman/execution/detail/sync_wait.hpp index ae18f3da..6d1441d0 100644 --- a/include/beman/execution/detail/sync_wait.hpp +++ b/include/beman/execution/detail/sync_wait.hpp @@ -18,13 +18,12 @@ import beman.execution.detail.apply_sender; import beman.execution.detail.as_except_ptr; import beman.execution.detail.connect; import beman.execution.detail.decayed_tuple; +import beman.execution.detail.default_domain; import beman.execution.detail.get_delegation_scheduler; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_scheduler; import beman.execution.detail.receiver; import beman.execution.detail.run_loop; import beman.execution.detail.sender_in; -import beman.execution.detail.sender_in; import beman.execution.detail.start; import beman.execution.detail.value_types_of_t; #else @@ -32,13 +31,12 @@ import beman.execution.detail.value_types_of_t; #include #include #include +#include #include -#include #include #include #include #include -#include #include #include #endif diff --git a/include/beman/execution/detail/sync_wait_with_variant.hpp b/include/beman/execution/detail/sync_wait_with_variant.hpp index 4e329d2d..9e9b41c3 100644 --- a/include/beman/execution/detail/sync_wait_with_variant.hpp +++ b/include/beman/execution/detail/sync_wait_with_variant.hpp @@ -16,7 +16,7 @@ import std; import beman.execution.detail.apply_sender; import beman.execution.detail.callable; import beman.execution.detail.call_result_t; -import beman.execution.detail.get_domain_early; +import beman.execution.detail.default_domain; import beman.execution.detail.into_variant; import beman.execution.detail.sender_in; import beman.execution.detail.sync_wait; @@ -25,7 +25,7 @@ import beman.execution.detail.value_types_of_t; #include #include #include -#include +#include #include #include #include diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index fee07be5..db14488a 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -15,20 +15,14 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.completion_domain; import beman.execution.detail.default_domain; -import beman.execution.detail.env_of_t; -import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; 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 @@ -53,7 +47,8 @@ struct transform_sndr_recurse { template auto operator()(Sndr&& sndr, const Env& env) -> decltype(auto) { - auto&& new_sndr = ::beman::execution::detail::transformed_sndr(Domain(), ::std::forward(sndr), env); + decltype(auto) new_sndr = + ::beman::execution::detail::transformed_sndr(Domain(), Tag(), ::std::forward(sndr), env); if constexpr (::std::same_as<::std::decay_t, ::std::decay_t>) { return std::forward(new_sndr); } else { diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index d170294d..5b20ae0f 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -97,12 +97,13 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_stop_token.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/hide_sched.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/hide_sched.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/immovable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/impls_for.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indeterminate_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indices_for.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indirect_meta_apply.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/inline_attrs.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/inline_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/inplace_stop_source.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/into_variant.hpp @@ -294,12 +295,13 @@ if(BEMAN_USE_MODULES) get_stop_token.cppm has_as_awaitable.cppm has_completions.cppm - hide_sched.cppm + hide_sched.cppm immovable.cppm impls_for.cppm indeterminate_domain.cppm indices_for.cppm indirect_meta_apply.cppm + inline_attrs.cppm inline_scheduler.cppm inplace_stop_source.cppm into_variant.cppm diff --git a/src/beman/execution/continues_on.cppm b/src/beman/execution/continues_on.cppm index 38b22d7a..d222dd4e 100644 --- a/src/beman/execution/continues_on.cppm +++ b/src/beman/execution/continues_on.cppm @@ -10,27 +10,3 @@ namespace beman::execution { export using beman::execution::continues_on_t; export using beman::execution::continues_on; } // namespace beman::execution - -namespace beman::execution::detail { -export template -auto get_domain_late( - const ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>& sender, Env&&) { - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -export template -auto get_domain_late( - ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>&& sender, Env&&) { - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -export template -auto get_domain_late( - ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>& sender, Env&&) { - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -} // namespace beman::execution::detail diff --git a/src/beman/execution/inline_attrs.cppm b/src/beman/execution/inline_attrs.cppm new file mode 100644 index 00000000..70bc9e5d --- /dev/null +++ b/src/beman/execution/inline_attrs.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/inline_attrs.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.inline_attrs; + +namespace beman::execution::detail { +export using beman::execution::detail::inline_attrs; +} // namespace beman::execution::detail From cda8075b8de6b7caef76456138416197170f9ce7 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Fri, 24 Apr 2026 17:03:02 +0800 Subject: [PATCH 05/16] Remove `get_domain_early` and `get_domain_late` --- include/beman/execution/detail/connect.hpp | 1 - .../execution/detail/get_domain_early.hpp | 36 --------- .../execution/detail/get_domain_late.hpp | 76 ------------------- include/beman/execution/detail/on.hpp | 2 - include/beman/execution/detail/when_all.hpp | 4 - .../detail/when_all_with_variant.hpp | 2 - src/beman/execution/CMakeLists.txt | 4 - src/beman/execution/execution-detail.cppm | 2 - src/beman/execution/get_domain_early.cppm | 11 --- src/beman/execution/get_domain_late.cppm | 11 --- 10 files changed, 149 deletions(-) delete mode 100644 include/beman/execution/detail/get_domain_early.hpp delete mode 100644 include/beman/execution/detail/get_domain_late.hpp delete mode 100644 src/beman/execution/get_domain_early.cppm delete mode 100644 src/beman/execution/get_domain_late.cppm diff --git a/include/beman/execution/detail/connect.hpp b/include/beman/execution/detail/connect.hpp index 9a4f7a3d..aab16bfb 100644 --- a/include/beman/execution/detail/connect.hpp +++ b/include/beman/execution/detail/connect.hpp @@ -39,7 +39,6 @@ struct connect_t { static auto make_new_sender(Sender&& sender, Receiver&& receiver) //-dk:TODO this noexcept needs to get confirmed/fixed noexcept(true) -> decltype(auto) { - // P3826R5: transform_sender(sndr, get_env(rcvr)) return ::beman::execution::transform_sender( ::std::forward(sender), ::beman::execution::get_env(receiver)); diff --git a/include/beman/execution/detail/get_domain_early.hpp b/include/beman/execution/detail/get_domain_early.hpp deleted file mode 100644 index 13e40915..00000000 --- a/include/beman/execution/detail/get_domain_early.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// include/beman/execution/detail/get_domain_early.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_EARLY -#define INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_EARLY - -#include -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.completion_domain; -import beman.execution.detail.default_domain; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -#else -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -template -constexpr auto get_domain_early(const Sender& sender) noexcept { - if constexpr (requires { ::beman::execution::get_domain(::beman::execution::get_env(sender)); }) - return decltype(::beman::execution::get_domain(::beman::execution::get_env(sender))){}; - else if constexpr (requires { ::beman::execution::detail::completion_domain(sender); }) - return decltype(::beman::execution::detail::completion_domain(sender)){}; - else - return ::beman::execution::default_domain{}; -} -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_EARLY diff --git a/include/beman/execution/detail/get_domain_late.hpp b/include/beman/execution/detail/get_domain_late.hpp deleted file mode 100644 index 147c1767..00000000 --- a/include/beman/execution/detail/get_domain_late.hpp +++ /dev/null @@ -1,76 +0,0 @@ -// include/beman/execution/detail/get_domain_late.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_LATE -#define INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_LATE - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#endif -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.completion_domain; -import beman.execution.detail.default_domain; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -import beman.execution.detail.get_scheduler; -import beman.execution.detail.sender_decompose; -import beman.execution.detail.tag_of_t; -#else -#include -#include -#include -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -template -concept not_void = !::std::same_as; - -template -struct get_domain_late_helper { - template - static constexpr auto get(const Sender& sender, const Env& env) noexcept { - if constexpr (requires { - { - ::beman::execution::get_domain(::beman::execution::get_env(sender)) - } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::get_domain(::beman::execution::get_env(sender)); - else if constexpr (requires { - { - ::beman::execution::detail::completion_domain(sender) - } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::detail::completion_domain(sender); - else if constexpr (requires { - { ::beman::execution::get_domain(env) } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::get_domain(env); - else if constexpr (requires { - { - ::beman::execution::get_domain(::beman::execution::get_scheduler(env)) - } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::get_domain(::beman::execution::get_scheduler(env)); - else - return ::beman::execution::default_domain(); - } -}; -template -constexpr auto get_domain_late(const Sender& sender, const Env& env) noexcept { - using tag_t = ::beman::execution::tag_of_t; - return ::beman::execution::detail::get_domain_late_helper::get(sender, env); -} -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_LATE diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp index 6ca62d81..1d5e982a 100644 --- a/include/beman/execution/detail/on.hpp +++ b/include/beman/execution/detail/on.hpp @@ -19,7 +19,6 @@ import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_env; import beman.execution.detail.get_scheduler; import beman.execution.detail.join_env; @@ -41,7 +40,6 @@ import beman.execution.detail.write_env; #include #include #include -#include #include #include #include diff --git a/include/beman/execution/detail/when_all.hpp b/include/beman/execution/detail/when_all.hpp index caa28ea0..2dea4379 100644 --- a/include/beman/execution/detail/when_all.hpp +++ b/include/beman/execution/detail/when_all.hpp @@ -33,7 +33,6 @@ import beman.execution.detail.env_of_t; import beman.execution.detail.error_types_of_t; import beman.execution.detail.get_env; import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_stop_token; import beman.execution.detail.impls_for; import beman.execution.detail.inplace_stop_source; @@ -73,7 +72,6 @@ import beman.execution.detail.value_types_of_t; #include #include #include -#include #include #include #include @@ -135,7 +133,6 @@ static_assert(std::same_as<::beman::execution::inplace_stop_token, ::std::declval>>()))>); struct when_all_t { - // P3826R5: No early customization - just return make_sender directly template <::beman::execution::sender... Sender> requires(0u != sizeof...(Sender)) && (... && beman::execution::detail::valid_when_all_sender) auto operator()(Sender&&... sender) const { @@ -181,7 +178,6 @@ struct when_all_t { struct impls_for : ::beman::execution::detail::default_impls { struct get_attrs_impl { - // P3826R5: get_attrs no longer computes domain from get_domain_early auto operator()(auto&&, auto&&...) const { return ::beman::execution::env<>{}; } diff --git a/include/beman/execution/detail/when_all_with_variant.hpp b/include/beman/execution/detail/when_all_with_variant.hpp index 53fe0815..a802e9b9 100644 --- a/include/beman/execution/detail/when_all_with_variant.hpp +++ b/include/beman/execution/detail/when_all_with_variant.hpp @@ -13,7 +13,6 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; import beman.execution.detail.into_variant; import beman.execution.detail.make_sender; import beman.execution.detail.sender; @@ -22,7 +21,6 @@ import beman.execution.detail.transform_sender; import beman.execution.detail.when_all; #else #include -#include #include #include #include diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 5b20ae0f..387c7aba 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -89,8 +89,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_completion_signatures.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_delegation_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_domain.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_domain_early.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_domain_late.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_forward_progress_guarantee.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_scheduler.hpp @@ -286,8 +284,6 @@ if(BEMAN_USE_MODULES) get_completion_scheduler.cppm get_completion_signatures.cppm get_delegation_scheduler.cppm - get_domain_early.cppm - get_domain_late.cppm get_domain.cppm get_env.cppm get_forward_progress_guarantee.cppm diff --git a/src/beman/execution/execution-detail.cppm b/src/beman/execution/execution-detail.cppm index 568be1bb..c9dac2c4 100644 --- a/src/beman/execution/execution-detail.cppm +++ b/src/beman/execution/execution-detail.cppm @@ -32,8 +32,6 @@ export import beman.execution.detail.forward_like; export import beman.execution.detail.fwd_env; export import beman.execution.detail.gather_signatures; export import beman.execution.detail.get_awaiter; -export import beman.execution.detail.get_domain_early; -export import beman.execution.detail.get_domain_late; export import beman.execution.detail.has_as_awaitable; export import beman.execution.detail.has_completions; export import beman.execution.detail.immovable; diff --git a/src/beman/execution/get_domain_early.cppm b/src/beman/execution/get_domain_early.cppm deleted file mode 100644 index 05fb99f9..00000000 --- a/src/beman/execution/get_domain_early.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/get_domain_early.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.get_domain_early; - -namespace beman::execution::detail { -export using beman::execution::detail::get_domain_early; -} // namespace beman::execution::detail diff --git a/src/beman/execution/get_domain_late.cppm b/src/beman/execution/get_domain_late.cppm deleted file mode 100644 index 35296e11..00000000 --- a/src/beman/execution/get_domain_late.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/get_domain_late.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.get_domain_late; - -namespace beman::execution::detail { -export using beman::execution::detail::get_domain_late; -} // namespace beman::execution::detail From 78811a8c63e07097a03dab89af4d56547833ca16 Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Sun, 26 Apr 2026 18:18:26 +0800 Subject: [PATCH 06/16] Refactor sender-algorithms --- include/beman/execution/detail/affine_on.hpp | 2 +- include/beman/execution/detail/bulk.hpp | 2 +- .../execution/detail/completion_domain.hpp | 8 ++- .../beman/execution/detail/continues_on.hpp | 57 ++++++----------- include/beman/execution/detail/on.hpp | 42 +++---------- .../execution/detail/query_with_default.hpp | 13 ++++ .../beman/execution/detail/sched_attrs.hpp | 61 ------------------- .../beman/execution/detail/schedule_from.hpp | 31 +++------- include/beman/execution/detail/split.hpp | 4 +- include/beman/execution/detail/starts_on.hpp | 54 ++++++++++++++-- .../execution/detail/stopped_as_error.hpp | 2 +- .../execution/detail/stopped_as_optional.hpp | 2 +- include/beman/execution/detail/sync_wait.hpp | 12 +++- .../detail/sync_wait_with_variant.hpp | 6 +- include/beman/execution/detail/then.hpp | 1 - .../detail/when_all_with_variant.hpp | 12 ++-- src/beman/execution/CMakeLists.txt | 2 - src/beman/execution/execution-detail.cppm | 1 - src/beman/execution/query_with_default.cppm | 1 + src/beman/execution/sched_attrs.cppm | 11 ---- 20 files changed, 130 insertions(+), 194 deletions(-) delete mode 100644 include/beman/execution/detail/sched_attrs.hpp delete mode 100644 src/beman/execution/sched_attrs.cppm diff --git a/include/beman/execution/detail/affine_on.hpp b/include/beman/execution/detail/affine_on.hpp index aec16339..f5617030 100644 --- a/include/beman/execution/detail/affine_on.hpp +++ b/include/beman/execution/detail/affine_on.hpp @@ -131,7 +131,7 @@ struct affine_on_t : ::beman::execution::sender_adaptor_closure { { ::beman::execution::get_scheduler(env) } -> ::beman::execution::scheduler; { ::beman::execution::schedule(::beman::execution::get_scheduler(env)) } -> ::beman::execution::sender; } - static auto transform_sender(Sender&& sender, const Env& ev) { + static auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env& ev) { static_assert(requires { { ::beman::execution::get_completion_signatures { } template <::beman::execution::detail::sender_for Sender, typename... Env> - auto transform_sender(Sender&& sndr, Env&&...) const { + auto transform_sender(::beman::execution::set_value_t, Sender&& sndr, Env&&...) const { auto data = ::beman::execution::detail::forward_like(sndr.template get<1>()); auto child = ::beman::execution::detail::forward_like(sndr.template get<2>()); diff --git a/include/beman/execution/detail/completion_domain.hpp b/include/beman/execution/detail/completion_domain.hpp index 40b7aa8f..d3cd3874 100644 --- a/include/beman/execution/detail/completion_domain.hpp +++ b/include/beman/execution/detail/completion_domain.hpp @@ -23,10 +23,12 @@ import beman.execution.detail.get_env; // ---------------------------------------------------------------------------- namespace beman::execution::detail { -template +template constexpr auto completion_domain(const Sndr& sndr, const Env& env) noexcept { - if constexpr (requires { ::beman::execution::get_completion_domain<>(::beman::execution::get_env(sndr), env); }) { - return ::beman::execution::get_completion_domain<>(::beman::execution::get_env(sndr), env); + if constexpr (requires { + ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), env); + }) { + return ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), env); } else { return ::beman::execution::default_domain(); } diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index df4d0211..60088c1a 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -39,7 +39,6 @@ import beman.execution.detail.meta.to; import beman.execution.detail.meta.transform; import beman.execution.detail.meta.unique; import beman.execution.detail.receiver; -import beman.execution.detail.sched_attrs; import beman.execution.detail.schedule; import beman.execution.detail.schedule_from; import beman.execution.detail.schedule_result_t; @@ -70,7 +69,6 @@ import beman.execution.detail.start; #include #include #include -#include #include #include #include @@ -90,16 +88,12 @@ import beman.execution.detail.start; namespace beman::execution::detail { -// P3826R5: continues_on schedules work dependent on the completion of a sender -// onto a scheduler's associated execution resource. -// continues_on(sndr, sch) = make_sender(continues_on, sch, schedule_from(sndr)) struct continues_on_t { template <::beman::execution::scheduler Scheduler> auto operator()(Scheduler&& scheduler) const { return ::beman::execution::detail::make_sender_adaptor(*this, ::std::forward(scheduler)); } - // P3826R5: continues_on(sndr, sch) = make_sender(continues_on, sch, schedule_from(sndr)) template <::beman::execution::sender Sender, ::beman::execution::scheduler Scheduler> auto operator()(Sender&& sender, Scheduler&& scheduler) const { return ::beman::execution::detail::make_sender( @@ -119,9 +113,9 @@ struct continues_on_t { template using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; using type = ::beman::execution::detail::meta::combine< - decltype(::beman::execution::get_completion_signatures()), - ::beman::execution::error_types_of_t, - ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; + decltype(::beman::execution::get_completion_signatures()), + ::beman::execution::error_types_of_t, + ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; }; public: @@ -130,7 +124,6 @@ struct continues_on_t { return typename get_signatures<::std::remove_cvref_t, Env...>::type{}; } - // P3826R5: impls_for has the scheduling machinery struct impls_for : ::beman::execution::detail::default_impls { template struct upstream_receiver { @@ -160,9 +153,7 @@ struct continues_on_t { ::beman::execution::set_error(std::move(state->receiver), std::forward(err)); } - auto set_stopped() && noexcept -> void { - ::beman::execution::set_stopped(std::move(state->receiver)); - } + auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(std::move(state->receiver)); } auto get_env() const noexcept -> decltype(auto) { return ::beman::execution::detail::fwd_env(::beman::execution::get_env(state->receiver)); @@ -183,23 +174,14 @@ struct continues_on_t { operation_t op_state; static constexpr bool nothrow() { - return noexcept(::beman::execution::connect( - ::beman::execution::schedule(::std::declval()), receiver_t{nullptr})); + return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval()), + receiver_t{nullptr})); } explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow()) : state_base{rcvr}, op_state(::beman::execution::connect(::beman::execution::schedule(sch), receiver_t{this})) {} }; - struct get_attrs_impl { - auto operator()(const auto& data, const auto& child) const noexcept -> decltype(auto) { - return ::beman::execution::detail::join_env( - ::beman::execution::detail::sched_attrs(data), - ::beman::execution::detail::fwd_env(::beman::execution::get_env(child))); - } - }; - static constexpr auto get_attrs{get_attrs_impl{}}; - struct get_state_impl { template requires ::beman::execution::sender_in<::beman::execution::detail::child_type, @@ -208,20 +190,19 @@ struct continues_on_t { auto sch{sender.template get<1>()}; using sched_t = ::std::remove_cvref_t; - using variant_t = ::beman::execution::detail::meta::unique< - ::beman::execution::detail::meta::prepend< - ::std::monostate, - ::beman::execution::detail::meta::transform< - ::beman::execution::detail::as_tuple_t, - ::beman::execution::detail::meta::to< - ::std::variant, - ::beman::execution::detail::meta::combine< - ::beman::execution::completion_signatures_of_t< - ::beman::execution::detail::child_type, - ::beman::execution::env_of_t>, - ::beman::execution::completion_signatures< - ::beman::execution::set_error_t(::std::exception_ptr), - ::beman::execution::set_stopped_t()>>>>>>; + using variant_t = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend< + ::std::monostate, + ::beman::execution::detail::meta::transform< + ::beman::execution::detail::as_tuple_t, + ::beman::execution::detail::meta::to< + ::std::variant, + ::beman::execution::detail::meta::combine< + ::beman::execution::completion_signatures_of_t< + ::beman::execution::detail::child_type, + ::beman::execution::env_of_t>, + ::beman::execution::completion_signatures<::beman::execution::set_error_t( + ::std::exception_ptr), + ::beman::execution::set_stopped_t()>>>>>>; return state_type(sch, receiver); }; diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp index 1d5e982a..25bdf3aa 100644 --- a/include/beman/execution/detail/on.hpp +++ b/include/beman/execution/detail/on.hpp @@ -33,7 +33,6 @@ import beman.execution.detail.sender_for; import beman.execution.detail.set_value; import beman.execution.detail.starts_on; import beman.execution.detail.transform_sender; -import beman.execution.detail.write_env; #else #include #include @@ -51,27 +50,12 @@ import beman.execution.detail.write_env; #include #include #include -#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { struct on_t : ::beman::execution::sender_adaptor_closure { - template <::beman::execution::detail::sender_for OutSndr, typename Env> - auto transform_env(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) { - auto&& data{out_sndr.template get<1>()}; - - if constexpr (::beman::execution::scheduler) - return ::beman::execution::detail::join_env( - ::beman::execution::detail::sched_env(::beman::execution::detail::forward_like(data) - - ), - ::beman::execution::detail::fwd_env(::std::forward(env))); - else - return std::forward(env); - } - template struct env_needs_get_scheduler { using sender_concept = ::beman::execution::sender_t; @@ -81,9 +65,9 @@ struct on_t : ::beman::execution::sender_adaptor_closure { } }; - // P3826R5: transform_sender now takes Tag as first param - template OutSndr, typename Env> - auto transform_sender(Tag, OutSndr&& out_sndr, const Env& env) const -> decltype(auto) { + template <::beman::execution::detail::sender_for OutSndr, typename Env> + auto transform_sender(::beman::execution::set_value_t, OutSndr&& out_sndr, const Env& env) const + -> decltype(auto) { struct not_a_scheduler_t {}; auto&& data = out_sndr.template get<1>(); auto&& child = out_sndr.template get<2>(); @@ -101,23 +85,19 @@ struct on_t : ::beman::execution::sender_adaptor_closure { } } else { auto& [sch, closure] = data; - auto orig_sch{::beman::execution::detail::query_with_default( + auto orig_sch{::beman::execution::detail::call_with_default( ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>, + not_a_scheduler_t{}, ::beman::execution::get_env(child), - ::beman::execution::detail::query_with_default( - ::beman::execution::get_scheduler, env, not_a_scheduler_t{}))}; + env)}; if constexpr (::std::same_as) { return env_needs_get_scheduler{}; } else { - return ::beman::execution::write_env( - ::beman::execution::continues_on( - ::beman::execution::detail::forward_like(closure)(::beman::execution::continues_on( - ::beman::execution::write_env(::beman::execution::detail::forward_like(child), - ::beman::execution::detail::sched_env(orig_sch)), - sch)), - orig_sch), - ::beman::execution::detail::sched_env(env)); + return ::beman::execution::continues_on( + ::beman::execution::detail::forward_like(closure)(::beman::execution::continues_on( + ::beman::execution::detail::forward_like(child), sch)), + orig_sch); } } } @@ -136,14 +116,12 @@ struct on_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr> auto operator()(Sch&& sch, Sndr&& sndr) const { - // P3826R5: No early customization return ::beman::execution::detail::make_sender(*this, ::std::forward(sch), ::std::forward(sndr)); } template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr, ::beman::execution::detail::is_sender_adaptor_closure Closure> auto operator()(Sndr&& sndr, Sch&& sch, Closure&& closure) const { - // P3826R5: No early customization return ::beman::execution::detail::make_sender( *this, ::beman::execution::detail::product_type{::std::forward(sch), ::std::forward(closure)}, diff --git a/include/beman/execution/detail/query_with_default.hpp b/include/beman/execution/detail/query_with_default.hpp index f6c3b26e..f94f315e 100644 --- a/include/beman/execution/detail/query_with_default.hpp +++ b/include/beman/execution/detail/query_with_default.hpp @@ -26,6 +26,19 @@ query_with_default(Tag, const Env&, Value&& value) noexcept(noexcept(static_cast -> decltype(auto) { return static_cast(std::forward(value)); } + +template + requires requires(const Tag& tag, const Env& env, Args&&... args) { tag(env, ::std::forward(args)...); } +constexpr auto call_with_default(Tag, DefaultValue&&, const Env& env, Args&&... args) noexcept( + noexcept(Tag()(env, ::std::forward(args)...))) -> decltype(auto) { + return Tag()(env, ::std::forward(args)...); +} + +template +constexpr auto call_with_default(Tag, DefaultValue&& value, const Env&, const Args&...) noexcept( + noexcept(static_cast(std::forward(value)))) -> decltype(auto) { + return static_cast(std::forward(value)); +} } // namespace beman::execution::detail // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/sched_attrs.hpp b/include/beman/execution/detail/sched_attrs.hpp deleted file mode 100644 index 1483c5e6..00000000 --- a/include/beman/execution/detail/sched_attrs.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// include/beman/execution/detail/sched_attrs.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_SCHED_ATTRS -#define INCLUDED_BEMAN_EXECUTION_DETAIL_SCHED_ATTRS - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#include -#include -#endif -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.get_completion_scheduler; -import beman.execution.detail.get_domain; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.set_value; -#else -#include -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { - -template -class sched_attrs { - private: - Scheduler sched; - - public: - template - requires(!::std::same_as>) - explicit sched_attrs(S&& s) : sched(::std::forward(s)) {} - - template - auto query(const ::beman::execution::get_completion_scheduler_t&) const noexcept { - return this->sched; - } - - template - requires requires(Scheduler&& s) { s.query(::beman::execution::get_domain); } - auto query(const ::beman::execution::get_domain_t& q, T = true) const noexcept { - return this->sched.query(q); - } -}; - -template -sched_attrs(Scheduler&&) -> sched_attrs<::std::remove_cvref_t>; -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_SCHED_ATTRS diff --git a/include/beman/execution/detail/schedule_from.hpp b/include/beman/execution/detail/schedule_from.hpp index c647251e..de361e2b 100644 --- a/include/beman/execution/detail/schedule_from.hpp +++ b/include/beman/execution/detail/schedule_from.hpp @@ -11,16 +11,14 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.default_impls; -import beman.execution.detail.fwd_env; -import beman.execution.detail.get_env; +import beman.execution.detail.child_type; +import beman.execution.detail.get_completion_signatures; import beman.execution.detail.make_sender; import beman.execution.detail.product_type; import beman.execution.detail.sender; #else -#include -#include -#include +#include +#include #include #include #include @@ -30,25 +28,16 @@ import beman.execution.detail.sender; namespace beman::execution::detail { -// P3826R5: schedule_from(sndr) = make_sender(schedule_from, {}, sndr) -// schedule_from(sndr) is semantically equivalent to sndr. -// It exists so it can be customized by schedulers to control how to -// transition off their execution contexts. struct schedule_from_t { + template + static consteval auto get_completion_signatures() { + return ::beman::execution::get_completion_signatures<::beman::execution::detail::child_type, Env...>(); + } + template <::beman::execution::sender Sender> auto operator()(Sender&& sender) const { return ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::product_type<>{}, - ::std::forward(sender)); - } - - // Legacy 2-arg overload for backward compatibility during transition - template - auto operator()(Scheduler&& /*scheduler*/, Sender&& sender) const { - // P3826R5: The new schedule_from only takes a sender. - // The old schedule_from(sch, sndr) behavior is now in continues_on. - return (*this)(::std::forward(sender)); + *this, ::beman::execution::detail::product_type<>{}, ::std::forward(sender)); } }; diff --git a/include/beman/execution/detail/split.hpp b/include/beman/execution/detail/split.hpp index 810009c0..45b518d3 100644 --- a/include/beman/execution/detail/split.hpp +++ b/include/beman/execution/detail/split.hpp @@ -364,8 +364,8 @@ struct shared_wrapper { }; struct split_t { - template - auto transform_sender(Sndr&& sndr) const { + template + auto transform_sender(::beman::execution::set_value_t, Sndr&& sndr, const Env&...) const { auto&& child = ::std::forward(sndr).template get<2>(); using child_type = decltype(child); using shared_state = ::beman::execution::detail::impls_for::shared_state; diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index a7e0a3f6..abe15671 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -14,9 +14,12 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.continues_on; import beman.execution.detail.default_domain; +import beman.execution.detail.default_impls; import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; +import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_domain; +import beman.execution.detail.get_env; import beman.execution.detail.join_env; import beman.execution.detail.just; import beman.execution.detail.let; @@ -31,9 +34,12 @@ import beman.execution.detail.transform_sender; #else #include #include +#include #include #include +#include #include +#include #include #include #include @@ -50,11 +56,39 @@ import beman.execution.detail.transform_sender; // ---------------------------------------------------------------------------- namespace beman::execution::detail { + +// starts_on_attrs_t: attrs object for starts_on(sch, sndr). +// When asked for its completion domain, it injects the scheduler's env into +// the child's completion domain query (the child knows it will start on sch). +template +struct starts_on_attrs_t { + Scheduler sch; + ChildEnv child_env; + + // Answer get_completion_domain queries: delegate to the child's env with + // the scheduler's context (sched_env(sch)) prepended to rcvr_env. + template + auto query(::beman::execution::get_completion_domain_t, const Env& rcvr_env) const noexcept { + auto env_for_child = ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(sch), + ::beman::execution::detail::fwd_env(rcvr_env)); + if constexpr (requires { ::beman::execution::get_completion_domain(child_env, env_for_child); }) { + return ::beman::execution::get_completion_domain(child_env, env_for_child); + } else { + return ::beman::execution::default_domain{}; + } + } + + // Forward all other forwarding queries to child_env. + template + requires requires { ::std::as_const(child_env).query(::std::declval(), ::std::declval()...); } + auto query(Q q, Args&&... args) const noexcept { + return ::std::as_const(child_env).query(q, ::std::forward(args)...); + } +}; + struct starts_on_t { - template Sender, - typename Env> - auto transform_sender(Tag, Sender&& sender, const Env&) const noexcept { + template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename Env> + auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env&) const noexcept { auto&& scheduler{sender.template get<1>()}; auto&& new_sender{sender.template get<2>()}; return ::beman::execution::let_value( @@ -63,6 +97,18 @@ struct starts_on_t { ::std::is_nothrow_constructible_v<::std::decay_t>) { return ::std::move(new_sender); }); } + struct impls_for : ::beman::execution::detail::default_impls { + struct get_attrs_impl { + auto operator()(const auto& sch, const auto& child) const noexcept { + using Sch = ::std::remove_cvref_t; + using ChildEnv = ::std::remove_cvref_t; + return ::beman::execution::detail::starts_on_attrs_t{ + sch, ::beman::execution::get_env(child)}; + } + }; + static constexpr auto get_attrs{get_attrs_impl{}}; + }; + template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender> auto operator()(Scheduler&& scheduler, Sender&& sender) const { return ::beman::execution::detail::make_sender( diff --git a/include/beman/execution/detail/stopped_as_error.hpp b/include/beman/execution/detail/stopped_as_error.hpp index 2f6ee763..a0760f6c 100644 --- a/include/beman/execution/detail/stopped_as_error.hpp +++ b/include/beman/execution/detail/stopped_as_error.hpp @@ -35,7 +35,7 @@ import beman.execution.detail.sender_for; namespace beman::execution::detail { struct stopped_as_error_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::detail::sender_for Sndr, typename Env> - auto transform_sender(Sndr&& sndr, Env&&) const noexcept { + auto transform_sender(::beman::execution::set_value_t, Sndr&& sndr, Env&&) const noexcept { auto&& data = sndr.template get<1>(); auto&& child = sndr.template get<2>(); using Error = ::std::decay_t; diff --git a/include/beman/execution/detail/stopped_as_optional.hpp b/include/beman/execution/detail/stopped_as_optional.hpp index 0d43d708..27c95986 100644 --- a/include/beman/execution/detail/stopped_as_optional.hpp +++ b/include/beman/execution/detail/stopped_as_optional.hpp @@ -43,7 +43,7 @@ import beman.execution.detail.then; namespace beman::execution::detail { struct stopped_as_optional_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::detail::sender_for Sndr, typename Env> - auto transform_sender(Sndr&& sndr, Env&&) const noexcept { + auto transform_sender(::beman::execution::set_value_t, Sndr&& sndr, Env&&) const noexcept { static_assert( ::beman::execution::detail::single_sender, ::beman::execution::detail::fwd_env>, "sender must be a single sender"); diff --git a/include/beman/execution/detail/sync_wait.hpp b/include/beman/execution/detail/sync_wait.hpp index 6d1441d0..fba94606 100644 --- a/include/beman/execution/detail/sync_wait.hpp +++ b/include/beman/execution/detail/sync_wait.hpp @@ -16,6 +16,7 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.apply_sender; import beman.execution.detail.as_except_ptr; +import beman.execution.detail.completion_domain; import beman.execution.detail.connect; import beman.execution.detail.decayed_tuple; import beman.execution.detail.default_domain; @@ -24,11 +25,13 @@ import beman.execution.detail.get_scheduler; import beman.execution.detail.receiver; import beman.execution.detail.run_loop; import beman.execution.detail.sender_in; +import beman.execution.detail.set_value; import beman.execution.detail.start; import beman.execution.detail.value_types_of_t; #else #include #include +#include #include #include #include @@ -37,6 +40,7 @@ import beman.execution.detail.value_types_of_t; #include #include #include +#include #include #include #endif @@ -113,14 +117,16 @@ struct sync_wait_t { typename ::beman::execution::detail::sync_wait_result_type; { ::beman::execution::apply_sender( - ::beman::execution::default_domain{}, + ::beman::execution::detail::completion_domain<::beman::execution::set_value_t>( + sender, ::beman::execution::detail::sync_wait_env{}), self, ::std::forward(sender)) } -> ::std::same_as<::beman::execution::detail::sync_wait_result_type>; } auto operator()(Sender&& sender) const { - // P3826R5: Use default_domain for apply_sender - return ::beman::execution::apply_sender(::beman::execution::default_domain{}, *this, ::std::forward(sender)); + auto dom = ::beman::execution::detail::completion_domain<::beman::execution::set_value_t>( + sender, ::beman::execution::detail::sync_wait_env{}); + return ::beman::execution::apply_sender(dom, *this, ::std::forward(sender)); } }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/sync_wait_with_variant.hpp b/include/beman/execution/detail/sync_wait_with_variant.hpp index 9e9b41c3..09678d6c 100644 --- a/include/beman/execution/detail/sync_wait_with_variant.hpp +++ b/include/beman/execution/detail/sync_wait_with_variant.hpp @@ -59,9 +59,9 @@ struct sync_wait_with_variant_t { template requires requires { typename ::beman::execution::detail::sync_wait_with_variant_result_type; } auto operator()(Sndr&& sndr) const { - // P3826R5: Use default_domain for apply_sender - return ::beman::execution::apply_sender( - ::beman::execution::default_domain{}, *this, ::std::forward(sndr)); + auto dom = ::beman::execution::detail::completion_domain<::beman::execution::set_value_t>( + sndr, ::beman::execution::detail::sync_wait_env{}); + return ::beman::execution::apply_sender(dom, *this, ::std::forward(sndr)); } }; diff --git a/include/beman/execution/detail/then.hpp b/include/beman/execution/detail/then.hpp index 6e6feffd..251c6719 100644 --- a/include/beman/execution/detail/then.hpp +++ b/include/beman/execution/detail/then.hpp @@ -115,7 +115,6 @@ struct then_t : ::beman::execution::sender_adaptor_closure> { } template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun> auto operator()(Sender&& sender, Fun&& fun) const { - // P3826R5: No early customization - just return make_sender directly return ::beman::execution::detail::make_sender(*this, ::std::forward(fun), ::std::forward(sender)); } template <::beman::execution::sender Sender, typename Env> diff --git a/include/beman/execution/detail/when_all_with_variant.hpp b/include/beman/execution/detail/when_all_with_variant.hpp index a802e9b9..22c4a7e9 100644 --- a/include/beman/execution/detail/when_all_with_variant.hpp +++ b/include/beman/execution/detail/when_all_with_variant.hpp @@ -17,7 +17,7 @@ import beman.execution.detail.into_variant; import beman.execution.detail.make_sender; import beman.execution.detail.sender; import beman.execution.detail.sender_for; -import beman.execution.detail.transform_sender; +import beman.execution.detail.set_value; import beman.execution.detail.when_all; #else #include @@ -25,7 +25,7 @@ import beman.execution.detail.when_all; #include #include #include -#include +#include #include #endif @@ -33,11 +33,8 @@ import beman.execution.detail.when_all; namespace beman::execution::detail { struct when_all_with_variant_t { - // P3826R5: transform_sender now takes Tag as first param - template Sender, - typename Env> - auto transform_sender(Tag, Sender&& sender, const Env&) const noexcept { + template <::beman::execution::detail::sender_for Sender, typename Env> + auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env&) const noexcept { return ::std::forward(sender).apply([](auto&&, auto&&, auto&&... child) { return ::beman::execution::when_all( ::beman::execution::into_variant(::beman::execution::detail::forward_like(child))...); @@ -46,7 +43,6 @@ struct when_all_with_variant_t { template <::beman::execution::sender... Sender> auto operator()(Sender&&... sender) const { - // P3826R5: No early customization return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...); } }; diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 387c7aba..3bb2e348 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -143,7 +143,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/receiver.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/receiver_of.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/run_loop.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sched_attrs.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sched_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/schedule.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/schedule_from.hpp @@ -340,7 +339,6 @@ if(BEMAN_USE_MODULES) receiver_of.cppm receiver.cppm run_loop.cppm - sched_attrs.cppm sched_env.cppm schedule_from.cppm schedule_result_t.cppm diff --git a/src/beman/execution/execution-detail.cppm b/src/beman/execution/execution-detail.cppm index c9dac2c4..3f532808 100644 --- a/src/beman/execution/execution-detail.cppm +++ b/src/beman/execution/execution-detail.cppm @@ -60,7 +60,6 @@ export import beman.execution.detail.operation_state_task; export import beman.execution.detail.product_type; export import beman.execution.detail.query_with_default; export import beman.execution.detail.queryable; -export import beman.execution.detail.sched_attrs; export import beman.execution.detail.sched_env; export import beman.execution.detail.sender; export import beman.execution.detail.sender_adaptor_closure; diff --git a/src/beman/execution/query_with_default.cppm b/src/beman/execution/query_with_default.cppm index 132bdece..bb348f29 100644 --- a/src/beman/execution/query_with_default.cppm +++ b/src/beman/execution/query_with_default.cppm @@ -8,4 +8,5 @@ export module beman.execution.detail.query_with_default; namespace beman::execution::detail { export using beman::execution::detail::query_with_default; +export using beman::execution::detail::call_with_default; } // namespace beman::execution::detail diff --git a/src/beman/execution/sched_attrs.cppm b/src/beman/execution/sched_attrs.cppm deleted file mode 100644 index d55e2eae..00000000 --- a/src/beman/execution/sched_attrs.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/sched_attrs.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.sched_attrs; - -namespace beman::execution::detail { -export using beman::execution::detail::sched_attrs; -} // namespace beman::execution::detail From 76fa7443d8defff1196ee1bc19721a37bc8891e7 Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Sun, 26 Apr 2026 23:19:04 +0800 Subject: [PATCH 07/16] Fix affine_on --- include/beman/execution/detail/affine_on.hpp | 9 +++++---- .../execution/detail/get_completion_scheduler.hpp | 11 +++++++---- include/beman/execution/detail/get_scheduler.hpp | 10 +++++++++- include/beman/execution/detail/transform_sender.hpp | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/beman/execution/detail/affine_on.hpp b/include/beman/execution/detail/affine_on.hpp index f5617030..b154ab57 100644 --- a/include/beman/execution/detail/affine_on.hpp +++ b/include/beman/execution/detail/affine_on.hpp @@ -17,6 +17,7 @@ import std; import beman.execution.detail.basic_sender; import beman.execution.detail.completion_signatures; import beman.execution.detail.completion_signatures_of_t; +import beman.execution.detail.continues_on; import beman.execution.detail.env; import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; @@ -41,6 +42,7 @@ import beman.execution.detail.unstoppable; import beman.execution.detail.write_env; #else #include +#include #include #include #include @@ -49,7 +51,6 @@ import beman.execution.detail.write_env; #include #include #include -#include #include #include #include @@ -153,9 +154,9 @@ struct affine_on_t : ::beman::execution::sender_adaptor_closure { return ::beman::execution::detail::store_receiver( ::beman::execution::detail::forward_like(child), [](Child&& child, const auto& ev) { - return ::beman::execution::unstoppable(::beman::execution::schedule_from( - ::beman::execution::get_scheduler(ev), - ::beman::execution::write_env(::std::forward(child), ev))); + return ::beman::execution::unstoppable(::beman::execution::continues_on( + ::beman::execution::write_env(::std::forward(child), ev), + ::beman::execution::get_scheduler(ev))); }); } } diff --git a/include/beman/execution/detail/get_completion_scheduler.hpp b/include/beman/execution/detail/get_completion_scheduler.hpp index 23717339..3767aa3f 100644 --- a/include/beman/execution/detail/get_completion_scheduler.hpp +++ b/include/beman/execution/detail/get_completion_scheduler.hpp @@ -36,10 +36,13 @@ struct get_completion_scheduler_t; template concept has_completion_scheduler = requires { - ::beman::execution::detail::recurse_query( - ::std::declval().query(::std::declval<::beman::execution::detail::get_completion_scheduler_t>(), - ::std::declval()...), - ::std::declval()...); + { + ::beman::execution::detail::recurse_query( + ::std::declval().query( + ::std::declval<::beman::execution::detail::get_completion_scheduler_t>(), + ::std::declval()...), + ::std::declval()...) + } -> ::beman::execution::scheduler; } || (::beman::execution::scheduler && sizeof...(E) > 0); template <::beman::execution::detail::completion_tag Tag> diff --git a/include/beman/execution/detail/get_scheduler.hpp b/include/beman/execution/detail/get_scheduler.hpp index 963c69f2..59024cf3 100644 --- a/include/beman/execution/detail/get_scheduler.hpp +++ b/include/beman/execution/detail/get_scheduler.hpp @@ -14,11 +14,13 @@ import std; import beman.execution.detail.forwarding_query; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.hide_sched; +import beman.execution.detail.scheduler; import beman.execution.detail.set_value; #else #include #include #include +#include #include #endif @@ -27,7 +29,13 @@ import beman.execution.detail.set_value; namespace beman::execution { struct get_scheduler_t : ::beman::execution::forwarding_query_t { template - requires requires(const get_scheduler_t& self, Env&& env) { ::std::as_const(env).query(self); } + requires requires(const get_scheduler_t& self, Env&& env) { + ::std::as_const(env).query(self); + { + ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + ::std::as_const(env).query(self), ::beman::execution::detail::hide_sched(env)) + } -> ::beman::execution::scheduler; + } auto operator()(Env&& env) const noexcept { return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( ::std::as_const(env).query(*this), ::beman::execution::detail::hide_sched(env)); diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index db14488a..94a27b2b 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -50,7 +50,7 @@ struct transform_sndr_recurse { decltype(auto) new_sndr = ::beman::execution::detail::transformed_sndr(Domain(), Tag(), ::std::forward(sndr), env); if constexpr (::std::same_as<::std::decay_t, ::std::decay_t>) { - return std::forward(new_sndr); + return static_cast(new_sndr); } else { if constexpr (::std::same_as) { auto new_dom = ::beman::execution::get_domain(env); From 569c0c8763d2836eee0f1ab971ab32b0a31d79b6 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Mon, 27 Apr 2026 11:20:19 +0800 Subject: [PATCH 08/16] Add missing `set_value` import in multiple headers --- include/beman/execution/detail/starts_on.hpp | 2 ++ include/beman/execution/detail/stopped_as_error.hpp | 2 ++ include/beman/execution/detail/stopped_as_optional.hpp | 2 ++ include/beman/execution/detail/sync_wait_with_variant.hpp | 4 ++++ include/beman/execution/detail/transform_sender.hpp | 4 ++-- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index abe15671..7fc88433 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -30,6 +30,7 @@ import beman.execution.detail.schedule; import beman.execution.detail.scheduler; import beman.execution.detail.sender; import beman.execution.detail.sender_for; +import beman.execution.detail.set_value; import beman.execution.detail.transform_sender; #else #include @@ -50,6 +51,7 @@ import beman.execution.detail.transform_sender; #include #include #include +#include #include #endif diff --git a/include/beman/execution/detail/stopped_as_error.hpp b/include/beman/execution/detail/stopped_as_error.hpp index a0760f6c..c5cf8b00 100644 --- a/include/beman/execution/detail/stopped_as_error.hpp +++ b/include/beman/execution/detail/stopped_as_error.hpp @@ -21,6 +21,7 @@ import beman.execution.detail.movable_value; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; +import beman.execution.detail.set_value; #else #include #include @@ -30,6 +31,7 @@ import beman.execution.detail.sender_for; #include #include #include +#include #endif namespace beman::execution::detail { diff --git a/include/beman/execution/detail/stopped_as_optional.hpp b/include/beman/execution/detail/stopped_as_optional.hpp index 27c95986..ab1ed114 100644 --- a/include/beman/execution/detail/stopped_as_optional.hpp +++ b/include/beman/execution/detail/stopped_as_optional.hpp @@ -23,6 +23,7 @@ import beman.execution.detail.make_sender; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; +import beman.execution.detail.set_value; import beman.execution.detail.single_sender; import beman.execution.detail.single_sender_value_type; import beman.execution.detail.then; @@ -35,6 +36,7 @@ import beman.execution.detail.then; #include #include #include +#include #include #include #include diff --git a/include/beman/execution/detail/sync_wait_with_variant.hpp b/include/beman/execution/detail/sync_wait_with_variant.hpp index 09678d6c..9c529ebb 100644 --- a/include/beman/execution/detail/sync_wait_with_variant.hpp +++ b/include/beman/execution/detail/sync_wait_with_variant.hpp @@ -16,18 +16,22 @@ import std; import beman.execution.detail.apply_sender; import beman.execution.detail.callable; import beman.execution.detail.call_result_t; +import beman.execution.detail.completion_domain; import beman.execution.detail.default_domain; import beman.execution.detail.into_variant; import beman.execution.detail.sender_in; +import beman.execution.detail.set_value; import beman.execution.detail.sync_wait; import beman.execution.detail.value_types_of_t; #else #include #include #include +#include #include #include #include +#include #include #include #endif diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index 94a27b2b..a5ce57b4 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -46,11 +46,11 @@ struct transform_sndr_recurse { constexpr transform_sndr_recurse(Domain, Tag) noexcept {} template - auto operator()(Sndr&& sndr, const Env& env) -> decltype(auto) { + auto operator()(Sndr&& sndr, const Env& env) { decltype(auto) new_sndr = ::beman::execution::detail::transformed_sndr(Domain(), Tag(), ::std::forward(sndr), env); if constexpr (::std::same_as<::std::decay_t, ::std::decay_t>) { - return static_cast(new_sndr); + return ::std::forward(new_sndr); } else { if constexpr (::std::same_as) { auto new_dom = ::beman::execution::get_domain(env); From 27b782832bb38b6d24a0e16a7b87b9b99e801d36 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Mon, 27 Apr 2026 15:37:43 +0800 Subject: [PATCH 09/16] Rename `completion_domain` to `compl_domain` --- .../beman/execution/detail/compl_domain.hpp | 27 +++---------- .../execution/detail/completion_domain.hpp | 40 ------------------- include/beman/execution/detail/sync_wait.hpp | 8 ++-- .../detail/sync_wait_with_variant.hpp | 6 +-- .../execution/detail/transform_sender.hpp | 8 ++-- src/beman/execution/CMakeLists.txt | 4 +- src/beman/execution/compl_domain.cppm | 11 +++++ src/beman/execution/completion_domain.cppm | 11 ----- 8 files changed, 30 insertions(+), 85 deletions(-) delete mode 100644 include/beman/execution/detail/completion_domain.hpp create mode 100644 src/beman/execution/compl_domain.cppm delete mode 100644 src/beman/execution/completion_domain.cppm diff --git a/include/beman/execution/detail/compl_domain.hpp b/include/beman/execution/detail/compl_domain.hpp index eb233e13..9029955c 100644 --- a/include/beman/execution/detail/compl_domain.hpp +++ b/include/beman/execution/detail/compl_domain.hpp @@ -1,4 +1,4 @@ -// include/beman/execution/detail/compl_domain.hpp -*-C++-*- +// include/beman/execution/detail/compl_domain.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPL_DOMAIN @@ -9,45 +9,30 @@ import std; #else #include -#include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.default_domain; import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_env; -import beman.execution.detail.indeterminate_domain; #else +#include #include #include -#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { - -// COMPL-DOMAIN(Tag, sndr, envs): -// D() where D is the type of get_completion_domain(get_env(sndr), envs...) -// if that expression is well-formed or envs is empty pack, -// and indeterminate_domain<>() otherwise. -template +template constexpr auto compl_domain(const Sndr& sndr, const Envs&... envs) noexcept { if constexpr (requires { ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), envs...); }) { - return decltype( - ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), envs...)){}; - } else if constexpr (sizeof...(Envs) == 0) { - // If envs is empty, the expression should still be tried but may be ill-formed - // In that case, return indeterminate_domain - return ::beman::execution::indeterminate_domain<>{}; + return ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), envs...); } else { - return ::beman::execution::indeterminate_domain<>{}; + return ::beman::execution::default_domain(); } } - -template -using compl_domain_t = decltype(compl_domain(::std::declval(), ::std::declval()...)); - } // namespace beman::execution::detail // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/completion_domain.hpp b/include/beman/execution/detail/completion_domain.hpp deleted file mode 100644 index d3cd3874..00000000 --- a/include/beman/execution/detail/completion_domain.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// include/beman/execution/detail/completion_domain.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_DOMAIN -#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_DOMAIN - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#endif -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.default_domain; -import beman.execution.detail.get_completion_domain; -import beman.execution.detail.get_env; -#else -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -template -constexpr auto completion_domain(const Sndr& sndr, const Env& env) noexcept { - if constexpr (requires { - ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), env); - }) { - return ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), env); - } else { - return ::beman::execution::default_domain(); - } -} -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_DOMAIN diff --git a/include/beman/execution/detail/sync_wait.hpp b/include/beman/execution/detail/sync_wait.hpp index fba94606..037137d9 100644 --- a/include/beman/execution/detail/sync_wait.hpp +++ b/include/beman/execution/detail/sync_wait.hpp @@ -16,7 +16,7 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.apply_sender; import beman.execution.detail.as_except_ptr; -import beman.execution.detail.completion_domain; +import beman.execution.detail.compl_domain; import beman.execution.detail.connect; import beman.execution.detail.decayed_tuple; import beman.execution.detail.default_domain; @@ -31,7 +31,7 @@ import beman.execution.detail.value_types_of_t; #else #include #include -#include +#include #include #include #include @@ -117,14 +117,14 @@ struct sync_wait_t { typename ::beman::execution::detail::sync_wait_result_type; { ::beman::execution::apply_sender( - ::beman::execution::detail::completion_domain<::beman::execution::set_value_t>( + ::beman::execution::detail::compl_domain<::beman::execution::set_value_t>( sender, ::beman::execution::detail::sync_wait_env{}), self, ::std::forward(sender)) } -> ::std::same_as<::beman::execution::detail::sync_wait_result_type>; } auto operator()(Sender&& sender) const { - auto dom = ::beman::execution::detail::completion_domain<::beman::execution::set_value_t>( + auto dom = ::beman::execution::detail::compl_domain<::beman::execution::set_value_t>( sender, ::beman::execution::detail::sync_wait_env{}); return ::beman::execution::apply_sender(dom, *this, ::std::forward(sender)); } diff --git a/include/beman/execution/detail/sync_wait_with_variant.hpp b/include/beman/execution/detail/sync_wait_with_variant.hpp index 9c529ebb..20a6d7dc 100644 --- a/include/beman/execution/detail/sync_wait_with_variant.hpp +++ b/include/beman/execution/detail/sync_wait_with_variant.hpp @@ -16,7 +16,7 @@ import std; import beman.execution.detail.apply_sender; import beman.execution.detail.callable; import beman.execution.detail.call_result_t; -import beman.execution.detail.completion_domain; +import beman.execution.detail.compl_domain; import beman.execution.detail.default_domain; import beman.execution.detail.into_variant; import beman.execution.detail.sender_in; @@ -27,7 +27,7 @@ import beman.execution.detail.value_types_of_t; #include #include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ struct sync_wait_with_variant_t { template requires requires { typename ::beman::execution::detail::sync_wait_with_variant_result_type; } auto operator()(Sndr&& sndr) const { - auto dom = ::beman::execution::detail::completion_domain<::beman::execution::set_value_t>( + auto dom = ::beman::execution::detail::compl_domain<::beman::execution::set_value_t>( sndr, ::beman::execution::detail::sync_wait_env{}); return ::beman::execution::apply_sender(dom, *this, ::std::forward(sndr)); } diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index a5ce57b4..9f95450e 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -13,14 +13,14 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.completion_domain; +import beman.execution.detail.compl_domain; import beman.execution.detail.default_domain; import beman.execution.detail.get_domain; import beman.execution.detail.sender; import beman.execution.detail.set_value; import beman.execution.detail.start; #else -#include +#include #include #include #include @@ -56,7 +56,7 @@ struct transform_sndr_recurse { auto new_dom = ::beman::execution::get_domain(env); return transform_sndr_recurse{new_dom, Tag()}(::std::forward(new_sndr), env); } else { - auto new_dom = ::beman::execution::detail::completion_domain(new_sndr, env); + auto new_dom = ::beman::execution::detail::compl_domain(new_sndr, env); return transform_sndr_recurse{new_dom, Tag()}(::std::forward(new_sndr), env); } } @@ -68,7 +68,7 @@ namespace beman::execution { template <::beman::execution::sender Sndr, typename Env> auto transform_sender(Sndr&& sndr, const Env& env) -> ::beman::execution::sender decltype(auto) { auto starting_domain = ::beman::execution::get_domain(env); - auto completion_domain = ::beman::execution::detail::completion_domain(sndr, env); + auto completion_domain = ::beman::execution::detail::compl_domain(sndr, env); auto starting_transform = ::beman::execution::detail::transform_sndr_recurse(starting_domain, ::beman::execution::start); auto complete_transform = diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 3bb2e348..b3f3a280 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -46,7 +46,7 @@ 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_domain.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/compl_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signature.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signatures.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signatures_for.hpp @@ -240,7 +240,7 @@ if(BEMAN_USE_MODULES) check_type_alias_exist.cppm child_type.cppm class_type.cppm - completion_domain.cppm + compl_domain.cppm completion_signature.cppm completion_signatures_for.cppm completion_signatures_of_t.cppm diff --git a/src/beman/execution/compl_domain.cppm b/src/beman/execution/compl_domain.cppm new file mode 100644 index 00000000..386e1da4 --- /dev/null +++ b/src/beman/execution/compl_domain.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/compl_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.compl_domain; + +namespace beman::execution::detail { +export using beman::execution::detail::compl_domain; +} // namespace beman::execution::detail diff --git a/src/beman/execution/completion_domain.cppm b/src/beman/execution/completion_domain.cppm deleted file mode 100644 index 64b933bb..00000000 --- a/src/beman/execution/completion_domain.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/completion_domain.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.completion_domain; - -namespace beman::execution::detail { -export using beman::execution::detail::completion_domain; -} // namespace beman::execution::detail From 3ebbc0f90994d6bb4d50271765c4e1dd6bf175a2 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Mon, 27 Apr 2026 16:18:13 +0800 Subject: [PATCH 10/16] Update tests --- .../execution/detail/indeterminate_domain.hpp | 2 +- .../execution/detail/transform_sender.hpp | 6 +- src/beman/execution/execution-detail.cppm | 2 +- tests/beman/execution/CMakeLists.txt | 2 +- tests/beman/execution/exec-affine-on.test.cpp | 3 +- tests/beman/execution/exec-connect.test.cpp | 8 +- .../execution/exec-continues-on.test.cpp | 4 - .../execution/exec-domain-default.test.cpp | 120 +++------- tests/beman/execution/exec-env.test.cpp | 35 +++ .../execution/exec-get-compl-domain.test.cpp | 119 +++++----- .../execution/exec-get-compl-sched.test.cpp | 19 ++ .../beman/execution/exec-get-domain.test.cpp | 59 ++++- .../execution/exec-get-scheduler.test.cpp | 10 +- .../execution/exec-getcomplsigs.test.cpp | 10 +- .../execution/exec-inline-scheduler.test.cpp | 224 ++++++++++++++++++ tests/beman/execution/exec-on.test.cpp | 12 +- tests/beman/execution/exec-prop.test.cpp | 8 + .../execution/exec-queries-expos.test.cpp | 2 +- tests/beman/execution/exec-sched.test.cpp | 7 +- .../execution/exec-schedule-from.test.cpp | 97 -------- tests/beman/execution/exec-snd-expos.test.cpp | 56 +---- .../execution/exec-snd-transform.test.cpp | 210 ++++++++++------ tests/beman/execution/exec-when-all.test.cpp | 2 +- .../beman/execution/execution-module.test.cpp | 5 +- 24 files changed, 610 insertions(+), 412 deletions(-) create mode 100644 tests/beman/execution/exec-inline-scheduler.test.cpp delete mode 100644 tests/beman/execution/exec-schedule-from.test.cpp diff --git a/include/beman/execution/detail/indeterminate_domain.hpp b/include/beman/execution/detail/indeterminate_domain.hpp index ee977365..6bfde2d5 100644 --- a/include/beman/execution/detail/indeterminate_domain.hpp +++ b/include/beman/execution/detail/indeterminate_domain.hpp @@ -38,7 +38,7 @@ struct indeterminate_domain { static constexpr auto transform_sender(Tag tag, Sndr&& sndr, const Env& env) noexcept( noexcept(::beman::execution::default_domain{}.transform_sender(tag, ::std::forward(sndr), env))) -> decltype(auto) { - constexpr auto make_new_sender = [&]() -> decltype(auto) { + auto make_new_sender = [&]() -> decltype(auto) { return ::beman::execution::default_domain{}.transform_sender(tag, ::std::forward(sndr), env); }; (..., verify_mandates_<::std::decay_t, Domains, Tag, Sndr, Env>()); diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index 9f95450e..76bae11c 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -54,10 +54,12 @@ struct transform_sndr_recurse { } else { if constexpr (::std::same_as) { auto new_dom = ::beman::execution::get_domain(env); - return transform_sndr_recurse{new_dom, Tag()}(::std::forward(new_sndr), env); + return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}( + ::std::forward(new_sndr), env); } else { auto new_dom = ::beman::execution::detail::compl_domain(new_sndr, env); - return transform_sndr_recurse{new_dom, Tag()}(::std::forward(new_sndr), env); + return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}( + ::std::forward(new_sndr), env); } } } diff --git a/src/beman/execution/execution-detail.cppm b/src/beman/execution/execution-detail.cppm index 3f532808..e279a484 100644 --- a/src/beman/execution/execution-detail.cppm +++ b/src/beman/execution/execution-detail.cppm @@ -14,7 +14,7 @@ export import beman.execution.detail.basic_state; export import beman.execution.detail.call_result_t; export import beman.execution.detail.callable; export import beman.execution.detail.child_type; -export import beman.execution.detail.completion_domain; +export import beman.execution.detail.compl_domain; export import beman.execution.detail.completion_signature; export import beman.execution.detail.completion_signatures_for; export import beman.execution.detail.completion_tag; diff --git a/tests/beman/execution/CMakeLists.txt b/tests/beman/execution/CMakeLists.txt index 17d5677b..0dd5cb4f 100644 --- a/tests/beman/execution/CMakeLists.txt +++ b/tests/beman/execution/CMakeLists.txt @@ -27,6 +27,7 @@ list( exec-get-delegation-scheduler.test exec-get-domain.test exec-get-env.test + exec-inline-scheduler.test exec-get-scheduler.test exec-get-stop-token.test exec-into-variant.test @@ -43,7 +44,6 @@ list( exec-run-loop-general.test exec-run-loop-types.test exec-sched.test - exec-schedule-from.test exec-schedule.test exec-scope-concepts.test exec-scope-counting.test diff --git a/tests/beman/execution/exec-affine-on.test.cpp b/tests/beman/execution/exec-affine-on.test.cpp index b3cc19bf..efedaba6 100644 --- a/tests/beman/execution/exec-affine-on.test.cpp +++ b/tests/beman/execution/exec-affine-on.test.cpp @@ -162,8 +162,7 @@ TEST(affine_on) { static_assert(test_std::receiver); auto s{test_std::get_scheduler(test_std::get_env(r))}; assert(s == loop.get_scheduler()); - auto st{test_std::transform_sender( - test_std::default_domain(), test_std::affine_on(test_std::just(42)), test_std::get_env(r))}; + auto st{test_std::transform_sender(test_std::affine_on(test_std::just(42)), test_std::get_env(r))}; test_std::connect(std::move(st), std::move(r)); auto s0{test_std::connect(test_std::affine_on(test_std::just(42)), receiver(loop.get_scheduler()))}; diff --git a/tests/beman/execution/exec-connect.test.cpp b/tests/beman/execution/exec-connect.test.cpp index d440d684..41ee5018 100644 --- a/tests/beman/execution/exec-connect.test.cpp +++ b/tests/beman/execution/exec-connect.test.cpp @@ -96,7 +96,7 @@ struct domain_sender { }; struct domain { - auto transform_sender(auto&& sender, auto&&...) const noexcept -> domain_sender { + auto transform_sender(auto&&, auto&& sender, auto&&...) const noexcept -> domain_sender { return domain_sender{sender.value}; } }; @@ -353,9 +353,9 @@ TEST(exec_connect) { static_assert(std::same_as); static_assert(std::same_as); static_assert( - std::same_as); - static_assert( - std::same_as); + std::same_as); + static_assert(std::same_as); static_assert(std::same_as, decltype(test_std::connect(sender{42}, domain_receiver(17)))>); diff --git a/tests/beman/execution/exec-continues-on.test.cpp b/tests/beman/execution/exec-continues-on.test.cpp index 8a025042..e1743e1a 100644 --- a/tests/beman/execution/exec-continues-on.test.cpp +++ b/tests/beman/execution/exec-continues-on.test.cpp @@ -5,10 +5,8 @@ #include #ifdef BEMAN_HAS_MODULES import beman.execution; -import beman.execution.detail.get_domain_late; #else #include -#include #include #endif @@ -78,8 +76,6 @@ auto test_constraints(Scheduler&& scheduler, Sender&& sender) { test::check_type(domain); auto s{test_std::continues_on(::std::forward(sender), ::std::forward(scheduler))}; - auto late{test_detail::get_domain_late(s, test_std::env<>{})}; - //-dk:TODO test::check_type(late); } } diff --git a/tests/beman/execution/exec-domain-default.test.cpp b/tests/beman/execution/exec-domain-default.test.cpp index 57042766..a8bc9abf 100644 --- a/tests/beman/execution/exec-domain-default.test.cpp +++ b/tests/beman/execution/exec-domain-default.test.cpp @@ -36,16 +36,11 @@ struct simple_tag {}; template struct tag { - template - auto transform_sender(Sender&& sender, Env&&...) noexcept(Noexcept) { + template + auto transform_sender(TagParam, Sender&& sender, Env&&...) noexcept(Noexcept) { return simple_sender{sender.value}; } - template - auto transform_env(Sender&&, Env&& e) noexcept { - return env{e.value}; - } - template auto apply_sender(Sender&&, int value) noexcept(Noexcept) { return value; @@ -73,108 +68,72 @@ template auto test_transform_sender(Domain) { static_assert(test_detail::queryable); static_assert(test_std::sender); - static_assert(not requires { Domain::transform_sender(non_sender{}); }); - static_assert(requires { Domain::transform_sender(simple_sender{}); }); - static_assert(requires { Domain::transform_sender(simple_sender{}, env{}); }); - static_assert(not requires { Domain::transform_sender(simple_sender{}, env{}, env{}); }); - static_assert(noexcept(Domain::transform_sender(simple_sender{}))); - static_assert(noexcept(Domain::transform_sender(simple_sender{}, env{}))); - using simple_rvalue_type = decltype(Domain::transform_sender(simple_sender{})); + static_assert(not requires { Domain::transform_sender(simple_tag{}, non_sender{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, simple_sender{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, simple_sender{}, env{}); }); + static_assert(not requires { Domain::transform_sender(simple_tag{}, simple_sender{}, env{}, env{}); }); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, simple_sender{}))); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, simple_sender{}, env{}))); + using simple_rvalue_type = decltype(Domain::transform_sender(simple_tag{}, simple_sender{})); static_assert(std::same_as); - using simple_env_rvalue_type = decltype(Domain::transform_sender(simple_sender{}, env{})); + using simple_env_rvalue_type = decltype(Domain::transform_sender(simple_tag{}, simple_sender{}, env{})); static_assert(std::same_as); simple_sender sender; - using simple_lvalue_type = decltype(Domain::transform_sender(sender)); + using simple_lvalue_type = decltype(Domain::transform_sender(simple_tag{}, sender)); static_assert(std::same_as); - using simple_env_lvalue_type = decltype(Domain::transform_sender(sender, env{})); + using simple_env_lvalue_type = decltype(Domain::transform_sender(simple_tag{}, sender, env{})); static_assert(std::same_as); const simple_sender csender; - using simple_clvalue_type = decltype(Domain::transform_sender(csender)); + using simple_clvalue_type = decltype(Domain::transform_sender(simple_tag{}, csender)); static_assert(std::same_as); - using simple_env_clvalue_type = decltype(Domain::transform_sender(csender, env{})); + using simple_env_clvalue_type = decltype(Domain::transform_sender(simple_tag{}, csender, env{})); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(simple_sender{17}, env{})); - ASSERT(&sender == &Domain::transform_sender(sender, env{})); - ASSERT(&csender == &Domain::transform_sender(csender, env{})); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, simple_sender{17}, env{})); + ASSERT(&sender == &Domain::transform_sender(simple_tag{}, sender, env{})); + ASSERT(&csender == &Domain::transform_sender(simple_tag{}, csender, env{})); static_assert(test_std::sender>); static_assert(test_std::sender>); static_assert(std::same_as, test_std::tag_of_t>>); static_assert(std::same_as, test_std::tag_of_t>>); - static_assert(requires { tag().transform_sender(tagged_sender()); }); - static_assert(requires { tag().transform_sender(tagged_sender(), env{}); }); - static_assert(requires { tag().transform_sender(tagged_sender()); }); - static_assert(requires { tag().transform_sender(tagged_sender(), env{}); }); - static_assert(requires { Domain::transform_sender(tagged_sender()); }); - static_assert(requires { Domain::transform_sender(tagged_sender(), env{}); }); - static_assert(not requires { Domain::transform_sender(tagged_sender(), env{}, env{}); }); - static_assert(requires { Domain::transform_sender(tagged_sender()); }); - static_assert(requires { Domain::transform_sender(tagged_sender(), env{}); }); - static_assert(not requires { Domain::transform_sender(tagged_sender(), env{}, env{}); }); - static_assert(noexcept(Domain::transform_sender(tagged_sender()))); - static_assert(noexcept(Domain::transform_sender(tagged_sender(), env{}))); - static_assert(not noexcept(Domain::transform_sender(tagged_sender()))); - static_assert(not noexcept(Domain::transform_sender(tagged_sender(), env{}))); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(not requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}, env{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(not requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}, env{}); }); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, tagged_sender()))); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, tagged_sender(), env{}))); + static_assert(not noexcept(Domain::transform_sender(simple_tag{}, tagged_sender()))); + static_assert(not noexcept(Domain::transform_sender(simple_tag{}, tagged_sender(), env{}))); { - using type = decltype(Domain::transform_sender(tagged_sender())); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender())); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender())); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender())); } { - using type = decltype(Domain::transform_sender(tagged_sender(), env{})); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender(), env{})); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); } { - using type = decltype(Domain::transform_sender(tagged_sender())); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender())); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender())); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender())); } { - using type = decltype(Domain::transform_sender(tagged_sender(), env{})); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender(), env{})); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); } //-dk:TODO test returning a non-sender doesn't work } -template -auto test_transform_env(Domain) { - static_assert(test_detail::queryable); - static_assert(test_std::sender); - static_assert(requires { Domain::transform_env(simple_sender{}, env{}); }); - static_assert(noexcept(Domain::transform_env(simple_sender{}, env{}))); - { - using type = decltype(Domain::transform_env(simple_sender{}, env{})); - static_assert(std::same_as); - ASSERT(env{17} == Domain::transform_env(simple_sender{}, env{17})); - } - { - env e{17}; - using type = decltype(Domain::transform_env(simple_sender{}, e)); - static_assert(std::same_as); - ASSERT(&e == &Domain::transform_env(simple_sender{}, e)); - } - { - const env ce{17}; - using type = decltype(Domain::transform_env(simple_sender{}, ce)); - static_assert(std::same_as); - ASSERT(&ce == &Domain::transform_env(simple_sender{}, ce)); - } - - static_assert(test_std::sender>); - static_assert(requires { tag{}.transform_env(tagged_sender(), env{}); }); - static_assert(std::same_as{}.transform_env(tagged_sender(), env{}))>); - static_assert(requires { Domain::transform_env(tagged_sender{}, env{}); }); - static_assert(noexcept(Domain::transform_env(tagged_sender{}, env{}))); - { - using type = decltype(Domain::transform_env(tagged_sender{}, env{})); - static_assert(std::same_as); - ASSERT(env{17} == Domain::transform_env(simple_sender{}, env{17})); - } -} - template auto test_apply_sender(Domain) -> void { static_assert(test_std::sender); @@ -203,6 +162,5 @@ auto test_apply_sender(Domain) -> void { TEST(exec_domain_default) { test_std::default_domain domain{}; test_transform_sender(domain); - test_transform_env(domain); test_apply_sender(domain); } diff --git a/tests/beman/execution/exec-env.test.cpp b/tests/beman/execution/exec-env.test.cpp index 3526161d..487112d6 100644 --- a/tests/beman/execution/exec-env.test.cpp +++ b/tests/beman/execution/exec-env.test.cpp @@ -16,6 +16,29 @@ import beman.execution; // ---------------------------------------------------------------------------- +namespace { +struct extra_arg { + int value{}; +}; + +struct multi_arg_query_t { + constexpr auto operator()(const auto& e) const noexcept(noexcept(e.query(*this))) + -> decltype(e.query(*this)) { + return e.query(*this); + } + constexpr auto operator()(const auto& e, extra_arg a) const noexcept(noexcept(e.query(*this, a))) + -> decltype(e.query(*this, a)) { + return e.query(*this, a); + } +}; +constexpr multi_arg_query_t multi_arg_query{}; + +struct multi_arg_env { + auto query(const multi_arg_query_t&) const noexcept { return 42; } + auto query(const multi_arg_query_t&, extra_arg a) const noexcept { return a.value; } +}; +} // namespace + TEST(env) { test_std::inplace_stop_source source{}; [[maybe_unused]] test_std::env<> e0{}; @@ -28,4 +51,16 @@ TEST(env) { assert(s2 == source.get_token()); static_assert(not std::is_assignable_v, test_std::env<>>); + + // P3826R5: env::query now accepts extra arguments (Args&&...) + // The extra args are forwarded to the first matching sub-environment + test_std::env e3{multi_arg_env{}}; + ASSERT(e3.query(multi_arg_query) == 42); + ASSERT(e3.query(multi_arg_query, extra_arg{99}) == 99); + + // Test env with prop that accepts extra args + test_std::env e4{test_std::prop(test_std::get_allocator, std::allocator{}), + multi_arg_env{}}; + ASSERT(e4.query(multi_arg_query) == 42); + ASSERT(e4.query(multi_arg_query, extra_arg{7}) == 7); } diff --git a/tests/beman/execution/exec-get-compl-domain.test.cpp b/tests/beman/execution/exec-get-compl-domain.test.cpp index c801acfe..16b198d6 100644 --- a/tests/beman/execution/exec-get-compl-domain.test.cpp +++ b/tests/beman/execution/exec-get-compl-domain.test.cpp @@ -37,16 +37,17 @@ import beman.execution.detail.completion_signatures; // ---------------------------------------------------------------------------- namespace { - struct throwing_domain { - throwing_domain() noexcept(false) = default; - }; - template - struct domain { - int value{}; - auto operator==(const domain&) const -> bool = default; - }; - - template struct test_env {}; +struct throwing_domain { + throwing_domain() noexcept(false) = default; +}; +template +struct domain { + int value{}; + auto operator==(const domain&) const -> bool = default; +}; + +template +struct test_env {}; template void test_get_completion_domain_template() { @@ -62,75 +63,77 @@ auto test_get_completion_domain_tag() { auto query(test_std::get_completion_domain_t, test_env<3>) const { return throwing_domain{}; } }; - static_assert(std::same_as(queryable_tag{}, test_env<0>{})), domain<0>>); + static_assert(std::same_as(queryable_tag{}, test_env<0>{})), + domain<0>>); ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<0>{}) == domain<0>{}); - static_assert(std::same_as(queryable_tag{}, test_env<1>{})), domain<1>>); + static_assert(std::same_as(queryable_tag{}, test_env<1>{})), + domain<1>>); ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<1>{}) == domain<1>{}); static_assert(std::same_as(queryable_tag{})), domain<2>>); ASSERT(beman::execution::get_completion_domain(queryable_tag{}) == domain<2>{}); - static_assert(std::same_as(queryable_tag{}, test_env<2>{})), domain<2>>); + static_assert(std::same_as(queryable_tag{}, test_env<2>{})), + domain<2>>); ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<2>{}) == domain<2>{}); } - template - struct scheduler { - using scheduler_concept = test_std::scheduler_t; - struct state { - using operation_state_concept = test_std::operation_state_t; - auto start() noexcept {} - }; - struct env { - auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } - }; - struct sender { - using sender_concept = test_std::sender_t; - static consteval auto get_completion_signatures() { return test_std::completion_signatures(); } - auto connect(auto&&) const { return state{}; } - auto get_env() const noexcept { return env{}; } - }; - auto schedule() const { return sender{}; } - - bool operator==(const scheduler&) const = default; - - auto query(test_std::get_completion_domain_t, test_env<0>) const { return domain<0>{42}; } - auto query(test_std::get_completion_domain_t, test_env<1>) const { return domain<1>{42}; } - auto query(test_std::get_completion_domain_t) const { return domain<2>{42}; } - auto query(test_std::get_completion_domain_t, test_env<3>) const { return throwing_domain{}; } +template +struct scheduler { + using scheduler_concept = test_std::scheduler_t; + struct state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept {} }; - static_assert(beman::execution::scheduler>); + struct env { + auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } + }; + struct sender { + using sender_concept = test_std::sender_t; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return state{}; + } + auto get_env() const noexcept { return env{}; } + }; + auto schedule() const { return sender{}; } + + bool operator==(const scheduler&) const = default; + + auto query(test_std::get_completion_domain_t, test_env<0>) const { return domain<0>{42}; } + auto query(test_std::get_completion_domain_t, test_env<1>) const { return domain<1>{42}; } + auto query(test_std::get_completion_domain_t) const { return domain<2>{42}; } + auto query(test_std::get_completion_domain_t, test_env<3>) const { return throwing_domain{}; } +}; +static_assert(beman::execution::scheduler>); template auto test_get_completion_domain_tag_via_scheduler() { - struct initial_queryable{ - auto query(test_std::get_completion_scheduler_t, test_env<0>) const noexcept { return scheduler{}; } - auto query(test_std::get_completion_scheduler_t, test_env<1>) const noexcept { return scheduler{}; } - auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } - auto query(test_std::get_completion_scheduler_t, test_env<2>) const noexcept { return scheduler{}; } + struct initial_queryable { + auto query(test_std::get_completion_scheduler_t, test_env<0>) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t, test_env<1>) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t, test_env<2>) const noexcept { return scheduler{}; } }; test_std::get_completion_scheduler(initial_queryable{}); initial_queryable().query(test_std::get_completion_scheduler, test_env<0>{}); - //-dk:TODO test_std::get_completion_scheduler(initial_queryable{}, test_env<0>{}); - - //static_assert(std::same_as(initial_queryable{}, test_env<0>{})), domain<0>>); - #if 0 - ASSERT(beman::execution::get_completion_domain(initial_queryable{}, test_env<0>{}) == domain<0>{}); - static_assert(std::same_as(initial_queryable{}, test_env<1>{})), domain<1>>); - ASSERT(beman::execution::get_completion_domain(initial_queryable{}, test_env<1>{}) == domain<1>{}); - static_assert(std::same_as(initial_queryable{})), domain<2>>); - ASSERT(beman::execution::get_completion_domain(initial_queryable{}) == domain<2>{}); - static_assert(std::same_as(initial_queryable{}, test_env<2>{})), domain<2>>); - ASSERT(beman::execution::get_completion_domain(initial_queryable{}, test_env<2>{}) == domain<2>{}); - #endif +} + +auto test_void_defaults_to_set_value() { + struct queryable_void_default { + auto query(test_std::get_completion_domain_t) const { return domain<0>{17}; } + }; + static_assert(requires { beman::execution::get_completion_domain(queryable_void_default{}); }); } } // namespace -TEST(exec_with_awaitable_senders) { +TEST(exec_get_compl_domain) { test_get_completion_domain_template(); test_get_completion_domain_template(); test_get_completion_domain_template(); test_get_completion_domain_template(); - //-dk:TODO test compilation failure: test_get_completion_domain_template(); test_get_completion_domain_tag(); test_get_completion_domain_tag(); @@ -139,4 +142,6 @@ TEST(exec_with_awaitable_senders) { test_get_completion_domain_tag(); test_get_completion_domain_tag_via_scheduler(); + + test_void_defaults_to_set_value(); } diff --git a/tests/beman/execution/exec-get-compl-sched.test.cpp b/tests/beman/execution/exec-get-compl-sched.test.cpp index 2ffb7c11..75df8615 100644 --- a/tests/beman/execution/exec-get-compl-sched.test.cpp +++ b/tests/beman/execution/exec-get-compl-sched.test.cpp @@ -60,6 +60,20 @@ template auto test_tag(Env&& env) -> void { static_assert(Expect == requires { test_std::get_completion_scheduler(env); }); } + +struct extra_env { + int extra_value{}; +}; + +struct env_with_extra_args { + int value{}; + auto query(const test_std::get_completion_scheduler_t&) const noexcept { + return scheduler{this->value}; + } + auto query(const test_std::get_completion_scheduler_t&, extra_env e) const noexcept { + return scheduler{this->value + e.extra_value}; + } +}; } // namespace TEST(exec_get_compl_sched) { @@ -95,4 +109,9 @@ TEST(exec_get_compl_sched) { ASSERT(test_std::get_completion_scheduler(e) == scheduler{19}); ASSERT(test_std::get_completion_scheduler(e) == scheduler{20}); ASSERT(test_std::get_completion_scheduler(e) == scheduler{18}); + + env_with_extra_args ewa{10}; + ASSERT(test_std::get_completion_scheduler(ewa) == scheduler{10}); + ASSERT(test_std::get_completion_scheduler(ewa, extra_env{5}) == + scheduler{15}); } diff --git a/tests/beman/execution/exec-get-domain.test.cpp b/tests/beman/execution/exec-get-domain.test.cpp index 759e3231..98dc9605 100644 --- a/tests/beman/execution/exec-get-domain.test.cpp +++ b/tests/beman/execution/exec-get-domain.test.cpp @@ -34,13 +34,54 @@ struct overloaded_get_domain { auto query(const test_std::get_domain_t&) noexcept -> void = delete; }; -template +template auto test_get_domain(Object&& object) { - static_assert(Expect == requires { test_std::get_domain(object); }); if constexpr (requires { test_std::get_domain(object); }) { static_assert(std::same_as); } } + +struct sched_domain {}; + +struct test_sched_sender; +struct test_sched_env; + +struct test_scheduler { + using scheduler_concept = test_std::scheduler_t; + auto schedule() const -> test_sched_sender; + auto operator==(const test_scheduler&) const -> bool = default; + auto query(test_std::get_completion_domain_t) const noexcept { return sched_domain{}; } +}; + +struct test_sched_state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept {} +}; + +struct test_sched_env { + auto query(test_std::get_completion_scheduler_t) const noexcept { return test_scheduler{}; } +}; + +struct test_sched_sender { + using sender_concept = test_std::sender_t; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return test_sched_state{}; + } + auto get_env() const noexcept { return test_sched_env{}; } +}; + +inline auto test_scheduler::schedule() const -> test_sched_sender { return {}; } + +static_assert(test_std::scheduler); + +// Env that has get_scheduler but no get_domain +struct env_with_scheduler { + auto query(test_std::get_scheduler_t) const noexcept { return test_scheduler{}; } +}; } // namespace TEST(exec_get_domain) { @@ -48,12 +89,14 @@ TEST(exec_get_domain) { static_assert(test_std::forwarding_query(test_std::get_domain)); - test_get_domain(no_get_domain{}); - test_get_domain(non_const_get_domain{}); - test_get_domain(non_const_get_domain{}); - test_get_domain(has_get_domain{42}); - test_get_domain(has_get_domain{42}); - test_get_domain(overloaded_get_domain{}); + test_get_domain(no_get_domain{}); // falling back to `default_domain` + test_get_domain(non_const_get_domain{}); // falling back to `default_domain` + test_get_domain(non_const_get_domain{}); // falling back to `default_domain` + test_get_domain(has_get_domain{42}); + test_get_domain(has_get_domain{42}); + test_get_domain(overloaded_get_domain{}); static_assert(42 == test_std::get_domain(has_get_domain{42}).value); + + test_get_domain(env_with_scheduler{}); } diff --git a/tests/beman/execution/exec-get-scheduler.test.cpp b/tests/beman/execution/exec-get-scheduler.test.cpp index e71575cf..0e9b884e 100644 --- a/tests/beman/execution/exec-get-scheduler.test.cpp +++ b/tests/beman/execution/exec-get-scheduler.test.cpp @@ -14,8 +14,13 @@ import beman.execution; namespace { struct scheduler { - int value{}; - auto operator==(const scheduler&) const -> bool = default; + using scheduler_concept = test_std::scheduler_t; + struct sender { + using sender_concept = test_std::sender_t; + }; + int value{}; + auto operator==(const scheduler&) const -> bool = default; + static auto schedule() noexcept -> sender { return {}; } }; struct env { @@ -25,6 +30,7 @@ struct env { } // namespace TEST(exec_get_scheduler) { + static_assert(test_std::scheduler); static_assert(std::same_as); static_assert(test_std::forwarding_query(test_std::get_scheduler)); env e{17}; diff --git a/tests/beman/execution/exec-getcomplsigs.test.cpp b/tests/beman/execution/exec-getcomplsigs.test.cpp index 20a15976..6b1296ea 100644 --- a/tests/beman/execution/exec-getcomplsigs.test.cpp +++ b/tests/beman/execution/exec-getcomplsigs.test.cpp @@ -5,7 +5,6 @@ #include #ifdef BEMAN_HAS_MODULES import beman.execution; -import beman.execution.detail.get_domain_late; //-dk:TODO remove when get_domain_late is removed #else #include #endif @@ -80,15 +79,8 @@ auto test_get_completion_signatures() { }); static_assert(std::same_as); - static_assert( - std::same_as{}, env_with_domain{}))>); static_assert(std::same_as>(), env_with_domain{}), - no_signatures_sender{}, - env_with_domain{}))>); + decltype(test_std::transform_sender(no_signatures_sender{}, env_with_domain{}))>); static_assert(std::same_as())>); static_assert(requires { diff --git a/tests/beman/execution/exec-inline-scheduler.test.cpp b/tests/beman/execution/exec-inline-scheduler.test.cpp new file mode 100644 index 00000000..ffacb3d4 --- /dev/null +++ b/tests/beman/execution/exec-inline-scheduler.test.cpp @@ -0,0 +1,224 @@ +// tests/beman/execution/exec-inline-scheduler.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution; +import beman.execution.detail; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace { + +struct test_receiver { + using receiver_concept = test_std::receiver_t; + bool& called; + auto set_value() && noexcept -> void { called = true; } + auto get_env() const noexcept { return test_std::env{}; } +}; + +struct custom_scheduler { + using scheduler_concept = test_std::scheduler_t; + int id{}; + + struct state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept -> void {} + }; + struct env { + int id{}; + auto query(test_std::get_completion_scheduler_t) const noexcept { + return custom_scheduler{id}; + } + }; + struct sender { + using sender_concept = test_std::sender_t; + int id{}; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return state{}; + } + auto get_env() const noexcept { return env{id}; } + }; + auto schedule() const { return sender{id}; } + auto operator==(const custom_scheduler&) const -> bool = default; +}; + +struct custom_domain { + auto operator==(const custom_domain&) const -> bool = default; +}; + +struct sched_with_domain { + using scheduler_concept = test_std::scheduler_t; + + struct state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept -> void {} + }; + struct sender { + using sender_concept = test_std::sender_t; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return state{}; + } + }; + auto schedule() const { return sender{}; } + auto operator==(const sched_with_domain&) const -> bool = default; + auto query(test_std::get_domain_t) const noexcept { return custom_domain{}; } +}; + +// Receiver whose env provides a scheduler +struct sched_env_receiver { + using receiver_concept = test_std::receiver_t; + bool& called; + + struct env { + auto query(test_std::get_scheduler_t) const noexcept { return custom_scheduler{42}; } + }; + auto set_value() && noexcept -> void { called = true; } + auto get_env() const noexcept { return env{}; } +}; + +struct domain_env_receiver { + using receiver_concept = test_std::receiver_t; + bool& called; + + struct env { + auto query(test_std::get_scheduler_t) const noexcept { return sched_with_domain{}; } + }; + auto set_value() && noexcept -> void { called = true; } + auto get_env() const noexcept { return env{}; } +}; + +auto test_scheduler_concept() { + static_assert(test_std::scheduler); + static_assert(test_std::scheduler); + static_assert(test_std::scheduler); + static_assert(test_std::scheduler); +} + +auto test_schedule_returns_sender() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + static_assert(test_std::sender); + + // Completion signatures: set_value_t() + using sigs = test_std::completion_signatures; + static_assert(std::same_as); +} + +auto test_equality() { + test_std::inline_scheduler s1; + test_std::inline_scheduler s2; + + // All inline_schedulers are equal + ASSERT(s1 == s2); + ASSERT(!(s1 != s2)); +} + +auto test_copyable() { + static_assert(std::copyable); + + test_std::inline_scheduler s1; + test_std::inline_scheduler s2 = s1; + ASSERT(s1 == s2); +} + +auto test_connect_and_start() { + bool called = false; + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto op = test_std::connect(sndr, test_receiver{called}); + static_assert(test_std::operation_state); + ASSERT(!called); + test_std::start(op); + ASSERT(called); +} + +auto test_sender_env_is_inline_attrs() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto attrs = test_std::get_env(sndr); + static_assert(std::same_as>); +} + +auto test_inline_attrs_completion_scheduler() { + auto attrs = test_detail::inline_attrs{}; + + struct test_env { + auto query(test_std::get_scheduler_t) const noexcept { return custom_scheduler{42}; } + }; + + auto sched = attrs.query(test_std::get_completion_scheduler, test_env{}); + static_assert(std::same_as); + ASSERT(sched == custom_scheduler{42}); +} + +auto test_inline_attrs_completion_domain() { + auto attrs = test_detail::inline_attrs{}; + + struct domain_env { + auto query(test_std::get_domain_t) const noexcept { return custom_domain{}; } + }; + + auto dom = attrs.query(test_std::get_completion_domain, domain_env{}); + static_assert(std::same_as); +} + +auto test_connect_with_scheduler_env() { + bool called = false; + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto op = test_std::connect(sndr, sched_env_receiver{called}); + ASSERT(!called); + test_std::start(op); + ASSERT(called); +} + +auto test_get_completion_scheduler_with_env() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto attrs = test_std::get_env(sndr); + + struct test_env { + auto query(test_std::get_scheduler_t) const noexcept { return custom_scheduler{7}; } + }; + + auto sched = test_std::get_completion_scheduler(attrs, test_env{}); + static_assert(std::same_as); + ASSERT(sched == custom_scheduler{7}); +} + +auto test_get_completion_domain_with_env() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto attrs = test_std::get_env(sndr); + + struct test_env { + auto query(test_std::get_domain_t) const noexcept { return custom_domain{}; } + }; + + auto dom = test_std::get_completion_domain(attrs, test_env{}); + static_assert(std::same_as); +} + +} // namespace + +TEST(exec_inline_scheduler) { + test_scheduler_concept(); + test_schedule_returns_sender(); + test_equality(); + test_copyable(); + test_connect_and_start(); + test_sender_env_is_inline_attrs(); + test_inline_attrs_completion_scheduler(); + test_inline_attrs_completion_domain(); + test_connect_with_scheduler_env(); + test_get_completion_scheduler_with_env(); + test_get_completion_domain_with_env(); +} diff --git a/tests/beman/execution/exec-on.test.cpp b/tests/beman/execution/exec-on.test.cpp index dd875e27..3661a542 100644 --- a/tests/beman/execution/exec-on.test.cpp +++ b/tests/beman/execution/exec-on.test.cpp @@ -42,15 +42,9 @@ auto test_interface(Sch sch, Sndr sndr, Closure closure) -> void { test::use(sndr1, sndr2, sndr3); } -template OutSndr> -auto test_transform_env(OutSndr out_sndr) -> void { - auto e{test_std::on.transform_env(out_sndr, test_std::env<>{})}; - test::use(e); -} - template OutSndr> auto test_transform_sender(OutSndr out_sndr) -> void { - auto s{test_std::on.transform_sender(std::move(out_sndr), test_std::env<>{})}; + auto s{test_std::on.transform_sender(test_std::set_value, std::move(out_sndr), test_std::env<>{})}; static_assert(test_std::sender); auto ts{std::move(s) | test_std::then([](auto&&...) {})}; static_assert(test_std::sender); @@ -75,10 +69,6 @@ TEST(exec_on) { static_assert(not test_detail::is_sender_adaptor_closure); test_interface(pool.get_scheduler(), test_std::just(), test_std::then([] {})); - test_transform_env(test_detail::make_sender(test_std::on, pool.get_scheduler(), test_std::just())); - test_transform_env(test_detail::make_sender( - test_std::on, test_detail::product_type{pool.get_scheduler(), test_std::then([] {})}, test_std::just())); - test_transform_sender(test_detail::make_sender(test_std::on, pool.get_scheduler(), test_std::just())); test_transform_sender(test_detail::make_sender( test_std::on, test_detail::product_type{pool.get_scheduler(), test_std::then([] {})}, test_std::just())); diff --git a/tests/beman/execution/exec-prop.test.cpp b/tests/beman/execution/exec-prop.test.cpp index 40810315..ef97abb3 100644 --- a/tests/beman/execution/exec-prop.test.cpp +++ b/tests/beman/execution/exec-prop.test.cpp @@ -45,4 +45,12 @@ TEST(exec_prop) { [[maybe_unused]] decltype(p0) p2(p0); static_assert(not std::is_assignable_v); static_assert(not std::is_assignable_v>); + + // P3826R5: prop::query now accepts extra arguments (auto&&...) + // The extra arguments are ignored but allowed + auto p3{test_std::prop(test_query, 99)}; + ASSERT(p3.query(test_query) == 99); + ASSERT(p3.query(test_query, 1) == 99); + ASSERT(p3.query(test_query, 1, 2) == 99); + ASSERT(p3.query(test_query, 1, 2, 3) == 99); } diff --git a/tests/beman/execution/exec-queries-expos.test.cpp b/tests/beman/execution/exec-queries-expos.test.cpp index 01df2157..06acee24 100644 --- a/tests/beman/execution/exec-queries-expos.test.cpp +++ b/tests/beman/execution/exec-queries-expos.test.cpp @@ -5,7 +5,7 @@ #ifdef BEMAN_HAS_MODULES import beman.execution.detail.get_domain; import beman.execution.detail.get_scheduler; -import beman.execution.detail.hide_query; +import beman.execution.detail.hide_sched; import beman.execution.detail.try_query; #else #include diff --git a/tests/beman/execution/exec-sched.test.cpp b/tests/beman/execution/exec-sched.test.cpp index 363791a9..70d5312d 100644 --- a/tests/beman/execution/exec-sched.test.cpp +++ b/tests/beman/execution/exec-sched.test.cpp @@ -5,6 +5,7 @@ #ifdef BEMAN_HAS_MODULES import beman.execution; #else +#include #include #endif @@ -72,10 +73,10 @@ struct scheduler { auto operator==(const scheduler&) const -> bool = default; }; -struct bad_completion_scheduler { +struct indirect_completion_scheduler { using scheduler_concept = test_std::scheduler_t; auto schedule() -> sender> { return {}; } - auto operator==(const bad_completion_scheduler&) const -> bool = default; + auto operator==(const indirect_completion_scheduler&) const -> bool = default; }; template @@ -106,6 +107,6 @@ TEST(exec_sched) { test_scheduler(); test_scheduler(); test_scheduler(); - test_scheduler(); + test_scheduler(); test_scheduler(); } diff --git a/tests/beman/execution/exec-schedule-from.test.cpp b/tests/beman/execution/exec-schedule-from.test.cpp deleted file mode 100644 index 924b9e75..00000000 --- a/tests/beman/execution/exec-schedule-from.test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// src/beman/execution/tests/exec-schedule-from.test.cpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#include -#ifdef BEMAN_HAS_MODULES -import beman.execution; -import beman.execution.detail; -#else -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace { -struct non_scheduler {}; -struct non_sender {}; - -struct scheduler { - struct env { - auto query(const test_std::get_completion_scheduler_t&) const noexcept -> scheduler { - return {}; - } - }; - struct sender { - template - struct state { - using operation_state_concept = test_std::operation_state_t; - std::remove_cvref_t receiver; - auto start() & noexcept -> void { test_std::set_value(::std::move(this->receiver)); } - }; - using sender_concept = test_std::sender_t; - template - static consteval auto get_completion_signatures() -> test_std::completion_signatures { - return {}; - } - auto get_env() const noexcept -> env { return {}; } - template - auto connect(Receiver&& receiver) -> state { - return {std::forward(receiver)}; - } - }; - using scheduler_concept = test_std::scheduler_t; - auto schedule() -> sender { return {}; } - auto operator==(const scheduler&) const -> bool = default; -}; -struct sender { - using sender_concept = test_std::sender_t; - template - static consteval auto get_completion_signatures() -> test_std::completion_signatures { - return {}; - } - - template - struct state { - using operation_state_concept = test_std::operation_state_t; - std::remove_cvref_t receiver; - auto start() & noexcept -> void { test_std::set_value(::std::move(this->receiver)); } - }; - template - auto connect(Receiver&& receiver) -> state { - return {std::forward(receiver)}; - } -}; - -template -auto test_constraints(Scheduler&& scheduler, Sender&& sender) { - static_assert(Expect == requires { test_std::schedule_from(scheduler, sender); }); - static_assert(Expect == requires { - test_std::schedule_from(::std::forward(scheduler), ::std::forward(sender)); - }); -} - -template -auto test_use(Scheduler&& scheduler, Sender&& sender) { - auto s{test_std::schedule_from(::std::forward(scheduler), ::std::forward(sender))}; - - static_assert(test_std::sender); - test_std::sync_wait(std::move(s)); -} -} // namespace - -TEST(exec_schedule_from) { - static_assert(std::same_as); - static_assert(not test_std::scheduler); - static_assert(test_std::scheduler); - static_assert(not test_std::sender); - static_assert(test_std::sender); - - test_constraints(non_scheduler{}, non_sender{}); - test_constraints(non_scheduler{}, sender{}); - test_constraints(scheduler{}, non_sender{}); - test_constraints(scheduler{}, sender{}); - - test_use(scheduler{}, sender{}); -} diff --git a/tests/beman/execution/exec-snd-expos.test.cpp b/tests/beman/execution/exec-snd-expos.test.cpp index 67de17a6..852cd7ca 100644 --- a/tests/beman/execution/exec-snd-expos.test.cpp +++ b/tests/beman/execution/exec-snd-expos.test.cpp @@ -22,12 +22,9 @@ import beman.execution.detail; #include #include #include -#include #include #include #include -#include -#include #include #include #include @@ -260,30 +257,6 @@ auto test_join_env() -> void { ASSERT(cenv.query(custom_query<2>, 13) == 30); } -auto test_sched_attrs() -> void { - scheduler sched{17}; - ASSERT(sched.query(test_std::get_domain) == domain{17}); - - auto attrs{test_detail::sched_attrs(sched)}; - static_assert(test_detail::queryable); - - auto sched_error{attrs.query(test_std::get_completion_scheduler)}; - static_assert(::std::same_as); - ASSERT(sched_error == sched); - - auto sched_stopped{attrs.query(test_std::get_completion_scheduler)}; - static_assert(::std::same_as); - ASSERT(sched_stopped == sched); - - auto sched_value{attrs.query(test_std::get_completion_scheduler)}; - static_assert(::std::same_as); - ASSERT(sched_value == sched); - - auto dom{attrs.query(test_std::get_domain)}; - static_assert(::std::same_as); - ASSERT(dom == domain{17}); -} - auto test_sched_env() -> void { scheduler sched{17}; ASSERT(sched.query(test_std::get_domain) == domain{17}); @@ -389,11 +362,6 @@ auto test_completion_domain() -> void { static_assert(std::same_as( cd::env{})))>); - static_assert(std::same_as{})))>); - static_assert(std::same_as{})))>); - static_assert(std::same_as{})))>); - static_assert( - std::same_as{})))>); } auto test_query_with_default() -> void { @@ -401,7 +369,8 @@ auto test_query_with_default() -> void { static_assert(std::same_as); ASSERT(result1.value == 43); - auto result2{test_detail::query_with_default(test_std::get_domain, test_std::env<>(), default_domain{74})}; + auto result2{ + test_detail::query_with_default(test_std::get_completion_domain<>, test_std::env<>(), default_domain{74})}; static_assert(std::same_as); ASSERT(result2.default_value == 74); } @@ -411,11 +380,9 @@ auto test_get_domain_early() -> void { using sender_concept = test_std::sender_t; }; static_assert(test_std::sender); - static_assert(std::same_as); namespace cd = completion_domain; static_assert(test_std::sender>); - static_assert(std::same_as{}))>); struct sender_with_domain { using sender_concept = test_std::sender_t; @@ -428,15 +395,12 @@ auto test_get_domain_early() -> void { static_assert(test_std::sender); static_assert(std::same_as); static_assert(std::same_as); - static_assert( - std::same_as); } template auto test_get_domain_late(auto sender, auto env) -> void { static_assert(test_std::sender); static_assert(test_detail::queryable); - static_assert(std::same_as); } struct get_domain_late_scheduler { @@ -446,6 +410,11 @@ struct get_domain_late_scheduler { auto query(const test_std::get_completion_scheduler_t&) const noexcept -> get_domain_late_scheduler { return {}; } + + template + auto query(const test_std::get_completion_domain_t&) const noexcept -> dom { + return {}; + } }; struct sender { using sender_concept = test_std::sender_t; @@ -496,8 +465,8 @@ auto test_get_domain_late() -> void { }; static_assert(test_std::sender); static_assert(std::same_as); - static_assert( - std::same_as); + static_assert(std::same_as{}))>); test_get_domain_late(scheduler_sender{}, test_std::env<>{}); struct env_sender { @@ -1145,8 +1114,7 @@ auto test_basic_sender() -> void { static_assert(test_std::sender); static_assert(std::same_as>); static_assert( - std::same_as); + std::same_as); using basic_sender = test_detail::basic_sender; static_assert(test_std::sender); @@ -1161,8 +1129,7 @@ auto test_basic_sender() -> void { static_assert(std::same_as>); static_assert( - std::same_as); + std::same_as); static_assert(test_std::dependent_sender); // According to https://eel.is/c++draft/exec#adapt.general-3.5, basic_sender shall be a dependent-sender static_assert(test_std::dependent_sender); @@ -1340,7 +1307,6 @@ TEST(exec_snd_expos) { test_fwd_env(); test_make_env(); test_join_env(); - test_sched_attrs(); test_sched_env(); test_completion_domain(); test_query_with_default(); diff --git a/tests/beman/execution/exec-snd-transform.test.cpp b/tests/beman/execution/exec-snd-transform.test.cpp index 2a1a2497..a57ee78b 100644 --- a/tests/beman/execution/exec-snd-transform.test.cpp +++ b/tests/beman/execution/exec-snd-transform.test.cpp @@ -6,11 +6,9 @@ #include #ifdef BEMAN_HAS_MODULES import beman.execution; +import beman.execution.detail; #else -#include -#include #include -#include #endif // ---------------------------------------------------------------------------- @@ -18,7 +16,6 @@ import beman.execution; namespace { enum class kind : unsigned char { dom, tag }; struct env {}; -struct empty_domain {}; template struct final_sender { @@ -33,8 +30,8 @@ struct sender; template struct tag { - template - auto transform_sender(Sender sndr, Env&&...) const noexcept { + template + auto transform_sender(TagParam, Sender sndr, Env&&...) const noexcept { if constexpr (1 < I) return sender{{}, sndr.value}; else @@ -52,18 +49,21 @@ struct sender { }; struct special_domain { - template + template requires std::same_as, final_sender> - auto transform_sender(Sender&& sndr, auto&&...) const -> decltype(auto) { + auto transform_sender(TagParam, Sender&& sndr, auto&&...) const -> decltype(auto) { return std::forward(sndr); } - template + template requires std::same_as, final_sender> - auto transform_sender(Sender&& sndr, auto&&...) const { + auto transform_sender(TagParam, Sender&& sndr, auto&&...) const { return final_sender{sndr.value}; } - auto transform_sender(auto&& sndr, auto&&...) const { - using index_type = std::remove_cvref_t::index_type; + template + requires(!std::same_as, final_sender> && + !std::same_as, final_sender>) + auto transform_sender(TagParam, Sndr&& sndr, auto&&...) const { + using index_type = std::remove_cvref_t::index_type; if constexpr (1 < index_type::value) return sender{{}, sndr.value}; else @@ -71,84 +71,138 @@ struct special_domain { } }; -template -auto test_transform_sender(Dom&& dom, Sender&& sndr) { - auto value{sndr.value}; - static_assert(test_std::sender>); - static_assert(requires { test_std::transform_sender(dom, std::forward(sndr)); }); - if constexpr (requires { test_std::transform_sender(dom, std::forward(sndr)); }) { - static_assert(std::same_as(sndr)))>); - static_assert(Noexcept == noexcept(test_std::transform_sender(dom, std::forward(sndr)))); - ASSERT(value == test_std::transform_sender(dom, std::forward(sndr)).value); - } -} +template +struct compl_domain_attrs { + auto query(test_std::get_completion_domain_t) const noexcept { return Domain{}; } +}; + +template +struct domain_sender { + using sender_concept = test_std::sender_t; + using is_basic_sender_tag = void; + using index_type = std::integral_constant; + tag t; + int value{}; + auto get_env() const noexcept { return compl_domain_attrs{}; } +}; -template -auto test_transform_sender_env(Dom&& dom, Sender&& sndr) { - auto value{sndr.value}; - static_assert(requires { test_std::transform_sender(dom, std::forward(sndr), env{}); }); - if constexpr (requires { test_std::transform_sender(dom, std::forward(sndr), env{}); }) { - static_assert( - std::same_as(sndr), env{}))>); - static_assert(Noexcept == noexcept(test_std::transform_sender(dom, std::forward(sndr), env{}))); - ASSERT(value == test_std::transform_sender(dom, std::forward(sndr), env{}).value); +struct start_domain { + template + requires std::same_as, final_sender> + auto transform_sender(test_std::start_t, Sndr&& sndr, const auto&) const { + return final_sender{sndr.value}; } +}; + +template +struct starting_domain_env { + auto query(test_std::get_domain_t) const noexcept { return Domain{}; } +}; + +auto test_indeterminate_domain_transform() { + test_std::indeterminate_domain<> idom; + static_assert(requires { idom.transform_sender(test_std::set_value, final_sender{42}, env{}); }); + auto result = idom.transform_sender(test_std::set_value, final_sender{42}, env{}); + static_assert(test_std::sender); + ASSERT(result.value == 42); - static_assert(not requires { test_std::transform_sender(dom, std::forward(sndr), env{}, env{}); }); + test_std::indeterminate_domain idom2; + auto result2 = idom2.transform_sender(test_std::set_value, final_sender{17}, env{}); + ASSERT(result2.value == 17); } } // namespace TEST(exec_snd_transform) { - test_transform_sender&&>(empty_domain{}, final_sender{42}); - test_transform_sender_env&&>(empty_domain{}, final_sender{42}); - final_sender fs{42}; - test_transform_sender&>(empty_domain{}, fs); - test_transform_sender_env&>(empty_domain{}, fs); - const final_sender cfs{42}; - test_transform_sender&>(empty_domain{}, cfs); - test_transform_sender_env&>(empty_domain{}, cfs); - static_assert(std::same_as, test_std::tag_of_t>>); static_assert(std::same_as, test_std::tag_of_t>>); - static_assert(std::same_as, decltype(tag<1>{}.transform_sender(sender<1>{{}, 0}))>); - static_assert(std::same_as, decltype(tag<1>{}.transform_sender(sender<1>{{}, 0}, env{}))>); - static_assert(std::same_as, - decltype(test_std::default_domain{}.transform_sender(sender<1>{{}, 0}))>); + using Tag1 = std::integral_constant; + using Tag2 = std::integral_constant; + static_assert( + std::same_as, decltype(tag<1>{}.transform_sender(Tag1{}, sender<1>{{}, 0}))>); + static_assert( + std::same_as, decltype(tag<1>{}.transform_sender(Tag1{}, sender<1>{{}, 0}, env{}))>); + static_assert(std::same_as, decltype(tag<2>{}.transform_sender(Tag2{}, sender<2>{{}, 0}))>); static_assert(std::same_as, - decltype(test_std::default_domain{}.transform_sender(sender<1>{{}, 0}, env{}))>); + decltype(test_std::default_domain{}.transform_sender(Tag1{}, sender<1>{{}, 0}))>); + static_assert( + std::same_as, + decltype(test_std::default_domain{}.transform_sender(Tag1{}, sender<1>{{}, 0}, env{}))>); + + // Identity: final senders (no tag customization) pass through unchanged + { + static_assert(requires { test_std::transform_sender(final_sender{42}, env{}); }); + final_sender r = test_std::transform_sender(final_sender{42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + { + final_sender r = test_std::transform_sender(final_sender{42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } - static_assert(std::same_as, decltype(tag<2>{}.transform_sender(sender<2>{{}, 0}))>); - static_assert(std::same_as, decltype(tag<2>{}.transform_sender(sender<2>{{}, 0}, env{}))>); + // Single-step recursive reduction through default completion domain + { + final_sender r = test_std::transform_sender(sender<1>{{}, 42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } - test_transform_sender>(empty_domain{}, sender<1>{{}, 42}); - test_transform_sender_env>(empty_domain{}, sender<1>{{}, 42}); - test_transform_sender>(empty_domain{}, sender<2>{{}, 42}); - test_transform_sender_env>(empty_domain{}, sender<2>{{}, 42}); - test_transform_sender>(empty_domain{}, sender<5>{{}, 42}); - test_transform_sender_env>(empty_domain{}, sender<5>{{}, 42}); + // Multi-step recursive reduction + { + final_sender r = test_std::transform_sender(sender<2>{{}, 17}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 17); + } + { + final_sender r = test_std::transform_sender(sender<3>{{}, 42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + { + final_sender r = test_std::transform_sender(sender<5>{{}, 99}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 99); + } - static_assert(std::same_as&&, - decltype(special_domain{}.transform_sender(final_sender{}))>); - static_assert( - std::same_as, decltype(special_domain{}.transform_sender(final_sender{}))>); - static_assert( - std::same_as, decltype(special_domain{}.transform_sender(sender<1>{{}, 42}))>); - static_assert(std::same_as, decltype(special_domain{}.transform_sender(sender<2>{{}, 42}))>); - test_transform_sender&&>(special_domain{}, final_sender{42}); - test_transform_sender_env&&>(special_domain{}, final_sender{42}); - final_sender fd{42}; - test_transform_sender&>(special_domain{}, fd); - test_transform_sender_env&>(special_domain{}, fd); - const final_sender cfd{42}; - test_transform_sender&>(special_domain{}, cfd); - test_transform_sender_env&>(special_domain{}, cfd); - test_transform_sender>(special_domain{}, final_sender{42}); - test_transform_sender_env>(special_domain{}, final_sender{42}); - test_transform_sender>(special_domain{}, sender<1>{{}, 42}); - test_transform_sender_env>(special_domain{}, sender<1>{{}, 42}); - test_transform_sender>(special_domain{}, sender<2>{{}, 42}); - test_transform_sender_env>(special_domain{}, sender<2>{{}, 42}); - test_transform_sender>(special_domain{}, sender<5>{{}, 42}); - test_transform_sender_env>(special_domain{}, sender<5>{{}, 42}); + { + final_sender r = test_std::transform_sender(domain_sender<1, special_domain>{{}, 42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + { + final_sender r = test_std::transform_sender(domain_sender<2, special_domain>{{}, 17}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 17); + } + { + final_sender r = test_std::transform_sender(domain_sender<5, special_domain>{{}, 99}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 99); + } + + { + final_sender r = test_std::transform_sender(sender<1>{{}, 42}, starting_domain_env{}); + static_assert(test_std::sender); + static_assert(std::same_as>); + ASSERT(r.value == 42); + } + { + // Multi-step completion, then starting domain + final_sender r = test_std::transform_sender(sender<3>{{}, 77}, starting_domain_env{}); + static_assert(std::same_as>); + ASSERT(r.value == 77); + } + + // Both custom completion and starting domains + { + final_sender r = + test_std::transform_sender(domain_sender<1, special_domain>{{}, 42}, starting_domain_env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + + // indeterminate_domain + test_indeterminate_domain_transform(); } diff --git a/tests/beman/execution/exec-when-all.test.cpp b/tests/beman/execution/exec-when-all.test.cpp index 6bf697fe..a605da33 100644 --- a/tests/beman/execution/exec-when-all.test.cpp +++ b/tests/beman/execution/exec-when-all.test.cpp @@ -206,7 +206,7 @@ auto test_when_all() -> void { test_when_all_available(multi_sender()); test_when_all_available(multi_sender()); test_when_all_available(domain_sender>(), domain_sender>()); - test_when_all_available(domain_sender>(), domain_sender>()); + test_when_all_available(domain_sender>(), domain_sender>()); test_when_all_breathing(); diff --git a/tests/beman/execution/execution-module.test.cpp b/tests/beman/execution/execution-module.test.cpp index b11e998f..340ea46d 100644 --- a/tests/beman/execution/execution-module.test.cpp +++ b/tests/beman/execution/execution-module.test.cpp @@ -101,10 +101,7 @@ TEST(execution_modules) { test::use_template(); // [exec.snd.transform], sender transformations - test_std::transform_sender(test_std::default_domain{}, test_std::just()); - - // [exec.snd.transform.env], environment transformations - //-dk:TODO test_std::transform_env(test_std::default_domain{}, test_std::just(), test_std::env<>{}); + // test_std::transform_sender(test_std::default_domain{}, test_std::just()); // [exec.snd.apply], sender algorithm application //-dk:TODO test_std::apply_sender(test_std::default_domain{}, test_std::just_t{}, test_std::just()); From 99be8929ceed8a733e11fa3e88f5e2632296a85c Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Tue, 28 Apr 2026 22:10:28 +0800 Subject: [PATCH 11/16] Add missing modules --- include/beman/execution/detail/common_domain.hpp | 4 ---- src/beman/execution/CMakeLists.txt | 2 ++ src/beman/execution/common_domain.cppm | 12 ++++++++++++ src/beman/execution/execution-detail.cppm | 2 ++ 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 src/beman/execution/common_domain.cppm diff --git a/include/beman/execution/detail/common_domain.hpp b/include/beman/execution/detail/common_domain.hpp index 5dbc9396..889dcf0a 100644 --- a/include/beman/execution/detail/common_domain.hpp +++ b/include/beman/execution/detail/common_domain.hpp @@ -21,10 +21,6 @@ import beman.execution.detail.indeterminate_domain; namespace beman::execution::detail { -// COMMON-DOMAIN(domains...): -// common_type_t() if well-formed, -// otherwise indeterminate_domain() where Ds is the pack of types -// consisting of decltype(auto(domains))... with duplicates removed. template struct common_domain_impl { using type = ::beman::execution::indeterminate_domain; diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index b3f3a280..a24ace03 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -46,6 +46,7 @@ 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/common_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/compl_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signature.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signatures.hpp @@ -240,6 +241,7 @@ if(BEMAN_USE_MODULES) check_type_alias_exist.cppm child_type.cppm class_type.cppm + common_domain.cppm compl_domain.cppm completion_signature.cppm completion_signatures_for.cppm diff --git a/src/beman/execution/common_domain.cppm b/src/beman/execution/common_domain.cppm new file mode 100644 index 00000000..33e28967 --- /dev/null +++ b/src/beman/execution/common_domain.cppm @@ -0,0 +1,12 @@ +module; +// src/beman/execution/common_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.common_domain; + +namespace beman::execution::detail { +export using beman::execution::detail::common_domain_t; +export using beman::execution::detail::common_domain; +} // namespace beman::execution::detail diff --git a/src/beman/execution/execution-detail.cppm b/src/beman/execution/execution-detail.cppm index e279a484..36f1328c 100644 --- a/src/beman/execution/execution-detail.cppm +++ b/src/beman/execution/execution-detail.cppm @@ -38,6 +38,8 @@ export import beman.execution.detail.immovable; export import beman.execution.detail.impls_for; export import beman.execution.detail.indices_for; export import beman.execution.detail.indirect_meta_apply; +export import beman.execution.detail.inline_attrs; +export import beman.execution.detail.inline_scheduler; export import beman.execution.detail.is_awaitable; export import beman.execution.detail.is_awaiter; export import beman.execution.detail.is_sender; From 71657a18daddbb0079928f7cf75f0740b56ff389 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Wed, 29 Apr 2026 11:02:31 +0800 Subject: [PATCH 12/16] Fix continues_on --- .../execution/detail/call_with_default.hpp | 44 ------------------- .../beman/execution/detail/continues_on.hpp | 13 ++---- include/beman/execution/detail/env.hpp | 21 +++++---- include/beman/execution/detail/starts_on.hpp | 6 --- include/beman/execution/detail/try_query.hpp | 2 +- 5 files changed, 15 insertions(+), 71 deletions(-) delete mode 100644 include/beman/execution/detail/call_with_default.hpp diff --git a/include/beman/execution/detail/call_with_default.hpp b/include/beman/execution/detail/call_with_default.hpp deleted file mode 100644 index 149c80b9..00000000 --- a/include/beman/execution/detail/call_with_default.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// include/beman/execution/detail/call_with_default.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_WITH_DEFAULT -#define INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_WITH_DEFAULT - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { - -// call-with-default(fn, default, args...): -// If fn(args...) is well-formed, returns fn(args...). -// Otherwise, returns static_cast(default). -template - requires requires(Fn&& fn, Args&&... args) { - ::std::forward(fn)(::std::forward(args)...); - } -constexpr decltype(auto) call_with_default(Fn&& fn, Default&&, Args&&... args) noexcept( - noexcept(::std::forward(fn)(::std::forward(args)...))) { - return ::std::forward(fn)(::std::forward(args)...); -} - -template - requires(not requires(Fn&& fn, Args&&... args) { - ::std::forward(fn)(::std::forward(args)...); - }) -constexpr auto call_with_default(Fn&&, Default&& value, Args&&...) noexcept( - noexcept(static_cast(::std::forward(value)))) -> Default { - return static_cast(::std::forward(value)); -} - -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_CALL_WITH_DEFAULT diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index 60088c1a..294196ca 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -194,15 +194,10 @@ struct continues_on_t { ::std::monostate, ::beman::execution::detail::meta::transform< ::beman::execution::detail::as_tuple_t, - ::beman::execution::detail::meta::to< - ::std::variant, - ::beman::execution::detail::meta::combine< - ::beman::execution::completion_signatures_of_t< - ::beman::execution::detail::child_type, - ::beman::execution::env_of_t>, - ::beman::execution::completion_signatures<::beman::execution::set_error_t( - ::std::exception_ptr), - ::beman::execution::set_stopped_t()>>>>>>; + ::beman::execution::detail::meta::to<::std::variant, + ::beman::execution::completion_signatures_of_t< + ::beman::execution::detail::child_type, + ::beman::execution::env_of_t>>>>>; return state_type(sch, receiver); }; diff --git a/include/beman/execution/detail/env.hpp b/include/beman/execution/detail/env.hpp index ac496c40..86e4ff14 100644 --- a/include/beman/execution/detail/env.hpp +++ b/include/beman/execution/detail/env.hpp @@ -9,13 +9,16 @@ import std; #else #include +#include #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.non_assignable; import beman.execution.detail.queryable; +import beman.execution.detail.type_list; #else #include #include +#include #endif // ---------------------------------------------------------------------------- @@ -42,21 +45,17 @@ struct find_env { using type = typename find_env::type; }; -// find_env variant that supports additional args -template -struct args_list {}; - template struct find_env_with_args; template - requires has_query -struct find_env_with_args, E0, E...> { + requires ::beman::execution::detail::has_query +struct find_env_with_args, E0, E...> { using type = E0; }; template - requires(not has_query) -struct find_env_with_args, E0, E...> { - using type = typename find_env_with_args, E...>::type; + requires(not ::beman::execution::detail::has_query) +struct find_env_with_args, E0, E...> { + using type = typename find_env_with_args, E...>::type; }; } // namespace beman::execution::detail @@ -70,8 +69,8 @@ struct env : ::beman::execution::detail::env_base... { template requires(::beman::execution::detail::has_query || ...) constexpr auto query(Q q, Args&&... args) const noexcept -> decltype(auto) { - using E = typename ::beman::execution::detail::find_env_with_args< - Q, ::beman::execution::detail::args_list, Envs...>::type; + using E = typename ::beman::execution::detail:: + find_env_with_args, Envs...>::type; return static_cast&>(*this).env_.query( q, ::std::forward(args)...); } diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index 12c70f72..1719be47 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -59,16 +59,11 @@ import beman.execution.detail.transform_sender; namespace beman::execution::detail { -// starts_on_attrs_t: attrs object for starts_on(sch, sndr). -// When asked for its completion domain, it injects the scheduler's env into -// the child's completion domain query (the child knows it will start on sch). template struct starts_on_attrs_t { Scheduler sch; ChildEnv child_env; - // Answer get_completion_domain queries: delegate to the child's env with - // the scheduler's context (sched_env(sch)) prepended to rcvr_env. template auto query(::beman::execution::get_completion_domain_t, const Env& rcvr_env) const noexcept { auto env_for_child = ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(sch), @@ -80,7 +75,6 @@ struct starts_on_attrs_t { } } - // Forward all other forwarding queries to child_env. template requires requires { ::std::as_const(child_env).query(::std::declval(), ::std::declval()...); } auto query(Q q, Args&&... args) const noexcept { diff --git a/include/beman/execution/detail/try_query.hpp b/include/beman/execution/detail/try_query.hpp index 352c4698..60bff1ae 100644 --- a/include/beman/execution/detail/try_query.hpp +++ b/include/beman/execution/detail/try_query.hpp @@ -8,7 +8,7 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else -#include +#include #endif #if BEMAN_HAS_MODULES import beman.execution.detail.queryable; From f78237eddf5085a537f0a2b3a24720d15249839a Mon Sep 17 00:00:00 2001 From: Cra3z Date: Thu, 30 Apr 2026 17:08:26 +0800 Subject: [PATCH 13/16] GCC/MSVC module bug workaround --- .../detail/atomic_intrusive_stack.hpp | 6 ++--- .../detail/get_completion_domain.hpp | 24 ++++++++++--------- .../detail/get_completion_scheduler.hpp | 14 ++++++----- include/beman/execution/detail/get_domain.hpp | 5 +++- .../beman/execution/detail/get_scheduler.hpp | 13 +++++----- include/beman/execution/detail/hide_sched.hpp | 8 +++---- .../execution/detail/intrusive_stack.hpp | 8 +++---- .../execution/detail/transform_sender.hpp | 11 ++++----- src/beman/execution/execution.cppm | 4 +--- 9 files changed, 45 insertions(+), 48 deletions(-) diff --git a/include/beman/execution/detail/atomic_intrusive_stack.hpp b/include/beman/execution/detail/atomic_intrusive_stack.hpp index 1113e7ef..4db200e2 100644 --- a/include/beman/execution/detail/atomic_intrusive_stack.hpp +++ b/include/beman/execution/detail/atomic_intrusive_stack.hpp @@ -80,11 +80,9 @@ class atomic_intrusive_stack { auto stack = ::beman::execution::detail::intrusive_stack{}; void* ptr = head_.exchange(this); if (ptr == this) { - return stack; + return {}; } - auto item = static_cast(ptr); - stack.head_ = item; - return stack; + return ::beman::execution::detail::intrusive_stack{static_cast(ptr)}; } private: diff --git a/include/beman/execution/detail/get_completion_domain.hpp b/include/beman/execution/detail/get_completion_domain.hpp index d368bb8f..a150ba98 100644 --- a/include/beman/execution/detail/get_completion_domain.hpp +++ b/include/beman/execution/detail/get_completion_domain.hpp @@ -37,28 +37,28 @@ import beman.execution.detail.try_query; namespace beman::execution::detail { struct no_completion_domain {}; -template - requires ::std::same_as || ::beman::execution::detail::completion_tag +template + requires ::std::same_as || ::beman::execution::detail::completion_tag struct get_completion_domain_t : ::beman::execution::forwarding_query_t { template static auto impl(Q&& q, E&&... e) noexcept { if constexpr (requires { ::beman::execution::detail::try_query( - ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); + ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); }) { return ::beman::execution::detail::try_query( - ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); - } else if constexpr (::std::same_as) { + ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); + } else if constexpr (::std::same_as) { return get_completion_domain_t<::beman::execution::set_value_t>::impl(::std::forward(q), ::std::forward(e)...); } else if constexpr (requires { ::beman::execution::detail::try_query( - ::beman::execution::get_completion_scheduler(q, e...), + ::beman::execution::get_completion_scheduler(q, e...), get_completion_domain_t<::beman::execution::set_value_t>{}, ::std::forward(q), ::std::forward(e)...); }) { - return ::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), + return ::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), get_completion_domain_t<::beman::execution::set_value_t>{}, ::std::forward(q), ::std::forward(e)...); @@ -83,10 +83,12 @@ struct get_completion_domain_t : ::beman::execution::forwarding_query_t { } // namespace beman::execution::detail namespace beman::execution { -template -using get_completion_domain_t = detail::get_completion_domain_t; -template -inline constexpr get_completion_domain_t get_completion_domain{}; +template + requires ::std::same_as || ::beman::execution::detail::completion_tag +using get_completion_domain_t = ::beman::execution::detail::get_completion_domain_t; +template + requires ::std::same_as || ::beman::execution::detail::completion_tag +inline constexpr get_completion_domain_t get_completion_domain{}; } // namespace beman::execution // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/get_completion_scheduler.hpp b/include/beman/execution/detail/get_completion_scheduler.hpp index 3767aa3f..de5a67a3 100644 --- a/include/beman/execution/detail/get_completion_scheduler.hpp +++ b/include/beman/execution/detail/get_completion_scheduler.hpp @@ -35,7 +35,7 @@ template <::beman::execution::detail::completion_tag Tag> struct get_completion_scheduler_t; template -concept has_completion_scheduler = requires { +concept compl_sched_recurse_queryable = requires { { ::beman::execution::detail::recurse_query( ::std::declval().query( @@ -43,18 +43,19 @@ concept has_completion_scheduler = requires { ::std::declval()...), ::std::declval()...) } -> ::beman::execution::scheduler; -} || (::beman::execution::scheduler && sizeof...(E) > 0); +}; template <::beman::execution::detail::completion_tag Tag> struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { template - requires ::beman::execution::detail::has_completion_scheduler + requires ::beman::execution::detail::compl_sched_recurse_queryable || + (::beman::execution::scheduler && sizeof...(E) > 0) auto operator()(const Q& q, const E&... e) const noexcept; }; template auto recurse_query(Scheduler sch, const Envs&... envs) noexcept { - get_completion_scheduler_t<::beman::execution::set_value_t> get_compl_sch{}; + ::beman::execution::detail::get_completion_scheduler_t<::beman::execution::set_value_t> get_compl_sch{}; if constexpr (requires { ::std::as_const(sch).query(get_compl_sch, envs...); }) { auto sch2 = ::std::as_const(sch).query(get_compl_sch, envs...); if constexpr (::std::same_as) { @@ -72,9 +73,10 @@ auto recurse_query(Scheduler sch, const Envs&... envs) noexcept { template <::beman::execution::detail::completion_tag Tag> template - requires ::beman::execution::detail::has_completion_scheduler + requires ::beman::execution::detail::compl_sched_recurse_queryable || + (::beman::execution::scheduler && sizeof...(E) > 0) auto get_completion_scheduler_t::operator()(const Q& q, const E&... e) const noexcept { - if constexpr (requires { ::beman::execution::detail::recurse_query(q.query(*this, e...), e...); }) { + if constexpr (::beman::execution::detail::compl_sched_recurse_queryable) { return ::beman::execution::detail::recurse_query(q.query(*this, e...), e...); } else { static_assert(::beman::execution::scheduler && sizeof...(E) > 0); diff --git a/include/beman/execution/detail/get_domain.hpp b/include/beman/execution/detail/get_domain.hpp index 6c2322ff..d774a526 100644 --- a/include/beman/execution/detail/get_domain.hpp +++ b/include/beman/execution/detail/get_domain.hpp @@ -30,7 +30,7 @@ import beman.execution.detail.set_value; // ---------------------------------------------------------------------------- -namespace beman::execution { +namespace beman::execution::detail { struct get_domain_t : ::beman::execution::forwarding_query_t { template constexpr auto operator()(Env&& env) const noexcept { @@ -48,7 +48,10 @@ struct get_domain_t : ::beman::execution::forwarding_query_t { } } }; +} // namespace beman::execution::detail +namespace beman::execution { +using get_domain_t = ::beman::execution::detail::get_domain_t; inline constexpr get_domain_t get_domain{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/get_scheduler.hpp b/include/beman/execution/detail/get_scheduler.hpp index 59024cf3..a0dc5c50 100644 --- a/include/beman/execution/detail/get_scheduler.hpp +++ b/include/beman/execution/detail/get_scheduler.hpp @@ -14,34 +14,33 @@ import std; import beman.execution.detail.forwarding_query; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.hide_sched; -import beman.execution.detail.scheduler; import beman.execution.detail.set_value; #else #include #include #include -#include #include #endif // ---------------------------------------------------------------------------- -namespace beman::execution { +namespace beman::execution::detail { struct get_scheduler_t : ::beman::execution::forwarding_query_t { template requires requires(const get_scheduler_t& self, Env&& env) { ::std::as_const(env).query(self); - { - ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( - ::std::as_const(env).query(self), ::beman::execution::detail::hide_sched(env)) - } -> ::beman::execution::scheduler; + ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + ::std::as_const(env).query(self), ::beman::execution::detail::hide_sched(env)); } auto operator()(Env&& env) const noexcept { return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( ::std::as_const(env).query(*this), ::beman::execution::detail::hide_sched(env)); } }; +} // namespace beman::execution::detail +namespace beman::execution { +using get_scheduler_t = ::beman::execution::detail::get_scheduler_t; inline constexpr get_scheduler_t get_scheduler{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/hide_sched.hpp b/include/beman/execution/detail/hide_sched.hpp index 09a432ca..76f38110 100644 --- a/include/beman/execution/detail/hide_sched.hpp +++ b/include/beman/execution/detail/hide_sched.hpp @@ -19,12 +19,10 @@ import beman.execution.detail.queryable; // ---------------------------------------------------------------------------- -namespace beman::execution { +namespace beman::execution::detail { struct get_domain_t; struct get_scheduler_t; -} // namespace beman::execution -namespace beman::execution::detail { template <::beman::execution::detail::queryable Q> struct hide_sched_t { template @@ -34,10 +32,10 @@ struct hide_sched_t { } template - auto query(::beman::execution::get_domain_t, Args&&... args) const noexcept -> void = delete; + auto query(::beman::execution::detail::get_domain_t, Args&&... args) const noexcept -> void = delete; template - auto query(::beman::execution::get_scheduler_t, Args&&... args) const noexcept -> void = delete; + auto query(::beman::execution::detail::get_scheduler_t, Args&&... args) const noexcept -> void = delete; const Q& q; }; diff --git a/include/beman/execution/detail/intrusive_stack.hpp b/include/beman/execution/detail/intrusive_stack.hpp index 276a4d6f..cc258fb8 100644 --- a/include/beman/execution/detail/intrusive_stack.hpp +++ b/include/beman/execution/detail/intrusive_stack.hpp @@ -14,9 +14,6 @@ import std; namespace beman::execution::detail { -template -class atomic_intrusive_stack; - template class intrusive_stack; @@ -24,6 +21,10 @@ class intrusive_stack; template class intrusive_stack { public: + intrusive_stack() = default; + + explicit intrusive_stack(Item* head) noexcept : head_{head} {} + //! @brief Pushes an item to the queue. auto push(Item* item) noexcept -> void { item->*Next = std::exchange(head_, item); } @@ -43,7 +44,6 @@ class intrusive_stack { auto empty() const noexcept -> bool { return !head_; } private: - friend class atomic_intrusive_stack; Item* head_{nullptr}; }; diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index 76bae11c..aad4060c 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -47,19 +47,16 @@ struct transform_sndr_recurse { template auto operator()(Sndr&& sndr, const Env& env) { - decltype(auto) new_sndr = - ::beman::execution::detail::transformed_sndr(Domain(), Tag(), ::std::forward(sndr), env); + auto new_sndr = ::beman::execution::detail::transformed_sndr(Domain(), Tag(), ::std::forward(sndr), env); if constexpr (::std::same_as<::std::decay_t, ::std::decay_t>) { - return ::std::forward(new_sndr); + return ::std::move(new_sndr); } else { if constexpr (::std::same_as) { auto new_dom = ::beman::execution::get_domain(env); - return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}( - ::std::forward(new_sndr), env); + return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}(::std::move(new_sndr), env); } else { auto new_dom = ::beman::execution::detail::compl_domain(new_sndr, env); - return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}( - ::std::forward(new_sndr), env); + return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}(::std::move(new_sndr), env); } } } diff --git a/src/beman/execution/execution.cppm b/src/beman/execution/execution.cppm index d943705f..3ad8c982 100644 --- a/src/beman/execution/execution.cppm +++ b/src/beman/execution/execution.cppm @@ -28,11 +28,11 @@ export import beman.execution.detail.execution_policy; import beman.execution.detail.forwarding_query; import beman.execution.detail.get_allocator; import beman.execution.detail.get_await_completion_adaptor; +export import beman.execution.detail.get_completion_domain; export import beman.execution.detail.get_completion_scheduler; export import beman.execution.detail.get_completion_signatures; // [exec.getcomplsigs], completion signatures import beman.execution.detail.get_delegation_scheduler; import beman.execution.detail.get_domain; -import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_env; import beman.execution.detail.get_forward_progress_guarantee; import beman.execution.detail.get_scheduler; @@ -136,14 +136,12 @@ export using ::beman::execution::get_stop_token; export using ::beman::execution::stop_token_of_t; export using ::beman::execution::get_domain_t; -export using ::beman::execution::get_completion_domain_t; export using ::beman::execution::get_scheduler_t; export using ::beman::execution::get_delegation_scheduler_t; export using ::beman::execution::get_await_completion_adaptor_t; export using ::beman::execution::get_forward_progress_guarantee_t; export using ::beman::execution::get_domain; -export using ::beman::execution::get_completion_domain; export using ::beman::execution::get_scheduler; export using ::beman::execution::get_delegation_scheduler; export using ::beman::execution::get_await_completion_adaptor; From f46716dea73594c49cc412e44f7564be9f29fa2c Mon Sep 17 00:00:00 2001 From: Cra3z Date: Sat, 2 May 2026 21:25:49 +0800 Subject: [PATCH 14/16] Try fix GCC CI error --- include/beman/execution/detail/transform_sender.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index aad4060c..6efd4120 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -33,7 +33,7 @@ import beman.execution.detail.start; namespace beman::execution::detail { template -auto transformed_sndr(Domain dom, Tag tag, Sndr&& sndr, const Env& env) -> decltype(auto) { +auto transformed_sndr(Domain dom, Tag tag, Sndr&& sndr, const Env& env) { if constexpr (requires { dom.transform_sender(tag, ::std::forward(sndr), env); }) { return dom.transform_sender(tag, ::std::forward(sndr), env); } else { @@ -65,7 +65,7 @@ struct transform_sndr_recurse { namespace beman::execution { template <::beman::execution::sender Sndr, typename Env> -auto transform_sender(Sndr&& sndr, const Env& env) -> ::beman::execution::sender decltype(auto) { +auto transform_sender(Sndr&& sndr, const Env& env) -> ::beman::execution::sender auto { auto starting_domain = ::beman::execution::get_domain(env); auto completion_domain = ::beman::execution::detail::compl_domain(sndr, env); auto starting_transform = From d5813ea40ef5a626c1a4ca64dcff40609efb28f4 Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Mon, 4 May 2026 17:02:20 +0800 Subject: [PATCH 15/16] Format code --- Makefile | 2 +- include/beman/execution/detail/associate.hpp | 3 +-- include/beman/execution/detail/connect.hpp | 5 ++--- include/beman/execution/detail/continues_on.hpp | 6 +++--- .../beman/execution/detail/get_completion_signatures.hpp | 4 +--- include/beman/execution/detail/when_all.hpp | 4 +--- tests/beman/execution/exec-env.test.cpp | 6 ++---- 7 files changed, 11 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 18a3d08a..6bd96c88 100644 --- a/Makefile +++ b/Makefile @@ -149,7 +149,7 @@ dev-test: dev-build PATH=/opt/llvm-$(LLVM_VERSION)/bin:$$PATH CXX=clang++ ctest --test-dir $(DEV_DIR) -R beman.execution.$(TESTCASE).test dev: dev-test - + # $(SANITIZERS): # $(MAKE) SANITIZER=$@ diff --git a/include/beman/execution/detail/associate.hpp b/include/beman/execution/detail/associate.hpp index 5dada5ae..ac333c10 100644 --- a/include/beman/execution/detail/associate.hpp +++ b/include/beman/execution/detail/associate.hpp @@ -105,8 +105,7 @@ struct associate_t { template <::beman::execution::sender Sender, ::beman::execution::scope_token Token> auto operator()(Sender&& sender, Token token) const { return ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::associate_data(::std::move(token), ::std::forward(sender))); + *this, ::beman::execution::detail::associate_data(::std::move(token), ::std::forward(sender))); } template <::beman::execution::scope_token Token> diff --git a/include/beman/execution/detail/connect.hpp b/include/beman/execution/detail/connect.hpp index aab16bfb..f4642379 100644 --- a/include/beman/execution/detail/connect.hpp +++ b/include/beman/execution/detail/connect.hpp @@ -39,9 +39,8 @@ struct connect_t { static auto make_new_sender(Sender&& sender, Receiver&& receiver) //-dk:TODO this noexcept needs to get confirmed/fixed noexcept(true) -> decltype(auto) { - return ::beman::execution::transform_sender( - ::std::forward(sender), - ::beman::execution::get_env(receiver)); + return ::beman::execution::transform_sender(::std::forward(sender), + ::beman::execution::get_env(receiver)); } template static constexpr auto connect_noexcept() -> bool { diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index 294196ca..f57d665f 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -113,9 +113,9 @@ struct continues_on_t { template using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; using type = ::beman::execution::detail::meta::combine< - decltype(::beman::execution::get_completion_signatures()), - ::beman::execution::error_types_of_t, - ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; + decltype(::beman::execution::get_completion_signatures()), + ::beman::execution::error_types_of_t, + ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; }; public: diff --git a/include/beman/execution/detail/get_completion_signatures.hpp b/include/beman/execution/detail/get_completion_signatures.hpp index aceb6533..dcf513ce 100644 --- a/include/beman/execution/detail/get_completion_signatures.hpp +++ b/include/beman/execution/detail/get_completion_signatures.hpp @@ -49,9 +49,7 @@ struct get_completion_signatures_new_sender { template struct get_completion_signatures_new_sender { - using type = decltype(::beman::execution::transform_sender( - ::std::declval(), - ::std::declval())); + using type = decltype(::beman::execution::transform_sender(::std::declval(), ::std::declval())); }; template diff --git a/include/beman/execution/detail/when_all.hpp b/include/beman/execution/detail/when_all.hpp index 2dea4379..37564da5 100644 --- a/include/beman/execution/detail/when_all.hpp +++ b/include/beman/execution/detail/when_all.hpp @@ -178,9 +178,7 @@ struct when_all_t { struct impls_for : ::beman::execution::detail::default_impls { struct get_attrs_impl { - auto operator()(auto&&, auto&&...) const { - return ::beman::execution::env<>{}; - } + auto operator()(auto&&, auto&&...) const { return ::beman::execution::env<>{}; } }; static constexpr auto get_attrs{get_attrs_impl{}}; struct get_env_impl { diff --git a/tests/beman/execution/exec-env.test.cpp b/tests/beman/execution/exec-env.test.cpp index 487112d6..be11d331 100644 --- a/tests/beman/execution/exec-env.test.cpp +++ b/tests/beman/execution/exec-env.test.cpp @@ -22,8 +22,7 @@ struct extra_arg { }; struct multi_arg_query_t { - constexpr auto operator()(const auto& e) const noexcept(noexcept(e.query(*this))) - -> decltype(e.query(*this)) { + constexpr auto operator()(const auto& e) const noexcept(noexcept(e.query(*this))) -> decltype(e.query(*this)) { return e.query(*this); } constexpr auto operator()(const auto& e, extra_arg a) const noexcept(noexcept(e.query(*this, a))) @@ -59,8 +58,7 @@ TEST(env) { ASSERT(e3.query(multi_arg_query, extra_arg{99}) == 99); // Test env with prop that accepts extra args - test_std::env e4{test_std::prop(test_std::get_allocator, std::allocator{}), - multi_arg_env{}}; + test_std::env e4{test_std::prop(test_std::get_allocator, std::allocator{}), multi_arg_env{}}; ASSERT(e4.query(multi_arg_query) == 42); ASSERT(e4.query(multi_arg_query, extra_arg{7}) == 7); } From ee1fc8776355631bd9ffba838e7b6d5ded786581 Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Mon, 4 May 2026 18:00:05 +0800 Subject: [PATCH 16/16] Refactor `transform_sender` --- .../beman/execution/detail/basic_receiver.hpp | 9 +-- include/beman/execution/detail/bulk.hpp | 4 +- .../beman/execution/detail/compl_domain.hpp | 6 +- .../beman/execution/detail/default_domain.hpp | 6 +- .../execution/detail/transform_sender.hpp | 58 +++++++++++-------- src/beman/execution/compl_domain.cppm | 1 + .../execution/exec-domain-default.test.cpp | 4 +- 7 files changed, 50 insertions(+), 38 deletions(-) diff --git a/include/beman/execution/detail/basic_receiver.hpp b/include/beman/execution/detail/basic_receiver.hpp index da85dce8..b4427dff 100644 --- a/include/beman/execution/detail/basic_receiver.hpp +++ b/include/beman/execution/detail/basic_receiver.hpp @@ -72,7 +72,7 @@ template this->complete(Index(), this->op->state, this->op->receiver, - ::beman::execution::set_value_t(), + ::beman::execution::set_value, ::std::forward(args)...); } @@ -81,11 +81,8 @@ template requires ::beman::execution::detail:: callable { - this->complete(Index(), - this->op->state, - this->op->receiver, - ::beman::execution::set_error_t(), - ::std::forward(error)); + this->complete( + Index(), this->op->state, this->op->receiver, ::beman::execution::set_error, ::std::forward(error)); } auto set_stopped() && noexcept -> void diff --git a/include/beman/execution/detail/bulk.hpp b/include/beman/execution/detail/bulk.hpp index 9681d41f..b228941d 100644 --- a/include/beman/execution/detail/bulk.hpp +++ b/include/beman/execution/detail/bulk.hpp @@ -211,8 +211,8 @@ struct bulk_t : ::beman::execution::sender_adaptor_closure { ::std::forward(sndr)); } - template <::beman::execution::detail::sender_for Sender, typename... Env> - auto transform_sender(::beman::execution::set_value_t, Sender&& sndr, Env&&...) const { + template <::beman::execution::detail::sender_for Sender, typename Env> + auto transform_sender(::beman::execution::set_value_t, Sender&& sndr, const Env&) const { auto data = ::beman::execution::detail::forward_like(sndr.template get<1>()); auto child = ::beman::execution::detail::forward_like(sndr.template get<2>()); diff --git a/include/beman/execution/detail/compl_domain.hpp b/include/beman/execution/detail/compl_domain.hpp index 9029955c..e9ed7d2d 100644 --- a/include/beman/execution/detail/compl_domain.hpp +++ b/include/beman/execution/detail/compl_domain.hpp @@ -8,7 +8,7 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else -#include +#include #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.default_domain; @@ -33,6 +33,10 @@ constexpr auto compl_domain(const Sndr& sndr, const Envs&... envs) noexcept { return ::beman::execution::default_domain(); } } + +template +using compl_domain_of_t = + decltype(::beman::execution::detail::compl_domain(::std::declval(), ::std::declval()...)); } // namespace beman::execution::detail // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/default_domain.hpp b/include/beman/execution/detail/default_domain.hpp index d96cb06b..bd92b445 100644 --- a/include/beman/execution/detail/default_domain.hpp +++ b/include/beman/execution/detail/default_domain.hpp @@ -42,9 +42,9 @@ struct default_domain { Tag(), ::std::forward(sender), env...); }) static constexpr auto - transform_sender(Tag, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward(sender))) - -> ::beman::execution::sender decltype(auto) { - return ::std::forward(sender); + transform_sender(Tag, Sender&& sender, const Env&...) noexcept(::std::is_nothrow_constructible_v) + -> Sender { + return static_cast(sender); } template diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index 6efd4120..cd912c42 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -14,6 +14,7 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.compl_domain; +import beman.execution.detail.decayed_same_as; import beman.execution.detail.default_domain; import beman.execution.detail.get_domain; import beman.execution.detail.sender; @@ -21,6 +22,7 @@ import beman.execution.detail.set_value; import beman.execution.detail.start; #else #include +#include #include #include #include @@ -32,45 +34,53 @@ import beman.execution.detail.start; namespace beman::execution::detail { -template -auto transformed_sndr(Domain dom, Tag tag, Sndr&& sndr, const Env& env) { - if constexpr (requires { dom.transform_sender(tag, ::std::forward(sndr), env); }) { - return dom.transform_sender(tag, ::std::forward(sndr), env); - } else { - return ::beman::execution::default_domain().transform_sender(tag, ::std::forward(sndr), env); - } -} - template struct transform_sndr_recurse { + template + using domain_t = ::std::conditional_t().transform_sender( + ::std::declval(), ::std::declval(), ::std::declval()); + }, Domain, ::beman::execution::default_domain>; + + template + using new_sndr_t = + decltype(domain_t().transform_sender(Tag(), ::std::declval(), ::std::declval())); + constexpr transform_sndr_recurse(Domain, Tag) noexcept {} template - auto operator()(Sndr&& sndr, const Env& env) { - auto new_sndr = ::beman::execution::detail::transformed_sndr(Domain(), Tag(), ::std::forward(sndr), env); - if constexpr (::std::same_as<::std::decay_t, ::std::decay_t>) { - return ::std::move(new_sndr); - } else { + requires ::beman::execution::detail::decayed_same_as, Sndr> + auto operator()(Sndr&& sndr, const Env& env) const -> decltype(auto) { + return domain_t().transform_sender(Tag(), ::std::forward(sndr), env); + } + + template + auto operator()(Sndr&& sndr, const Env& env) const -> decltype(auto) { + auto next_domain = [&] { if constexpr (::std::same_as) { - auto new_dom = ::beman::execution::get_domain(env); - return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}(::std::move(new_sndr), env); + static_assert( + ::beman::execution::detail::decayed_same_as); + return ::beman::execution::get_domain(env); } else { - auto new_dom = ::beman::execution::detail::compl_domain(new_sndr, env); - return ::beman::execution::detail::transform_sndr_recurse{new_dom, Tag()}(::std::move(new_sndr), env); + using compl_domain_t = ::beman::execution::detail::compl_domain_of_t, Env>; + return compl_domain_t(); } - } + }(); + const auto next_transform = ::beman::execution::detail::transform_sndr_recurse{next_domain, Tag()}; + return next_transform(domain_t().transform_sender(Tag(), ::std::forward(sndr), env), env); } }; } // namespace beman::execution::detail namespace beman::execution { template <::beman::execution::sender Sndr, typename Env> -auto transform_sender(Sndr&& sndr, const Env& env) -> ::beman::execution::sender auto { - auto starting_domain = ::beman::execution::get_domain(env); - auto completion_domain = ::beman::execution::detail::compl_domain(sndr, env); - auto starting_transform = +auto transform_sender(Sndr&& sndr, const Env& env) -> ::beman::execution::sender decltype(auto) { + const auto starting_domain = ::beman::execution::get_domain(env); + const auto completion_domain = ::beman::execution::detail::compl_domain(sndr, env); + const auto starting_transform = ::beman::execution::detail::transform_sndr_recurse(starting_domain, ::beman::execution::start); - auto complete_transform = + const auto complete_transform = ::beman::execution::detail::transform_sndr_recurse(completion_domain, ::beman::execution::set_value); return starting_transform(complete_transform(::std::forward(sndr), env), env); } diff --git a/src/beman/execution/compl_domain.cppm b/src/beman/execution/compl_domain.cppm index 386e1da4..bd4dc9c1 100644 --- a/src/beman/execution/compl_domain.cppm +++ b/src/beman/execution/compl_domain.cppm @@ -8,4 +8,5 @@ export module beman.execution.detail.compl_domain; namespace beman::execution::detail { export using beman::execution::detail::compl_domain; +export using beman::execution::detail::compl_domain_of_t; } // namespace beman::execution::detail diff --git a/tests/beman/execution/exec-domain-default.test.cpp b/tests/beman/execution/exec-domain-default.test.cpp index a8bc9abf..f6260268 100644 --- a/tests/beman/execution/exec-domain-default.test.cpp +++ b/tests/beman/execution/exec-domain-default.test.cpp @@ -75,9 +75,9 @@ auto test_transform_sender(Domain) { static_assert(noexcept(Domain::transform_sender(simple_tag{}, simple_sender{}))); static_assert(noexcept(Domain::transform_sender(simple_tag{}, simple_sender{}, env{}))); using simple_rvalue_type = decltype(Domain::transform_sender(simple_tag{}, simple_sender{})); - static_assert(std::same_as); + static_assert(std::same_as); using simple_env_rvalue_type = decltype(Domain::transform_sender(simple_tag{}, simple_sender{}, env{})); - static_assert(std::same_as); + static_assert(std::same_as); simple_sender sender; using simple_lvalue_type = decltype(Domain::transform_sender(simple_tag{}, sender)); static_assert(std::same_as);