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 20 namespace stdexec::__std_concepts { 21 #if STDEXEC_HAS_STD_CONCEPTS_HEADER() 22 using std::invocable; 23 #else 24 template <class _Fun, class... _As> 25 concept invocable = requires(_Fun&& __f, _As&&... __as) { 26 std::invoke(static_cast<_Fun &&>(__f), static_cast<_As &&>(__as)...); 27 }; 28 #endif 29 } // namespace stdexec::__std_concepts 30 31 namespace std { 32 using namespace stdexec::__std_concepts; 33 } // namespace std 34 35 namespace stdexec { 36 // [func.tag_invoke], tag_invoke 37 namespace __tag_invoke { 38 void tag_invoke(); 39 40 // NOT TO SPEC: Don't require tag_invocable to subsume invocable. 41 // std::invoke is more expensive at compile time than necessary, 42 // and results in diagnostics that are more verbose than necessary. 43 template <class _Tag, class... _Args> 44 concept tag_invocable = requires(_Tag __tag, _Args&&... __args) { 45 tag_invoke(static_cast<_Tag &&>(__tag), static_cast<_Args &&>(__args)...); 46 }; 47 48 template <class _Ret, class _Tag, class... _Args> 49 concept __tag_invocable_r = requires(_Tag __tag, _Args&&... __args) { 50 { 51 static_cast<_Ret>(tag_invoke(static_cast<_Tag &&>(__tag), static_cast<_Args &&>(__args)...)) 52 }; 53 }; 54 55 // NOT TO SPEC: nothrow_tag_invocable subsumes tag_invocable 56 template <class _Tag, class... _Args> 57 concept nothrow_tag_invocable = 58 tag_invocable<_Tag, _Args...> && requires(_Tag __tag, _Args&&... __args) { 59 { tag_invoke(static_cast<_Tag &&>(__tag), static_cast<_Args &&>(__args)...) } noexcept; 60 }; 61 62 template <class _Tag, class... _Args> 63 using tag_invoke_result_t = decltype(tag_invoke(__declval<_Tag>(), __declval<_Args>()...)); 64 65 template <class _Tag, class... _Args> 66 struct tag_invoke_result { }; 67 68 template <class _Tag, class... _Args> 69 requires tag_invocable<_Tag, _Args...> 70 struct tag_invoke_result<_Tag, _Args...> { 71 using type = tag_invoke_result_t<_Tag, _Args...>; 72 }; 73 74 struct tag_invoke_t { 75 template <class _Tag, class... _Args> 76 requires tag_invocable<_Tag, _Args...> STDEXEC_ATTRIBUTEstdexec::__tag_invoke::tag_invoke_t77 STDEXEC_ATTRIBUTE(always_inline) 78 constexpr auto operator()(_Tag __tag, _Args&&... __args) const 79 noexcept(nothrow_tag_invocable<_Tag, _Args...>) -> tag_invoke_result_t<_Tag, _Args...> { 80 return tag_invoke(static_cast<_Tag&&>(__tag), static_cast<_Args&&>(__args)...); 81 } 82 }; 83 84 } // namespace __tag_invoke 85 86 using __tag_invoke::tag_invoke_t; 87 88 namespace __ti { 89 inline constexpr tag_invoke_t tag_invoke{}; 90 } // namespace __ti 91 92 using namespace __ti; 93 94 template <auto& _Tag> 95 using tag_t = __decay_t<decltype(_Tag)>; 96 97 using __tag_invoke::tag_invocable; 98 using __tag_invoke::__tag_invocable_r; 99 using __tag_invoke::nothrow_tag_invocable; 100 using __tag_invoke::tag_invoke_result_t; 101 using __tag_invoke::tag_invoke_result; 102 } // namespace stdexec 103