-
Notifications
You must be signed in to change notification settings - Fork 24
within algorithm from P3955
#288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1225cda
255cea4
6ad4a34
4125dba
6d30be6
297c5af
20ad718
c2ff435
ff3b5fc
ea6c641
55a2484
24bc7c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| // include/beman/execution/detail/completion_storage.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_STORAGE | ||
| #define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_STORAGE | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #include <beman/execution/detail/suppress_push.hpp> | ||
| #ifdef BEMAN_HAS_IMPORT_STD | ||
| import std; | ||
| #else | ||
| #include <exception> | ||
| #include <tuple> | ||
| #include <type_traits> | ||
| #include <variant> | ||
| #endif | ||
| #ifdef BEMAN_HAS_MODULES | ||
| import beman.execution.detail.completion_signatures; | ||
| import beman.execution.detail.receiver_of; | ||
| import beman.execution.detail.receiver; | ||
| import beman.execution.detail.set_error; | ||
| import beman.execution.detail.unreachable; | ||
| #else | ||
| #include <beman/execution/detail/completion_signatures.hpp> | ||
| #include <beman/execution/detail/receiver_of.hpp> | ||
| #include <beman/execution/detail/receiver.hpp> | ||
| #include <beman/execution/detail/set_error.hpp> | ||
| #include <beman/execution/detail/unreachable.hpp> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution::detail { | ||
|
|
||
| /// For a signature `Sig` of the form `Tag(Args...)`, compute the corresponding tuple type that can store the | ||
| /// completion. | ||
| template <typename Sig> | ||
| struct tuple_for_signature; | ||
|
|
||
| template <typename Tag, typename... Args> | ||
| struct tuple_for_signature<Tag(Args...)> { | ||
| /// The tuple type corresponding to the signature `Tag(Args...)`. | ||
| using type = ::std::tuple<Tag, ::std::remove_cvref_t<Args>...>; | ||
|
|
||
| /// Helper function to be used in overloaded scenario to select the correct tuple type from a set of arguments. | ||
| static auto select_tuple(Tag t, Args&&... args) -> type; | ||
| }; | ||
|
|
||
| /// The variant storage for a set of completion signatures. | ||
| template <typename Signatures> | ||
| struct variant_for_signatures; | ||
|
|
||
| template <typename... Sigs> | ||
| struct variant_for_signatures<::beman::execution::completion_signatures<Sigs...>> | ||
| : ::beman::execution::detail::tuple_for_signature<Sigs>... { | ||
| /// The type of the variant that can store any of the completions in `Sigs...`. | ||
| using type = | ||
| ::std::variant<std::monostate, typename ::beman::execution::detail::tuple_for_signature<Sigs>::type...>; | ||
|
|
||
| /// Stores in `storage` the completion with tag `t` and arguments `args...`. | ||
| /// | ||
| /// If the construction of the tuple throws, it will store a `set_error` completion with the current exception. | ||
| template <typename Tag, typename... Args> | ||
| static auto store_into_variant(type& storage, Tag t, Args&&... args) noexcept { | ||
| using tuple_type = decltype(select_tuple(t, ::std::forward<Args>(args)...)); | ||
| if constexpr (std::is_nothrow_constructible_v<tuple_type, Tag, Args&&...>) { | ||
| storage.template emplace<tuple_type>(t, ::std::forward<Args>(args)...); | ||
| } else { | ||
| try { | ||
| storage.template emplace<tuple_type>(t, ::std::forward<Args>(args)...); | ||
| } catch (...) { | ||
| store_into_variant(storage, ::beman::execution::set_error_t{}, ::std::current_exception()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Completes `receiver` with the completion stored in `storage`. | ||
| /// | ||
| /// The completion receives a copy of the stored tuple, in case the completion destroys the storage. | ||
| template <::beman::execution::receiver Receiver> | ||
| static void complete_from_variant(type&& storage, Receiver&& receiver) noexcept { | ||
| std::visit( | ||
| [&](auto&& tuple_data) { | ||
| using tuple_type = ::std::remove_cvref_t<decltype(tuple_data)>; | ||
| if constexpr (std::is_same_v<tuple_type, std::monostate>) { | ||
| ::beman::execution::detail::unreachable(); | ||
| } else { | ||
| ::std::apply( | ||
| [&](const auto tag, auto&&... args) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this function wants to be |
||
| tag(::std::forward<Receiver>(receiver), ::std::forward<decltype(args)>(args)...); | ||
| }, | ||
| // Make a copy, in case the tuple is destroyed by the completion call. | ||
| tuple_type{::std::move(tuple_data)}); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... and this move construction may possible throw in which case the exception should probably be caught and turned into a |
||
| } | ||
| }, | ||
| ::std::move(storage)); | ||
| } | ||
|
|
||
| /// Helper to create an overload set to be able to select the right tuple from a set of arguments. | ||
| using ::beman::execution::detail::tuple_for_signature<Sigs>::select_tuple...; | ||
| }; | ||
|
|
||
| /// Storage for a set of completions. | ||
| template <typename Signatures> | ||
| struct completion_storage { | ||
| completion_storage() noexcept = default; | ||
|
|
||
| /// Stores the completion with tag `t` and arguments `args...`. | ||
| template <typename Tag, typename... Args> | ||
| void store(Tag t, Args&&... args) noexcept { | ||
| variant_impl::store_into_variant(storage, t, ::std::forward<Args>(args)...); | ||
| } | ||
|
|
||
| /// Completes `receiver` with the completion stored in this storage. | ||
| template <::beman::execution::receiver_of<Signatures> Receiver> | ||
| void complete(Receiver&& receiver) && noexcept { | ||
| variant_impl::complete_from_variant(::std::move(storage), ::std::forward<Receiver>(receiver)); | ||
| } | ||
|
|
||
| private: | ||
| using variant_impl = ::beman::execution::detail::variant_for_signatures<Signatures>; | ||
| typename variant_impl::type storage; | ||
| }; | ||
|
|
||
| } // namespace beman::execution::detail | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_STORAGE | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| // include/beman/execution/detail/elide.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ELIDE | ||
| #define INCLUDED_BEMAN_EXECUTION_DETAIL_ELIDE | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #include <beman/execution/detail/suppress_push.hpp> | ||
| #ifdef BEMAN_HAS_IMPORT_STD | ||
| import std; | ||
| #else | ||
| #include <functional> | ||
| #include <type_traits> | ||
| #include <utility> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution::detail { | ||
|
|
||
| /// Helper to elide move construction of a value when it is only used once. | ||
| /// | ||
| /// Uses a small lambda and conversion operator to elide the move construction. | ||
| template <std::invocable F> | ||
| struct elide { | ||
| /// The resulting type of the elision. | ||
| using result_t = std::invoke_result_t<F>; | ||
|
|
||
| /// Constructs the elision wrapper from callable `f`. | ||
| elide(F&& f) noexcept : f_(::std::forward<F>(f)) {} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the ctor be conditionally |
||
|
|
||
| /// Evaluates the callable given at construction and returns the result, eliding the move construction of the | ||
| /// result. | ||
| operator result_t() && noexcept(::std::is_nothrow_invocable_v<F>) { return ::std::invoke(::std::forward<F>(f_)); } | ||
|
|
||
| private: | ||
| /// The callable to evaluate when the elision is converted to the result type. | ||
| F f_; | ||
| }; | ||
|
|
||
| } // namespace beman::execution::detail | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif // INCLUDED_BEMAN_EXECUTION_DETAIL_ELIDE | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // include/beman/execution/detail/enter_scope_sender.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ENTER_SCOPE_SENDER | ||
| #define INCLUDED_BEMAN_EXECUTION_DETAIL_ENTER_SCOPE_SENDER | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #ifdef BEMAN_HAS_IMPORT_STD | ||
| import std; | ||
| #else | ||
| #include <concepts> | ||
| #include <type_traits> | ||
| #endif | ||
| #ifdef BEMAN_HAS_MODULES | ||
| import beman.execution.detail.sender; | ||
| #else | ||
| #include <beman/execution/detail/sender.hpp> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution { | ||
| template <typename Sender> | ||
| /*! | ||
| * \brief Sender corresponding to the action of entering a scope. | ||
| * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp> | ||
| */ | ||
| concept enter_scope_sender = ::beman::execution::sender<Sender>; | ||
| } // namespace beman::execution | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // include/beman/execution/detail/enter_scope_sender_in.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_ENTER_SCOPE_SENDER_IN | ||
| #define INCLUDED_BEMAN_EXECUTION_DETAIL_ENTER_SCOPE_SENDER_IN | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #ifdef BEMAN_HAS_MODULES | ||
| import beman.execution.detail.enter_scope_sender; | ||
| import beman.execution.detail.exit_scope_sender_of_t; | ||
| import beman.execution.detail.sender_in; | ||
| #else | ||
| #include <beman/execution/detail/enter_scope_sender.hpp> | ||
| #include <beman/execution/detail/exit_scope_sender_of_t.hpp> | ||
| #include <beman/execution/detail/sender_in.hpp> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution { | ||
| template <typename Sender, typename... Env> | ||
| /*! | ||
| * \brief An enter scope sender that can operate in the environment `Env...`. | ||
| * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp> | ||
| * | ||
| * \details | ||
| * Requirements: | ||
| * - `Sender` models `enter_scope_sender`. | ||
| * - `Sender` models `sender_in<Env...>`. | ||
| * - The completion signatures contains exactly one value completion signature, that completion | ||
| * signature is unary, and the type of the value models `exit_sender_in<Env...>`. | ||
| * - Semantic: The above exit sender undoes the action of the enter scope sender which sent it. | ||
| */ | ||
| concept enter_scope_sender_in = | ||
| ::beman::execution::enter_scope_sender<Sender> && ::beman::execution::sender_in<Sender, Env...> && | ||
| requires { typename ::beman::execution::exit_scope_sender_of_t<Sender, Env...>; }; | ||
| } // namespace beman::execution | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| // include/beman/execution/detail/exit_scope_sender.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_EXIT_SCOPE_SENDER | ||
| #define INCLUDED_BEMAN_EXECUTION_DETAIL_EXIT_SCOPE_SENDER | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #ifdef BEMAN_HAS_IMPORT_STD | ||
| import std; | ||
| #else | ||
| #include <concepts> | ||
| #include <type_traits> | ||
| #endif | ||
| #ifdef BEMAN_HAS_MODULES | ||
| import beman.execution.detail.sender; | ||
| #else | ||
| #include <beman/execution/detail/sender.hpp> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution { | ||
| /*! | ||
| * \brief A sender that does not throw when decay-copied or moved. | ||
| * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp> | ||
| */ | ||
| template <typename Sender> | ||
| concept exit_scope_sender = | ||
| ::beman::execution::sender<Sender> && std::is_nothrow_constructible_v<::std::remove_cvref_t<Sender>, Sender> && | ||
| std::is_nothrow_move_constructible_v<::std::remove_cvref_t<Sender>>; | ||
| } // namespace beman::execution | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| // include/beman/execution/detail/exit_scope_sender_in.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_EXIT_SCOPE_SENDER_IN | ||
| #define INCLUDED_BEMAN_EXECUTION_DETAIL_EXIT_SCOPE_SENDER_IN | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #ifdef BEMAN_HAS_IMPORT_STD | ||
| import std; | ||
| #else | ||
| #include <concepts> | ||
| #include <type_traits> | ||
| #endif | ||
| #ifdef BEMAN_HAS_MODULES | ||
| import beman.execution.detail.completion_signatures_of_t; | ||
| import beman.execution.detail.completion_signatures; | ||
| import beman.execution.detail.connect; | ||
| import beman.execution.detail.env; | ||
| import beman.execution.detail.exit_scope_sender; | ||
| import beman.execution.detail.nothrow_callable; | ||
| import beman.execution.detail.receiver; | ||
| import beman.execution.detail.sender_in; | ||
| import beman.execution.detail.set_value; | ||
| import beman.execution.detail.unreachable; | ||
| #else | ||
| #include <beman/execution/detail/completion_signatures_of_t.hpp> | ||
| #include <beman/execution/detail/completion_signatures.hpp> | ||
| #include <beman/execution/detail/connect.hpp> | ||
| #include <beman/execution/detail/env.hpp> | ||
| #include <beman/execution/detail/exit_scope_sender.hpp> | ||
| #include <beman/execution/detail/nothrow_callable.hpp> | ||
| #include <beman/execution/detail/receiver.hpp> | ||
| #include <beman/execution/detail/sender_in.hpp> | ||
| #include <beman/execution/detail/set_value.hpp> | ||
| #include <beman/execution/detail/unreachable.hpp> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution::detail { | ||
|
|
||
| /// A receiver with environment `Env` that accepts every possible completion. | ||
| template <typename Env = ::beman::execution::env<>> | ||
| struct generic_receiver { | ||
| using receiver_concept = ::beman::execution::receiver_tag; | ||
|
|
||
| template <typename... T> | ||
| void set_value(T&&...) && noexcept {} | ||
| template <typename E> | ||
| void set_error(E&&) && noexcept {} | ||
| void set_stopped() && noexcept {} | ||
|
|
||
| auto get_env() const noexcept -> Env { ::beman::execution::detail::unreachable(); } | ||
| }; | ||
|
Comment on lines
+42
to
+54
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this tool really specific to the |
||
|
|
||
| /// A sender that doesn't throw when connected to a receiver. | ||
| template <typename Sender, typename... Env> | ||
| concept nothrow_connectable = | ||
| ::beman::execution::detail::nothrow_callable<::beman::execution::connect_t, Sender, generic_receiver<Env...>>; | ||
|
|
||
| } // namespace beman::execution::detail | ||
|
Comment on lines
+57
to
+61
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise |
||
|
|
||
| namespace beman::execution { | ||
| /*! | ||
| * \brief An exit scope sender that can operate in the environment `Env...`. | ||
| * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp> | ||
| * | ||
| * \details | ||
| * Requirements: | ||
| * - `Sender` models `exit_scope_sender`. | ||
| * - `Sender` models `sender_in<Env...>`. | ||
| * - `Sender` is nothrow connectable to any receiver with environment `Env...`. | ||
| * - The completion signatures of `Sender` in `Env...` is exactly `completion_signatures<set_value_t()>`. | ||
| */ | ||
| template <typename Sender, typename... Env> | ||
| concept exit_scope_sender_in = | ||
| ::beman::execution::exit_scope_sender<Sender> && ::beman::execution::sender_in<Sender, Env...> && | ||
| ::beman::execution::detail::nothrow_connectable<Sender, Env...> && | ||
| std::is_same_v<::beman::execution::completion_signatures_of_t<Sender, Env...>, | ||
| ::beman::execution::completion_signatures<::beman::execution::set_value_t()>>; | ||
| } // namespace beman::execution | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "normal" pattern is to always use a
try/catchblock but execute the error work conditionally, thereby avoiding to duplicate the actual business logic (often thenothrowcondition is stored into aconstexprvariable):