diff --git a/.vscode/launch.json b/.vscode/launch.json index 8316045fe..f4d90ab0d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -85,6 +85,17 @@ "environment": [{"CUDA_LAUNCH_BLOCKING": "1"}], "args": ["--iterations=1000", "--N=512", "--run-stream-scheduler"], }, + { + "name": "(Windows) Launch", + "type": "cppvsdbg", + "request": "launch", + "program": "${command:cmake.launchTargetPath}", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "console": "externalTerminal" + }, ], "inputs": [ // These require the Tasks Shell Input extension: diff --git a/include/exec/detail/basic_sequence.hpp b/include/exec/detail/basic_sequence.hpp index 2c4a92b38..0357b7a0c 100644 --- a/include/exec/detail/basic_sequence.hpp +++ b/include/exec/detail/basic_sequence.hpp @@ -127,6 +127,6 @@ namespace STDEXEC::__detail extern decltype(_DescriptorFn()) __desc_of_v>; template - extern __declfn_t<__minvoke>> + extern __mtype<__minvoke>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/exec/repeat_until.hpp b/include/exec/repeat_until.hpp index c44b36645..146750da1 100644 --- a/include/exec/repeat_until.hpp +++ b/include/exec/repeat_until.hpp @@ -275,11 +275,11 @@ namespace experimental::execution using __eptr_completion_t = set_error_t(std::exception_ptr); constexpr auto __eptr_completion = (__eptr_completion_t *) nullptr; - STDEXEC_COMPLSIGS_LET( - __sigs, + auto __sigs = exec::transform_completion_signatures(get_completion_signatures<__child_t, _Env...>(), __transform_values<__child_t>, - __transform_errors)) + __transform_errors); + STDEXEC_IF_OK(__sigs) { // The repeat_until sender is a dependent sender if one of the following is // true: diff --git a/include/exec/static_thread_pool.hpp b/include/exec/static_thread_pool.hpp index 582f91b12..6673cc619 100644 --- a/include/exec/static_thread_pool.hpp +++ b/include/exec/static_thread_pool.hpp @@ -45,7 +45,6 @@ #include "sequence/iterate.hpp" #include "sequence_senders.hpp" -#include #include #include #include diff --git a/include/nvexec/nvtx.cuh b/include/nvexec/nvtx.cuh index 0c5bd4de2..d0be24e8b 100644 --- a/include/nvexec/nvtx.cuh +++ b/include/nvexec/nvtx.cuh @@ -196,7 +196,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t>> + extern __mtype>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/algorithm_base.cuh b/include/nvexec/stream/algorithm_base.cuh index c5b6a54ab..8832c1a84 100644 --- a/include/nvexec/stream/algorithm_base.cuh +++ b/include/nvexec/stream/algorithm_base.cuh @@ -145,7 +145,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t, InitT, Fun, __demangle_t>> + extern __mtype, InitT, Fun, __demangle_t>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/bulk.cuh b/include/nvexec/stream/bulk.cuh index e8b277ab2..a3a2a6ab8 100644 --- a/include/nvexec/stream/bulk.cuh +++ b/include/nvexec/stream/bulk.cuh @@ -440,12 +440,11 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - inline constexpr __declfn_t, Shape, Fun>> + inline constexpr __mtype, Shape, Fun>> __demangle_v>{}; template - inline constexpr __declfn_t< - nvexec::_strm::multi_gpu_bulk_sender<__demangle_t, Shape, Fun>> + inline constexpr __mtype, Shape, Fun>> __demangle_v>{}; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/continues_on.cuh b/include/nvexec/stream/continues_on.cuh index a7ee8f260..b06697755 100644 --- a/include/nvexec/stream/continues_on.cuh +++ b/include/nvexec/stream/continues_on.cuh @@ -284,7 +284,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t>> + extern __mtype>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/ensure_started.cuh b/include/nvexec/stream/ensure_started.cuh index 324842cd2..30ae50ab4 100644 --- a/include/nvexec/stream/ensure_started.cuh +++ b/include/nvexec/stream/ensure_started.cuh @@ -430,7 +430,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t>> + extern __mtype>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/launch.cuh b/include/nvexec/stream/launch.cuh index 35b29e785..de3f79f1d 100644 --- a/include/nvexec/stream/launch.cuh +++ b/include/nvexec/stream/launch.cuh @@ -204,7 +204,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t, Fun>> + extern __mtype, Fun>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/let_xxx.cuh b/include/nvexec/stream/let_xxx.cuh index 4d7e3b940..0ed840cb5 100644 --- a/include/nvexec/stream/let_xxx.cuh +++ b/include/nvexec/stream/let_xxx.cuh @@ -344,7 +344,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t, Fun, SetTag>> + extern __mtype, Fun, SetTag>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/reduce.cuh b/include/nvexec/stream/reduce.cuh index 90a5c3780..b1ec38b56 100644 --- a/include/nvexec/stream/reduce.cuh +++ b/include/nvexec/stream/reduce.cuh @@ -165,7 +165,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t, Init, Fun>> + extern __mtype, Init, Fun>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/schedule_from.cuh b/include/nvexec/stream/schedule_from.cuh index cb979c650..8f7edee11 100644 --- a/include/nvexec/stream/schedule_from.cuh +++ b/include/nvexec/stream/schedule_from.cuh @@ -196,6 +196,6 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t>> + extern __mtype>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/split.cuh b/include/nvexec/stream/split.cuh index 7488cbb39..d461e3ff1 100644 --- a/include/nvexec/stream/split.cuh +++ b/include/nvexec/stream/split.cuh @@ -412,7 +412,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t>> + extern __mtype>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/then.cuh b/include/nvexec/stream/then.cuh index 9d8f0171c..44e3a53b7 100644 --- a/include/nvexec/stream/then.cuh +++ b/include/nvexec/stream/then.cuh @@ -228,7 +228,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t, Fun>> + extern __mtype, Fun>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/upon_error.cuh b/include/nvexec/stream/upon_error.cuh index 4f0904f1a..38350b9ff 100644 --- a/include/nvexec/stream/upon_error.cuh +++ b/include/nvexec/stream/upon_error.cuh @@ -216,7 +216,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t, Fun>> + extern __mtype, Fun>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/upon_stopped.cuh b/include/nvexec/stream/upon_stopped.cuh index f18e4a120..cb7668c59 100644 --- a/include/nvexec/stream/upon_stopped.cuh +++ b/include/nvexec/stream/upon_stopped.cuh @@ -207,7 +207,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t, Fun>> + extern __mtype, Fun>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/when_all.cuh b/include/nvexec/stream/when_all.cuh index a367a9653..efa005e18 100644 --- a/include/nvexec/stream/when_all.cuh +++ b/include/nvexec/stream/when_all.cuh @@ -576,7 +576,7 @@ namespace nvexec = nv::execution; namespace STDEXEC::__detail { template - extern __declfn_t...>> + extern __mtype...>> __demangle_v>; } // namespace STDEXEC::__detail diff --git a/include/stdexec/__detail/__basic_sender.hpp b/include/stdexec/__detail/__basic_sender.hpp index 1f987463a..44fdf8a6b 100644 --- a/include/stdexec/__detail/__basic_sender.hpp +++ b/include/stdexec/__detail/__basic_sender.hpp @@ -456,7 +456,7 @@ namespace STDEXEC using __basic_sender_t = __basic_sender<_Tag, _Data, __demangle_t<_Child>...>::type; template - extern __declfn_t<__minvoke>> + extern __mtype<__minvoke>> __demangle_v<__sexpr<_Descriptor>>; } // namespace __detail } // namespace STDEXEC diff --git a/include/stdexec/__detail/__completion_info.hpp b/include/stdexec/__detail/__completion_info.hpp new file mode 100644 index 000000000..0512af80b --- /dev/null +++ b/include/stdexec/__detail/__completion_info.hpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2026 NVIDIA Corporation + * + * Licensed under the Apache License Version 2.0 with LLVM Exceptions + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://llvm.org/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "__execution_fwd.hpp" + +// IWYU pragma: begin_keep +#include "__completion_behavior.hpp" +#include "__completion_signatures.hpp" +#include "__meta.hpp" +#include "__static_vector.hpp" +#include "__typeinfo.hpp" + +#include "../functional.hpp" + +#include +#include +#include +// IWYU pragma: end_keep + +namespace STDEXEC +{ + template + constexpr _Sig *__signature = nullptr; + + struct __completion_info + { + using __behavior_t = __completion_behavior::__behavior; + + STDEXEC::__disposition __disposition = __invalid_disposition; + __type_index __signature = __mtypeid; + __type_index __domain = __mtypeid; + __behavior_t __behavior = __completion_behavior::__unknown; + + __completion_info() = default; + + template <__completion_tag _Tag, class... _Args> + constexpr __completion_info(_Tag (*)(_Args...), + __type_index __domain = __mtypeid, + __behavior_t __behavior = __completion_behavior::__unknown) noexcept + : __disposition(_Tag::__disposition) + , __signature(__mtypeid<_Tag(_Args...)>) + , __domain(__domain) + , __behavior(__behavior) + {} + + template + constexpr auto __populate() noexcept -> __completion_info & + { + switch (__disposition) + { + case __disposition::__value: + __domain = __mtypeid<__completion_domain_t, _Env...>>; + __behavior = STDEXEC::__get_completion_behavior(); + break; + case __disposition::__error: + __domain = __mtypeid<__completion_domain_t, _Env...>>; + __behavior = STDEXEC::__get_completion_behavior(); + break; + case __disposition::__stopped: + __domain = __mtypeid<__completion_domain_t, _Env...>>; + __behavior = STDEXEC::__get_completion_behavior(); + break; + } + return *this; + } + + [[nodiscard]] + constexpr auto operator<=>(__completion_info const &) const noexcept // + -> std::strong_ordering = default; + }; + + namespace __cmplsigs + { + template + constexpr auto __completion_info_from_v = []() noexcept + { + auto __cmpl_info = _GetComplInfo(); + STDEXEC_IF_OK(__cmpl_info) + { + constexpr auto __size = _GetComplInfo().size(); + auto __arr = __static_vector<__completion_info, __size>(); + std::ranges::sort(__cmpl_info); + auto const __end = std::ranges::unique_copy(__cmpl_info, __arr.begin()).out; + __arr.resize(__end - __arr.begin()); + return __arr; + } + }(); + + template + consteval auto __completion_info_from(_GetComplInfo) noexcept -> auto const & + { + return __completion_info_from_v<(_GetComplInfo())>; + } + + template + constexpr auto __completion_sigs_from_v = []() noexcept + { + constexpr auto __completions = __completion_info_from_v<_GetComplInfo>; + STDEXEC_IF_OK(__completions) + { + auto __signatures = __static_vector<__type_index, __completions.size()>(); + __signatures.resize(__completions.size()); + std::ranges::transform(__completions, + __signatures.begin(), + &__completion_info::__signature); + std::ranges::sort(__signatures); + auto const __end = std::ranges::unique(__signatures).begin(); + __signatures.erase(__end, __signatures.end()); + return __signatures; + } + }(); + + template + consteval auto __completion_sigs_from(_GetComplInfo) noexcept + { + constexpr auto __sigs = __completion_sigs_from_v<(_GetComplInfo())>; + STDEXEC_IF_OK(__sigs) + { + constexpr auto __fn = [=](__indices<_Is...>) + { + return completion_signatures<__msplice<__sigs[_Is]>...>(); + }; + return __fn(__make_indices<__sigs.size()>()); + } + } + + template + [[nodiscard]] + consteval auto __to_array(completion_signatures<_Sigs...>) noexcept + { + using __array_t = __static_vector<__completion_info, sizeof...(_Sigs)>; + auto __compls = __array_t{__completion_info(__signature<_Sigs>)...}; + std::ranges::sort(__compls); + return __compls; + } + } // namespace __cmplsigs +} // namespace STDEXEC diff --git a/include/stdexec/__detail/__completion_signatures.hpp b/include/stdexec/__detail/__completion_signatures.hpp index 2d6fd54b9..1a864218f 100644 --- a/include/stdexec/__detail/__completion_signatures.hpp +++ b/include/stdexec/__detail/__completion_signatures.hpp @@ -541,38 +541,15 @@ namespace STDEXEC __cmplsigs::__partitions_of_t<_Sigs>::__count_stopped::value; } // namespace __detail - // Below is the definition of the STDEXEC_COMPLSIGS_LET portability macro. It - // is used to check that an expression's type is a valid completion_signature - // specialization. - // - // USAGE: - // - // STDEXEC_COMPLSIGS_LET(__cs, ) - // { - // // __cs is guaranteed to be a specialization of completion_signatures. - // } - // - // When constexpr exceptions are available (C++26), the macro simply expands to - // the moral equivalent of: - // - // // With constexpr exceptions: - // auto __cs = ; // throws if __cs is not a completion_signatures - // - // When constexpr exceptions are not available, the macro expands to: - // - // // Without constexpr exceptions: - // if constexpr (auto __cs = ; !__valid_completion_signatures) - // { - // return __cs; - // } - // else + // Below is the definition of the STDEXEC_IF_OK portability macro. It is used to check + // that an expression's type is not an __mexception type. #if STDEXEC_NO_STDCPP_CONSTEXPR_EXCEPTIONS() -# define STDEXEC_COMPLSIGS_LET(_ID, ...) \ - if constexpr ([[maybe_unused]] auto _ID = __VA_ARGS__; \ - !STDEXEC::__valid_completion_signatures) { \ - return _ID; \ +# define STDEXEC_IF_OK(_ID) \ + if constexpr (STDEXEC::__merror) \ + { \ + return _ID; \ } else template @@ -591,9 +568,7 @@ namespace STDEXEC #else // ^^^ no constexpr exceptions ^^^ / vvv constexpr exceptions vvv -# define STDEXEC_COMPLSIGS_LET(_ID, ...) \ - if constexpr ([[maybe_unused]] auto _ID = __VA_ARGS__; false) { \ - } else +# define STDEXEC_IF_OK(_ID) template [[noreturn, nodiscard]] diff --git a/include/stdexec/__detail/__concepts.hpp b/include/stdexec/__detail/__concepts.hpp index f4de37fb1..21e235857 100644 --- a/include/stdexec/__detail/__concepts.hpp +++ b/include/stdexec/__detail/__concepts.hpp @@ -252,6 +252,16 @@ namespace STDEXEC } // namespace __std + template + concept __initializable_from = requires(__declfn_t<_As &&>... __as) { + { _Ty{__as()...} }; + }; + + template + concept __nothrow_initializable_from = requires(__declfn_t<_As &&>... __as) { + { _Ty{__as()...} } noexcept; + }; + template concept __movable_value = __std::move_constructible<__decay_t<_Ty>> && __std::constructible_from<__decay_t<_Ty>, _Ty>; diff --git a/include/stdexec/__detail/__continues_on.hpp b/include/stdexec/__detail/__continues_on.hpp index b87c400f8..c14fbec02 100644 --- a/include/stdexec/__detail/__continues_on.hpp +++ b/include/stdexec/__detail/__continues_on.hpp @@ -318,8 +318,9 @@ namespace STDEXEC template static consteval auto __get_child_completions() { - STDEXEC_COMPLSIGS_LET(__child_completions, - STDEXEC::get_completion_signatures<_Child, __fwd_env_t<_Env>...>()) + auto __child_completions = + STDEXEC::get_completion_signatures<_Child, __fwd_env_t<_Env>...>(); + STDEXEC_IF_OK(__child_completions) { // continues_on has the completions of the child sender, but with value and // error result types decayed. @@ -334,8 +335,9 @@ namespace STDEXEC static consteval auto __get_scheduler_completions() { using __sndr_t = schedule_result_t<_Scheduler>; - STDEXEC_COMPLSIGS_LET(__sched_completions, - STDEXEC::get_completion_signatures<__sndr_t, __fwd_env_t<_Env>...>()) + auto __sched_completions = + STDEXEC::get_completion_signatures<__sndr_t, __fwd_env_t<_Env>...>(); + STDEXEC_IF_OK(__sched_completions) { // The scheduler contributes only error and stopped completions; we ignore value // completions here diff --git a/include/stdexec/__detail/__cpo.hpp b/include/stdexec/__detail/__cpo.hpp deleted file mode 100644 index bbe2ae8b4..000000000 --- a/include/stdexec/__detail/__cpo.hpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2024 NVIDIA Corporation - * - * Licensed under the Apache License Version 2.0 with LLVM Exceptions - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * https://llvm.org/LICENSE.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include "__config.hpp" -#include "__execution_fwd.hpp" - -#if STDEXEC_MSVC() -# pragma deprecated(STDEXEC_CUSTOM) -# pragma deprecated(STDEXEC_MEMFN_DECL) -#endif - -/////////////////////////////////////////////////////////////////////////////// -/// To hook a customization point like STDEXEC::get_env, first bring the names -/// in STDEXEC::tags into scope: -/// -/// @code -/// using namespace STDEXEC::tags; -/// @endcode -/// -/// Then define a member function like this: -/// -/// @code -/// STDEXEC_MEMFN_DECL(auto get_env)(this const MySender& self) { -/// return ...; -/// } -/// @endcode -#define STDEXEC_MEMFN_DECL_IMPL(...) \ - friend STDEXEC_PP_EVAL( \ - STDEXEC_MEMFN_DECL_TAG_INVOKE, STDEXEC_MEMFN_DECL_WHICH(__VA_ARGS__), __VA_ARGS__) - -#define STDEXEC_MEMFN_DECL_WHICH(_A1, ...) \ - STDEXEC_PP_CAT(STDEXEC_MEMFN_DECL_WHICH_, STDEXEC_PP_FRONT(__VA_OPT__(1, ) 0))(_A1, __VA_ARGS__) -#define STDEXEC_MEMFN_DECL_WHICH_0(_A1, ...) \ - STDEXEC_PP_CHECK(STDEXEC_MEMFN_DECL_PROBE_##_A1), STDEXEC_PP_CHECK(_A1##_STDEXEC_MEMFN_DECL_PROBE) -#define STDEXEC_MEMFN_DECL_WHICH_1(_A1, ...) \ - 0, STDEXEC_PP_CHECK(STDEXEC_PP_CAT(STDEXEC_PP_BACK(__VA_ARGS__), _STDEXEC_MEMFN_DECL_PROBE)) - -#define STDEXEC_MEMFN_DECL_TAG_INVOKE(_WHICH, _QUERY, ...) \ - STDEXEC_MEMFN_DECL_RETURN_ ## _WHICH(__VA_ARGS__) \ - __tag_invoke(STDEXEC_MEMFN_DECL_TAG_ ## _WHICH ## _QUERY(__VA_ARGS__) - -#define STDEXEC_MEMFN_DECL_ARGS(...) \ - STDEXEC_PP_CAT(STDEXEC_EAT_THIS_, __VA_ARGS__)) - -#define STDEXEC_MEMFN_DECL_QUERY(_SELF, _TAG, ...) \ - _TAG, STDEXEC_PP_CAT(STDEXEC_EAT_THIS_, _SELF) __VA_OPT__(, __VA_ARGS__)) - -#define STDEXEC_EAT_THIS_this -#define STDEXEC_EAT_AUTO_auto -#define STDEXEC_EAT_VOID_void - -#define query_STDEXEC_MEMFN_DECL_PROBE STDEXEC_PP_PROBE(~, 1) -#define STDEXEC_MEMFN_DECL_PROBE_auto STDEXEC_PP_PROBE(~, 1) -#define STDEXEC_MEMFN_DECL_PROBE_void STDEXEC_PP_PROBE(~, 2) - -#define STDEXEC_MEMFN_DECL_RETURN_0(...) ::STDEXEC::__arg_type_t -#define STDEXEC_MEMFN_DECL_RETURN_1(...) auto -#define STDEXEC_MEMFN_DECL_RETURN_2(...) void - -#define STDEXEC_MEMFN_DECL_TAG_00(...) \ - const ::STDEXEC::__tag_type_t<__VA_ARGS__##_t::*>&, STDEXEC_MEMFN_DECL_ARGS -#define STDEXEC_MEMFN_DECL_TAG_10(...) \ - const STDEXEC_EAT_AUTO_##__VA_ARGS__##_t&, STDEXEC_MEMFN_DECL_ARGS -#define STDEXEC_MEMFN_DECL_TAG_20(...) \ - const STDEXEC_EAT_VOID_##__VA_ARGS__##_t&, STDEXEC_MEMFN_DECL_ARGS -#define STDEXEC_MEMFN_DECL_TAG_01(...) STDEXEC_MEMFN_DECL_QUERY -#define STDEXEC_MEMFN_DECL_TAG_11(...) STDEXEC_MEMFN_DECL_QUERY -#define STDEXEC_MEMFN_DECL_TAG_21(...) STDEXEC_MEMFN_DECL_QUERY - -#define STDEXEC_MEMFN_FRIEND(_TAG) \ - using STDEXEC_PP_CAT(_TAG, _t) = STDEXEC_PP_CAT(STDEXEC::_TAG, _t) - -#if STDEXEC_GCC() || (STDEXEC_CLANG() && STDEXEC_CLANG_VERSION < 1400) -# define STDEXEC_CUSTOM \ - _Pragma("GCC warning \"STDEXEC_CUSTOM is deprecated.\"") STDEXEC_MEMFN_DECL_IMPL -# define STDEXEC_MEMFN_DECL \ - _Pragma("GCC warning \"STDEXEC_MEMFN_DECL is deprecated.\"") STDEXEC_MEMFN_DECL_IMPL -#else -# define STDEXEC_CUSTOM STDEXEC_MEMFN_DECL_IMPL -# define STDEXEC_MEMFN_DECL STDEXEC_MEMFN_DECL_IMPL -#endif - -#if STDEXEC_CLANG() && STDEXEC_CLANG_VERSION >= 1400 -# pragma clang deprecated(STDEXEC_CUSTOM) -# pragma clang deprecated(STDEXEC_MEMFN_DECL) -#endif - -namespace STDEXEC -{ - template - struct __arg_type; - - template - struct __arg_type - { - using type = _Arg; - }; - - template - using __arg_type_t = __arg_type<_Fn>::type; - - template - struct __tag_type; - - template - struct __tag_type<_Ret _Tag::*> - { - using type = _Tag; - }; - - template - using __tag_type_t = __tag_type<_Fn>::type; - - namespace tags - { - using STDEXEC::set_value_t; - using STDEXEC::set_error_t; - using STDEXEC::set_stopped_t; - using STDEXEC::connect_t; - using STDEXEC::start_t; - using STDEXEC::get_env_t; - using STDEXEC::get_completion_signatures_t; - } // namespace tags -} // namespace STDEXEC diff --git a/include/stdexec/__detail/__diagnostics.hpp b/include/stdexec/__detail/__diagnostics.hpp index 485a67625..fe2f67bf6 100644 --- a/include/stdexec/__detail/__diagnostics.hpp +++ b/include/stdexec/__detail/__diagnostics.hpp @@ -267,15 +267,22 @@ namespace STDEXEC "complete."} {} - STDEXEC_ATTRIBUTE(host, device) constexpr auto operator+() const -> _ERROR_; + STDEXEC_ATTRIBUTE(host, device) + constexpr auto operator+() const -> _ERROR_; template STDEXEC_ATTRIBUTE(host, device) - constexpr auto operator,(_Ty const &) const -> _ERROR_; + constexpr auto operator,(_Ty const &) const -> _ERROR_ + { + return *this; + } template STDEXEC_ATTRIBUTE(host, device) - constexpr auto operator,(const _ERROR_ &) const -> _ERROR_; + constexpr auto operator,(const _ERROR_ &__other) const -> _ERROR_ + { + return __other; + } }; // By making __dependent_sender_error_t an alias for _ERROR_<...>, we ensure that diff --git a/include/stdexec/__detail/__domain.hpp b/include/stdexec/__detail/__domain.hpp index 2d49145c5..096671ccc 100644 --- a/include/stdexec/__detail/__domain.hpp +++ b/include/stdexec/__detail/__domain.hpp @@ -18,10 +18,8 @@ #include "__execution_fwd.hpp" #include "__completion_behavior.hpp" -#include "__completion_signatures_of.hpp" #include "__concepts.hpp" #include "__config.hpp" -#include "__execution_fwd.hpp" #include "__meta.hpp" #include "__sender_introspection.hpp" #include "__utility.hpp" @@ -171,12 +169,6 @@ namespace STDEXEC } // namespace __detail //////////////////////////////////////////////////////////////////////////////////////////////// - template - using __completion_domain_t = __call_result_or_t, - indeterminate_domain<>, - _Attrs, - _Env const &...>; - template requires __sends<_Tag, _Sender, _Env...> using __completion_domain_of_t = __completion_domain_t<_Tag, env_of_t<_Sender>, _Env const &...>; diff --git a/include/stdexec/__detail/__execution_fwd.hpp b/include/stdexec/__detail/__execution_fwd.hpp index 38e8408c7..031b5a5a0 100644 --- a/include/stdexec/__detail/__execution_fwd.hpp +++ b/include/stdexec/__detail/__execution_fwd.hpp @@ -74,6 +74,15 @@ namespace STDEXEC extern set_error_t const set_error; extern set_stopped_t const set_stopped; + enum class __disposition + { + __value, + __error, + __stopped + }; + + constexpr auto __invalid_disposition = static_cast<__disposition>(3); // invalid value + template concept __completion_tag = __one_of<_Tag, set_value_t, set_error_t, set_stopped_t>; @@ -135,6 +144,12 @@ namespace STDEXEC extern get_domain_t const get_domain; extern get_await_completion_adaptor_t const get_await_completion_adaptor; + template + using __completion_domain_t = __call_result_or_t, + indeterminate_domain<>, + _Attrs, + _Env const &...>; + template concept __is_debug_env = __callable<__debug_env_t, _Env>; @@ -184,17 +199,20 @@ namespace STDEXEC #if STDEXEC_NO_STDCPP_CONSTEXPR_EXCEPTIONS() template + [[nodiscard]] consteval auto __throw_compile_time_error(_Values...) -> __mexception<_What...>; #else // ^^^ no constexpr exceptions ^^^ / vvv constexpr exceptions vvv // C++26, https://wg21.link/p3068 template + [[noreturn, nodiscard]] consteval auto __throw_compile_time_error(_Values...) -> completion_signatures<>; #endif // ^^^ constexpr exceptions ^^^ template + [[nodiscard]] consteval auto __throw_compile_time_error(__mexception<_What...>); ////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/stdexec/__detail/__finally.hpp b/include/stdexec/__detail/__finally.hpp index 45d06d572..433781399 100644 --- a/include/stdexec/__detail/__finally.hpp +++ b/include/stdexec/__detail/__finally.hpp @@ -307,13 +307,13 @@ namespace STDEXEC template consteval auto __get_completion_signatures() { - STDEXEC_COMPLSIGS_LET(__initial_completions, - get_completion_signatures<_CvInitialSender, _Env...>()) + auto __initial_completions = get_completion_signatures<_CvInitialSender, _Env...>(); + STDEXEC_IF_OK(__initial_completions) { using __initial_completions_t = decltype(__initial_completions); - STDEXEC_COMPLSIGS_LET( - __final_completions, - get_completion_signatures<_CvFinalSender, __mk_final_env_t<_CvInitialSender, _Env>...>()) + auto __final_completions = + get_completion_signatures<_CvFinalSender, __mk_final_env_t<_CvInitialSender, _Env>...>(); + STDEXEC_IF_OK(__final_completions) { if constexpr (__never_sends + namespace STDEXEC { namespace __detail @@ -381,4 +384,16 @@ namespace STDEXEC template using __count_of = __msize_t<__detail::__count_of<_Tag, __completion_signatures_of_t<_Sender, _Env...>>>; + + template + consteval auto __get_completion_info() + { + auto __cmplsigs = STDEXEC::get_completion_signatures<_Sender, _Env...>(); + STDEXEC_IF_OK(__cmplsigs) + { + auto __cmplinfo = STDEXEC::__cmplsigs::__to_array(__cmplsigs); + std::ranges::for_each(__cmplinfo, &__completion_info::__populate<_Sender, _Env...>); + return __cmplinfo; + } + } } // namespace STDEXEC diff --git a/include/stdexec/__detail/__let.hpp b/include/stdexec/__detail/__let.hpp index b59096f80..c0c00b034 100644 --- a/include/stdexec/__detail/__let.hpp +++ b/include/stdexec/__detail/__let.hpp @@ -19,6 +19,7 @@ // include these after __execution_fwd.hpp #include "__basic_sender.hpp" +#include "__completion_info.hpp" #include "__diagnostics.hpp" #include "__domain.hpp" #include "__env.hpp" @@ -27,7 +28,6 @@ #include "__sender_adaptor_closure.hpp" #include "__senders.hpp" #include "__submit.hpp" -#include "__transform_completion_signatures.hpp" #include "__utility.hpp" #include "__variant.hpp" @@ -106,6 +106,12 @@ namespace STDEXEC __fn_t<_WITH_ENVIRONMENT_, _JoinEnv2>..., __mapply_q<_NESTED_ERROR_, __try_completion_signatures_of_t<_Sender, _JoinEnv2...>>>; + template + using __not_decay_copyable_error_t = + __mexception<_WHAT_(_SENDER_RESULTS_ARE_NOT_DECAY_COPYABLE_), + _WHERE_(_IN_ALGORITHM_, _LetTag), + _WITH_ARGUMENTS_(_Args...)>; + template concept __potentially_valid_sender_in = sender_in<_Sender, _JoinEnv2...> || (sender<_Sender> && (sizeof...(_JoinEnv2) == 0)); @@ -132,7 +138,8 @@ namespace STDEXEC using __rcvr2_t = __receiver_archetype<_Env2>; template - using __f = __mbool<__nothrow_decay_copyable<_Ts...> + using __f = __mbool<__nothrow_decay_copyable<_Ts...> // + && __nothrow_invocable<_Fn, __decay_t<_Ts>&...> // && __nothrow_connectable<__sndr2_t<_Ts...>, __rcvr2_t>>; }; @@ -514,111 +521,143 @@ namespace STDEXEC struct __impls : __sexpr_defaults { private: - using __set_t = __t<_LetTag>; - template - using __fn_t = __decay_t<__data_of<_Sender>>; + using __set_t = __t<_LetTag>; + using __eptr_sig_t = set_error_t(std::exception_ptr); + + template + using __fn_t = __decay_t<__data_of<_CvSender>>; + + template + using __env2_t = __let::__result_env_t<__set_t, _CvSender, _Env>; - template + template + using __rcvr2_t = __receiver_archetype<__env2_t<_CvSender, _Env>>; + + template using __opstate_t = __gather_completions_of_t< - __t<_LetTag>, - __child_of<_Sender>, + __set_t, + __child_of<_CvSender>, __fwd_env_t>, __q<__decayed_tuple>, - __mbind_front_q<__opstate, __t<_LetTag>, __child_of<_Sender>, __fn_t<_Sender>, _Receiver>>; + __mbind_front_q<__opstate, __set_t, __child_of<_CvSender>, __fn_t<_CvSender>, _Receiver>>; - template - using __not_decay_copyable_error_t = - __mexception<_WHAT_(_SENDER_RESULTS_ARE_NOT_DECAY_COPYABLE_), - _WHERE_(_IN_ALGORITHM_, _LetTag), - _WITH_ARGUMENTS_(_Args...)>; + template + static constexpr auto __transform_cmplsig = // + [](__set_t (*)(_As...), __completion_info __info) // + -> decltype(auto) + { + if constexpr (!__decay_copyable<_As...>) + { + using __what_t = __not_decay_copyable_error_t<_LetTag, _As...>; + return STDEXEC::__throw_compile_time_error(__what_t()); + } + else if constexpr (!__invocable<_Fun, __decay_t<_As>&...>) + { + using __what_t = __callable_error_t<_LetTag, _Fun, __decay_t<_As>&...>; + return STDEXEC::__throw_compile_time_error(__what_t()); + } + else if constexpr (!__potentially_valid_sender_in< + __invoke_result_t<_Fun, __decay_t<_As>&...>, + __env2_t<_Child, _Env>...>) + { + using __sndr_t = __invoke_result_t<_Fun, __decay_t<_As>&...>; + using __what_t = __bad_result_sender<__sndr_t, _LetTag, __env2_t<_Child, _Env>...>; + return STDEXEC::__throw_compile_time_error(__what_t()); + } + else + { + using __sndr2_t = __invoke_result_t<_Fun, __decay_t<_As>&...>; + auto __cmpls = STDEXEC::__get_completion_info<__sndr2_t, __env2_t<_Child, _Env>...>(); + STDEXEC_IF_OK(__cmpls) + { + if constexpr (!__nothrow_decay_copyable<_As...> + || !__nothrow_invocable<_Fun, __decay_t<_As>&...> + || (!__nothrow_connectable<__sndr2_t, __rcvr2_t<_Child, _Env>> || ...)) + { + __completion_info const __eptr_info(__signature<__eptr_sig_t>, + __info.__domain, + __info.__behavior); + return __cmpls + STDEXEC::__make_static_vector(__eptr_info); + } + else + { + return __cmpls; + } + } + } + }; - public: - static constexpr auto __get_attrs = - [](__ignore, __ignore, _Child const & __child) noexcept -> decltype(auto) + template <__completion_info _Info> + static constexpr auto __maybe_transform_cmplsig = [](auto __transform) -> decltype(auto) { - // TODO(ericniebler): this needs a proper implementation - return __fwd_env(STDEXEC::get_env(__child)); + if constexpr (_Info.__disposition != __set_t::__disposition) + return STDEXEC::__make_static_vector(_Info); + else + return __transform(__signature<__msplice<_Info.__signature>>, _Info); }; - template - static consteval auto __get_completion_signatures() + //! @tparam _Info A `__static_vector` of `__completion_info` objects representing + //! the completions of the predecessor sender. + template + static constexpr auto __get_cmpl_info_i = [](__indices<_Is...>) { - static_assert(__sender_for<_CvSndr, _LetTag>); - using __fn_t = __impls::__fn_t<_CvSndr>; - using __child_t = __child_of<_CvSndr>; - auto __completions = STDEXEC::get_completion_signatures<__child_t, _Env...>(); - auto __transform_fn = []() + return [] { - if constexpr (!__invocable<__fn_t, __decay_t<_Args>&...>) - { - using __what_t = __callable_error_t<_LetTag, __fn_t, __decay_t<_Args>&...>; - return STDEXEC::__throw_compile_time_error(__what_t()); - } - else if constexpr (!__decay_copyable<_Args...>) - { - using __what_t = __not_decay_copyable_error_t<_Args...>; - return STDEXEC::__throw_compile_time_error(__what_t()); - } - else if constexpr (!__potentially_valid_sender_in< - __invoke_result_t<__fn_t, __decay_t<_Args>&...>, - __result_env_t<__set_t, __child_t, _Env>...>) - { - using __sndr_t = __invoke_result_t<__fn_t, __decay_t<_Args>&...>; - using __what_t = - __bad_result_sender<__sndr_t, _LetTag, __result_env_t<__set_t, __child_t, _Env>...>; - return STDEXEC::__throw_compile_time_error(__what_t()); - } - else + __static_vector<__completion_info, 0> __result; + // NB: this fold uses an overloaded addition operator that propagates + // __mexception objects when constexpr exceptions are not available. + return (__maybe_transform_cmplsig<_Info[_Is]>(_Transform) + ... + __result); + }; + }; + + template + struct __get_cmpl_info + { + constexpr auto operator()() const + { + constexpr auto __transform = __transform_cmplsig<_Fun, _Child, _Env...>; + constexpr auto __get_sig = &__completion_info::__signature; + constexpr auto __eptr_sig_id = __mtypeid<__eptr_sig_t>; + constexpr auto __cmpls = STDEXEC::__get_completion_info<_Child, _Env...>(); + + STDEXEC_IF_OK(__cmpls) { - using __sndr_t = __invoke_result_t<__fn_t, __decay_t<_Args>&...>; - using __nothrow_t = __mbool<__nothrow_invocable<__fn_t, __decay_t<_Args>&...> - && __nothrow_decay_copyable<_Args...>>; - - STDEXEC_COMPLSIGS_LET( - __sigs, - STDEXEC::__concat_completion_signatures( - STDEXEC::get_completion_signatures<__sndr_t, - __result_env_t<__set_t, __child_t, _Env>...>(), - __eptr_completion_unless_t<__nothrow_t>())) + constexpr auto __idx = __make_indices<__cmpls.size()>(); + constexpr auto __get_cmpls2 = __get_cmpl_info_i<__cmpls, __transform>(__idx); + constexpr auto __cmpls2 = __cmplsigs::__completion_info_from(__get_cmpls2); + + STDEXEC_IF_OK(__cmpls2) { - if constexpr (__sigs.template __contains()) - { - return __sigs; - } - else if constexpr (sizeof...(_Env) == 0) - { - return STDEXEC::__dependent_sender<__sndr_t>(); - } + if constexpr (std::ranges::find(__cmpls2, __eptr_sig_id, __get_sig) == __cmpls2.end() + && sizeof...(_Env) == 0) + return STDEXEC::__dependent_sender<_Child>(); else - { - using __env_t = __mfront<__result_env_t<__set_t, __child_t, _Env>...>; - using __rcvr_t = __receiver_archetype<__env_t>; - using __nothrow_t = __mbool<__nothrow_connectable<__sndr_t, __rcvr_t>>; - using __eptr_t = __eptr_completion_unless_t<__nothrow_t>; - - return STDEXEC::__concat_completion_signatures(__sigs, __eptr_t()); - } + return __cmpls2; } } - }; + } + }; - if constexpr (!__decay_copyable<_CvSndr>) - { + public: + static constexpr auto __get_attrs = + [](__ignore, __ignore, _Child const & __child) noexcept -> decltype(auto) + { + // TODO(ericniebler): this needs a proper implementation + return __fwd_env(STDEXEC::get_env(__child)); + }; + + template + static consteval auto __get_completion_signatures() + { + static_assert(__sender_for<_CvSender, _LetTag>); + constexpr auto __get_cmpl_info = + __impls::__get_cmpl_info<__fn_t<_CvSender>, __child_of<_CvSender>, _Env...>(); + + if constexpr (!__decay_copyable<_CvSender>) return STDEXEC::__throw_compile_time_error<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, - _WITH_PRETTY_SENDER_<_CvSndr>>(); - } - else if constexpr (__same_as<_LetTag, let_value_t>) - { - return STDEXEC::__transform_completion_signatures(__completions, __transform_fn); - } - else if constexpr (__same_as<_LetTag, let_error_t>) - { - return STDEXEC::__transform_completion_signatures(__completions, {}, __transform_fn); - } + _WITH_PRETTY_SENDER_<_CvSender>>(); else - { - return STDEXEC::__transform_completion_signatures(__completions, {}, {}, __transform_fn); - } + return __cmplsigs::__completion_sigs_from(__get_cmpl_info); } static constexpr auto __connect = diff --git a/include/stdexec/__detail/__meta.hpp b/include/stdexec/__detail/__meta.hpp index e57538cab..5d87d5218 100644 --- a/include/stdexec/__detail/__meta.hpp +++ b/include/stdexec/__detail/__meta.hpp @@ -18,18 +18,18 @@ #include "__concepts.hpp" #include "__config.hpp" #include "__type_traits.hpp" +#include "__typeinfo.hpp" +#include +#include #include #include -#include // IWYU pragma: keep for std::source_location::current -#include #include namespace STDEXEC { - //! Convenience metafunction getting the dependant type `__t` out of `_Tp`. + //! Convenience metafunction getting the dependent type `__t` out of `_Tp`. //! That is, `typename _Tp::__t`. - //! See MAINTAINERS.md#class-template-parameters for details. template using __t = _Tp::__t; @@ -39,24 +39,16 @@ namespace STDEXEC template using __fn_ptr_t = _Ret (*)(_Args...); - template - struct __mtype - { - using __t = _Ty; - }; - template concept __mnever = false; - namespace __detail - { - // NB: This variable template is partially specialized for __type_index in __typeinfo.hpp: - template - extern __fn_ptr_t __mtypeof_v; - } // namespace __detail - +#if STDEXEC_GCC() && STDEXEC_GCC_VERSION < 1300 + template + using __mtypeof = std::remove_const_t; +#else template - using __mtypeof = decltype(__detail::__mtypeof_v<_Value>()); + using __mtypeof = decltype(_Value); +#endif template struct __mlist; @@ -203,7 +195,10 @@ namespace STDEXEC constexpr auto operator+() const -> _ERROR_; STDEXEC_ATTRIBUTE(host, device) - constexpr auto operator,(__ignore) const -> _ERROR_; + constexpr auto operator,(__ignore) const -> _ERROR_ + { + return *this; + } }; template @@ -301,46 +296,6 @@ namespace STDEXEC using __f = __mfind_error<_Args...>; }; -#if STDEXEC_EDG() - // Most compilers memoize alias template specializations, but - // nvc++ does not. So we memoize the type computations by - // indirecting through a class template specialization. - template