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
tag_invoke(_Tag,const _Env &)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))
tag_invoke(_Tag,const _Env & __env)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),
71 static_cast<_Args &&>(__args)...);
72 };
73
74 template <class _Ret, class _Tag, class... _Args>
75 concept __tag_invocable_r = //
76 requires(_Tag __tag, _Args&&... __args) {
77 {
78 static_cast<_Ret>(tag_invoke(static_cast<_Tag &&>(__tag),
79 static_cast<_Args &&>(__args)...))
80 };
81 };
82
83 // NOT TO SPEC: nothrow_tag_invocable subsumes tag_invocable
84 template <class _Tag, class... _Args>
85 concept nothrow_tag_invocable =
86 tag_invocable<_Tag, _Args...> && //
87 requires(_Tag __tag, _Args&&... __args) {
88 {
89 tag_invoke(static_cast<_Tag &&>(__tag),
90 static_cast<_Args &&>(__args)...)
91 } noexcept;
92 };
93
94 template <class _Tag, class... _Args>
95 using tag_invoke_result_t =
96 decltype(tag_invoke(__declval<_Tag>(), __declval<_Args>()...));
97
98 template <class _Tag, class... _Args>
99 struct tag_invoke_result
100 {};
101
102 template <class _Tag, class... _Args>
103 requires tag_invocable<_Tag, _Args...>
104 struct tag_invoke_result<_Tag, _Args...>
105 {
106 using type = tag_invoke_result_t<_Tag, _Args...>;
107 };
108
109 struct tag_invoke_t
110 {
111 template <class _Tag, class... _Args>
112 requires tag_invocable<_Tag, _Args...>
113 STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__tag_invoke::tag_invoke_t114 constexpr auto operator()(_Tag __tag, _Args&&... __args) const
115 noexcept(nothrow_tag_invocable<_Tag, _Args...>)
116 -> tag_invoke_result_t<_Tag, _Args...>
117 {
118 return tag_invoke(static_cast<_Tag&&>(__tag),
119 static_cast<_Args&&>(__args)...);
120 }
121 };
122
123 } // namespace __tag_invoke
124
125 using __tag_invoke::tag_invoke_t;
126
127 namespace __ti
128 {
129 inline constexpr tag_invoke_t tag_invoke{};
130 } // namespace __ti
131
132 using namespace __ti;
133
134 template <auto& _Tag>
135 using tag_t = __decay_t<decltype(_Tag)>;
136
137 using __tag_invoke::__tag_invocable_r;
138 using __tag_invoke::nothrow_tag_invocable;
139 using __tag_invoke::tag_invocable;
140 using __tag_invoke::tag_invoke_result;
141 using __tag_invoke::tag_invoke_result_t;
142 } // namespace stdexec
143