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 <type_traits> 19 20 #include "__config.hpp" 21 #include "__concepts.hpp" 22 #include "__execution_fwd.hpp" 23 #include "__tag_invoke.hpp" 24 #include "__type_traits.hpp" 25 26 namespace stdexec { 27 // [exec.queries.queryable] 28 template <class T> 29 concept queryable = destructible<T>; 30 31 template <class _Env, class _Query, class... _Args> 32 concept __member_queryable_with = 33 queryable<_Env> 34 && requires(const _Env& __env, const _Query& __query, __declfn<_Args&&>... __args) { 35 { __env.query(__query, __args()...) }; 36 }; 37 38 template <class _Env, class _Query, class... _Args> 39 concept __nothrow_member_queryable_with = 40 __member_queryable_with<_Env, _Query, _Args...> 41 && requires(const _Env& __env, const _Query& __query, __declfn<_Args&&>... __args) { 42 { __env.query(__query, __args()...) } noexcept; 43 }; 44 45 template <class _Env, class _Qy, class... _Args> 46 using __member_query_result_t = 47 decltype(__declval<const _Env&>().query(__declval<const _Qy&>(), __declval<_Args>()...)); 48 49 constexpr __none_such __no_default{}; 50 51 template <class _Query, class _Env, class... _Args> 52 concept __has_validation = requires { _Query::template __validate<_Env, _Args...>(); }; 53 54 template <class _Query, auto _Default = __no_default, class _Transform = __q1<__midentity>> 55 struct __query // NOLINT(bugprone-crtp-constructor-accessibility) 56 : __query<_Query, __no_default, _Transform> { 57 using __query<_Query, __no_default, _Transform>::operator(); 58 59 template <class... _Args> STDEXEC_ATTRIBUTEstdexec::__query60 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 61 constexpr auto operator()(__ignore, _Args&&...) const noexcept // 62 -> __mcall1<_Transform, __mtypeof<_Default>> { 63 return _Default; 64 } 65 }; 66 67 template <class _Query, class _Transform> 68 struct __query<_Query, __no_default, _Transform> { 69 template <class Sig> 70 static inline constexpr _Query (*signature)(Sig) = nullptr; 71 72 // Query with a .query member function: 73 template <class _Qy = _Query, class _Env, class... _Args> 74 requires __member_queryable_with<const _Env&, _Qy, _Args...> STDEXEC_ATTRIBUTEstdexec::__query75 STDEXEC_ATTRIBUTE(always_inline, host, device) 76 constexpr auto operator()(const _Env& __env, _Args&&... __args) const 77 noexcept(__nothrow_member_queryable_with<_Env, _Qy, _Args...>) 78 -> __mcall1<_Transform, __member_query_result_t<_Env, _Qy, _Args...>> { 79 if constexpr (__has_validation<_Query, _Env, _Args...>) { 80 _Query::template __validate<_Env, _Args...>(); 81 } 82 return __env.query(_Query(), static_cast<_Args&&>(__args)...); 83 } 84 85 // Query with tag_invoke (legacy): 86 template <class _Qy = _Query, class _Env, class... _Args> 87 requires(!__member_queryable_with<const _Env&, _Qy, _Args...>) 88 && tag_invocable<_Qy, const _Env&, _Args...> STDEXEC_ATTRIBUTEstdexec::__query89 STDEXEC_ATTRIBUTE(always_inline, host, device) 90 constexpr auto operator()(const _Env& __env, _Args&&... __args) const 91 noexcept(nothrow_tag_invocable<_Qy, const _Env&, _Args...>) 92 -> __mcall1<_Transform, tag_invoke_result_t<_Qy, const _Env&, _Args...>> { 93 if constexpr (__has_validation<_Query, _Env, _Args...>) { 94 _Query::template __validate<_Env, _Args...>(); 95 } 96 return tag_invoke(_Query(), __env, static_cast<_Args&&>(__args)...); 97 } 98 }; 99 100 template <class _Env, class _Query, class... _Args> 101 concept __queryable_with = __callable<__query<_Query>, _Env&, _Args...>; 102 103 template <class _Env, class _Query, class... _Args> 104 concept __nothrow_queryable_with = __nothrow_callable<__query<_Query>, _Env&, _Args...>; 105 106 template <class _Env, class _Query, class... _Args> 107 using __query_result_t = __call_result_t<__query<_Query>, _Env&, _Args...>; 108 109 template <class _Env, class _Query, class... _Args> 110 concept __statically_queryable_with_impl = requires(_Query __q, _Args&&... __args) { 111 std::remove_reference_t<_Env>::query(__q, static_cast<_Args&&>(__args)...); 112 }; 113 114 template <class _Env, class _Query, class... _Args> 115 concept __statically_queryable_with = __queryable_with<_Env, _Query, _Args...> 116 && __statically_queryable_with_impl<_Env, _Query, _Args...>; 117 118 ////////////////////////////////////////////////////////////////////////////////////////////////// 119 // [exec.queries] 120 namespace __queries { 121 template <class _Tp> 122 concept __is_bool_constant = requires { typename __mbool<_Tp::value>; }; 123 124 struct forwarding_query_t { 125 template <class _Query> STDEXEC_ATTRIBUTEstdexec::__queries::forwarding_query_t126 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 127 consteval auto operator()(_Query) const noexcept -> bool { 128 if constexpr (__queryable_with<_Query, forwarding_query_t>) { 129 return __query<forwarding_query_t>()(_Query()); 130 } else { 131 return derived_from<_Query, forwarding_query_t>; 132 } 133 } 134 }; 135 136 struct query_or_t { 137 template <class _Query, class _Queryable, class _Default, class... _Args> STDEXEC_ATTRIBUTEstdexec::__queries::query_or_t138 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 139 constexpr auto operator()(_Query, _Queryable&&, _Default&& __default, _Args&&...) const 140 noexcept(__nothrow_move_constructible<_Default>) -> _Default { 141 return static_cast<_Default&&>(__default); 142 } 143 144 template <class _Query, class _Queryable, class _Default, class... _Args> 145 requires __callable<_Query, _Queryable, _Args...> STDEXEC_ATTRIBUTEstdexec::__queries::query_or_t146 STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) 147 constexpr auto 148 operator()(_Query __query, _Queryable&& __queryable, _Default&&, _Args&&... __args) const 149 noexcept(__nothrow_callable<_Query, _Queryable, _Args...>) 150 -> __call_result_t<_Query, _Queryable, _Args...> { 151 return static_cast<_Query&&>( 152 __query)(static_cast<_Queryable&&>(__queryable), static_cast<_Args&&>(__args)...); 153 } 154 }; 155 } // namespace __queries 156 157 using __queries::forwarding_query_t; 158 using __queries::query_or_t; 159 160 inline constexpr forwarding_query_t forwarding_query{}; 161 inline constexpr query_or_t query_or{}; // NOT TO SPEC 162 163 template <class _Tag> 164 concept __forwarding_query = forwarding_query(_Tag{}); 165 } // namespace stdexec 166