1 /* 2 * Copyright (c) 2021-2024 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 "__concepts.hpp" 19 #include "__meta.hpp" 20 21 namespace stdexec::__std_concepts 22 { 23 #if STDEXEC_HAS_STD_CONCEPTS_HEADER() 24 using std::invocable; 25 #else 26 template <class _Fun, class... _As> 27 concept invocable = // 28 requires(_Fun&& __f, _As&&... __as) { 29 std::invoke(static_cast<_Fun&&>(__f), static_cast<_As&&>(__as)...); 30 }; 31 #endif 32 } // namespace stdexec::__std_concepts 33 34 namespace std 35 { 36 using namespace stdexec::__std_concepts; 37 } // namespace std 38 39 namespace stdexec 40 { 41 // [func.tag_invoke], tag_invoke 42 namespace __tag_invoke 43 { 44 void tag_invoke(); 45 46 // For handling queryables with a static constexpr query member function: 47 template <class _Tag, class _Env> 48 requires true // so this overload is preferred over the one below 49 STDEXEC_ATTRIBUTE((always_inline)) constexpr auto tag_invoke( 50 _Tag, const _Env&) noexcept -> __mconstant<_Env::query(_Tag())> 51 { 52 return {}; 53 } 54 55 // For handling queryables with a query member function: 56 template <class _Tag, class _Env> 57 STDEXEC_ATTRIBUTE((always_inline)) 58 constexpr auto tag_invoke(_Tag, const _Env& __env) noexcept( 59 noexcept(__env.query(_Tag()))) -> decltype(__env.query(_Tag())) 60 { 61 return __env.query(_Tag()); 62 } 63 64 // NOT TO SPEC: Don't require tag_invocable to subsume invocable. 65 // std::invoke is more expensive at compile time than necessary, 66 // and results in diagnostics that are more verbose than necessary. 67 template <class _Tag, class... _Args> 68 concept tag_invocable = // 69 requires(_Tag __tag, _Args&&... __args) { 70 tag_invoke(static_cast<_Tag&&>(__tag), static_cast<_Args&&>(__args)...); 71 }; 72 73 template <class _Ret, class _Tag, class... _Args> 74 concept __tag_invocable_r = // 75 requires(_Tag __tag, _Args&&... __args) { 76 { 77 static_cast<_Ret>(tag_invoke(static_cast<_Tag&&>(__tag), 78 static_cast<_Args&&>(__args)...)) 79 }; 80 }; 81 82 // NOT TO SPEC: nothrow_tag_invocable subsumes tag_invocable 83 template <class _Tag, class... _Args> 84 concept nothrow_tag_invocable = 85 tag_invocable<_Tag, _Args...> && // 86 requires(_Tag __tag, _Args&&... __args) { 87 { 88 tag_invoke(static_cast<_Tag&&>(__tag), 89 static_cast<_Args&&>(__args)...) 90 } noexcept; 91 }; 92 93 template <class _Tag, class... _Args> 94 using tag_invoke_result_t = 95 decltype(tag_invoke(__declval<_Tag>(), __declval<_Args>()...)); 96 97 template <class _Tag, class... _Args> 98 struct tag_invoke_result 99 {}; 100 101 template <class _Tag, class... _Args> 102 requires tag_invocable<_Tag, _Args...> 103 struct tag_invoke_result<_Tag, _Args...> 104 { 105 using type = tag_invoke_result_t<_Tag, _Args...>; 106 }; 107 108 struct tag_invoke_t 109 { 110 template <class _Tag, class... _Args> 111 requires tag_invocable<_Tag, _Args...> 112 STDEXEC_ATTRIBUTE((always_inline)) 113 constexpr auto operator()(_Tag __tag, _Args&&... __args) const 114 noexcept(nothrow_tag_invocable<_Tag, _Args...>) 115 -> tag_invoke_result_t<_Tag, _Args...> 116 { 117 return tag_invoke(static_cast<_Tag&&>(__tag), 118 static_cast<_Args&&>(__args)...); 119 } 120 }; 121 122 } // namespace __tag_invoke 123 124 using __tag_invoke::tag_invoke_t; 125 126 namespace __ti 127 { 128 inline constexpr tag_invoke_t tag_invoke{}; 129 } // namespace __ti 130 131 using namespace __ti; 132 133 template <auto& _Tag> 134 using tag_t = __decay_t<decltype(_Tag)>; 135 136 using __tag_invoke::__tag_invocable_r; 137 using __tag_invoke::nothrow_tag_invocable; 138 using __tag_invoke::tag_invocable; 139 using __tag_invoke::tag_invoke_result; 140 using __tag_invoke::tag_invoke_result_t; 141 } // namespace stdexec 142