From 8f1dfdcbc97fedbf0f1371c34706b41f53cdc6ce Mon Sep 17 00:00:00 2001 From: Hackathon User Date: Sun, 3 May 2026 20:22:52 +0530 Subject: [PATCH] Implement P2300 stopped_as_optional sender adapter - Added stopped_as_optional to transform stopped signals into value(nullopt) - Implemented sender, receiver, and operation state for the transformation - Provided support for piping syntax via partial_algorithm - Forwarded environment and completion scheduler from predecessor - Added comprehensive unit tests for value, error, and stopped paths --- .../algorithms/stopped_as_optional.hpp | 235 ++++++++++++++++++ libs/core/execution/tests/unit/CMakeLists.txt | 1 + .../unit/algorithm_stopped_as_optional.cpp | 93 +++++++ 3 files changed, 329 insertions(+) create mode 100644 libs/core/execution/include/hpx/execution/algorithms/stopped_as_optional.hpp create mode 100644 libs/core/execution/tests/unit/algorithm_stopped_as_optional.cpp diff --git a/libs/core/execution/include/hpx/execution/algorithms/stopped_as_optional.hpp b/libs/core/execution/include/hpx/execution/algorithms/stopped_as_optional.hpp new file mode 100644 index 000000000000..f9a408aa9935 --- /dev/null +++ b/libs/core/execution/include/hpx/execution/algorithms/stopped_as_optional.hpp @@ -0,0 +1,235 @@ +// Copyright (c) 2021 ETH Zurich +// Copyright (c) 2022-2025 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#include +#if defined(HPX_HAVE_STDEXEC) +#include +#else + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace hpx::execution::experimental { + + namespace detail { + + // Maps set_value(Ts...) -> set_value(optional>) + // set_stopped() -> set_value(nullopt) + // set_error(E) -> set_error(E) + HPX_CXX_CORE_EXPORT template + struct stopped_as_optional_receiver + { + HPX_NO_UNIQUE_ADDRESS std::decay_t receiver; + + template + friend void tag_invoke(set_error_t, + stopped_as_optional_receiver&& r, Error&& error) noexcept + { + hpx::execution::experimental::set_error( + HPX_MOVE(r.receiver), HPX_FORWARD(Error, error)); + } + + friend void tag_invoke( + set_stopped_t, stopped_as_optional_receiver&& r) noexcept + { + hpx::execution::experimental::set_value( + HPX_MOVE(r.receiver), std::optional(std::nullopt)); + } + + friend void tag_invoke(set_value_t, + stopped_as_optional_receiver&& r, T&& value) noexcept + { + hpx::detail::try_catch_exception_ptr( + [&]() { + hpx::execution::experimental::set_value( + HPX_MOVE(r.receiver), + std::optional(HPX_MOVE(value))); + }, + [&](std::exception_ptr ep) { + hpx::execution::experimental::set_error( + HPX_MOVE(r.receiver), HPX_MOVE(ep)); + }); + } + + friend void tag_invoke(set_value_t, + stopped_as_optional_receiver&& r, T const& value) noexcept + { + hpx::detail::try_catch_exception_ptr( + [&]() { + hpx::execution::experimental::set_value( + HPX_MOVE(r.receiver), std::optional(value)); + }, + [&](std::exception_ptr ep) { + hpx::execution::experimental::set_error( + HPX_MOVE(r.receiver), HPX_MOVE(ep)); + }); + } + + friend auto tag_invoke( + get_env_t, stopped_as_optional_receiver const& r) noexcept + -> decltype(hpx::execution::experimental::get_env(r.receiver)) + { + return hpx::execution::experimental::get_env(r.receiver); + } + }; + + // Extracts the single value type T from a sender's value_types. + // stopped_as_optional requires exactly one value set (a single T). + template + struct stopped_as_optional_value + { + template + struct pack + { + }; + + // single-value case: set_value(T) -> optional + template + static T extract(pack>); + + using type = + decltype(extract(value_types_of_t{})); + }; + + template + using stopped_as_optional_value_t = + typename stopped_as_optional_value::type; + + HPX_CXX_CORE_EXPORT template + struct stopped_as_optional_sender + { + using is_sender = void; + HPX_NO_UNIQUE_ADDRESS std::decay_t sender; + + template + struct generate_completion_signatures + { + using value_type = stopped_as_optional_value_t; + + template