1 /* 2 * Copyright (c) 2025 NVIDIA Corporation 3 * 4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * https://llvm.org/LICENSE.txt 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include <compare> 19 #include <type_traits> 20 #include <initializer_list> 21 22 #include "__config.hpp" 23 #include "__concepts.hpp" 24 #include "__query.hpp" 25 #include "__meta.hpp" 26 #include "__execution_fwd.hpp" 27 #include "__type_traits.hpp" 28 29 namespace stdexec { 30 ////////////////////////////////////////////////////////////////////////////////////////// 31 // get_completion_behavior 32 namespace __completion_behavior { 33 enum class completion_behavior : int { 34 unknown, ///< The completion behavior is unknown. 35 asynchronous, ///< The operation's completion will not happen on the calling thread before `start()` 36 ///< returns. 37 synchronous, ///< The operation's completion happens-before the return of `start()`. 38 inline_completion ///< The operation completes synchronously within `start()` on the same thread that called 39 ///< `start()`. 40 }; 41 42 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 43 constexpr auto operator<=>(completion_behavior __a, completion_behavior __b) noexcept 44 -> std::strong_ordering { 45 return static_cast<int>(__a) <=> static_cast<int>(__b); 46 } 47 48 template <completion_behavior _CB> 49 using __constant_t = std::integral_constant<completion_behavior, _CB>; 50 51 using __unknown_t = __constant_t<completion_behavior::unknown>; 52 using __asynchronous_t = __constant_t<completion_behavior::asynchronous>; 53 using __synchronous_t = __constant_t<completion_behavior::synchronous>; 54 using __inline_completion_t = __constant_t<completion_behavior::inline_completion>; 55 } // namespace __completion_behavior 56 57 struct min_t; 58 59 struct completion_behavior { 60 private: 61 template <__completion_behavior::completion_behavior _CB> 62 using __constant_t = std::integral_constant<__completion_behavior::completion_behavior, _CB>; 63 64 friend struct min_t; 65 66 public: 67 struct unknown_t : __completion_behavior::__unknown_t { }; 68 struct asynchronous_t : __completion_behavior::__asynchronous_t { }; 69 struct synchronous_t : __completion_behavior::__synchronous_t { }; 70 struct inline_completion_t : __completion_behavior::__inline_completion_t { }; 71 72 static constexpr unknown_t unknown{}; 73 static constexpr asynchronous_t asynchronous{}; 74 static constexpr synchronous_t synchronous{}; 75 static constexpr inline_completion_t inline_completion{}; 76 }; 77 78 ////////////////////////////////////////////////////////////////////////////////////////// 79 // get_completion_behavior: A sender can define this attribute to describe the sender's 80 // completion behavior 81 struct get_completion_behavior_t 82 : __query<get_completion_behavior_t, completion_behavior::unknown, __q1<__decay_t>> { 83 template <class _Attrs, class... _Env> STDEXEC_ATTRIBUTEstdexec::get_completion_behavior_t84 STDEXEC_ATTRIBUTE(always_inline, host, device) 85 static constexpr void __validate() noexcept { 86 static_assert( 87 __nothrow_queryable_with<_Attrs, get_completion_behavior_t, _Env...>, 88 "The get_completion_behavior query must be noexcept."); 89 static_assert( 90 convertible_to< 91 __query_result_t<_Attrs, get_completion_behavior_t, _Env...>, 92 __completion_behavior::completion_behavior 93 >, 94 "The get_completion_behavior query must return one of the static member variables in " 95 "execution::completion_behavior."); 96 } 97 STDEXEC_ATTRIBUTEstdexec::get_completion_behavior_t98 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 99 static constexpr auto query(forwarding_query_t) noexcept -> bool { 100 return true; 101 } 102 }; 103 104 struct min_t { 105 using __completion_behavior_t = __completion_behavior::completion_behavior; 106 STDEXEC_ATTRIBUTEstdexec::min_t107 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 108 static constexpr auto __minimum(std::initializer_list<__completion_behavior_t> __cbs) noexcept 109 -> __completion_behavior_t { 110 auto __result = __completion_behavior::completion_behavior::inline_completion; 111 for (auto __cb: __cbs) { 112 if (__cb < __result) { 113 __result = __cb; 114 } 115 } 116 return __result; 117 } 118 119 template <__completion_behavior_t... _CBs> STDEXEC_ATTRIBUTEstdexec::min_t120 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 121 constexpr auto operator()(completion_behavior::__constant_t<_CBs>...) const noexcept { 122 constexpr auto __behavior = __minimum({_CBs...}); 123 124 if constexpr (__behavior == completion_behavior::unknown) { 125 return completion_behavior::unknown; 126 } else if constexpr (__behavior == completion_behavior::asynchronous) { 127 return completion_behavior::asynchronous; 128 } else if constexpr (__behavior == completion_behavior::synchronous) { 129 return completion_behavior::synchronous; 130 } else if constexpr (__behavior == completion_behavior::inline_completion) { 131 return completion_behavior::inline_completion; 132 } 133 STDEXEC_UNREACHABLE(); 134 } 135 }; 136 137 constexpr min_t min{}; 138 139 template <class _Attrs, class... _Env> 140 concept __completes_inline = 141 (__call_result_t<get_completion_behavior_t, const _Attrs&, const _Env&...>{} 142 == completion_behavior::inline_completion); 143 144 template <class _Sndr, class... _Env> STDEXEC_ATTRIBUTE(nodiscard,always_inline,host,device)145 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 146 consteval auto get_completion_behavior() noexcept { 147 using __behavior_t = 148 __call_result_t<get_completion_behavior_t, env_of_t<_Sndr>, const _Env&...>; 149 return __behavior_t{}; 150 } 151 152 } // namespace stdexec 153