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), 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))
operator ()stdexec::__tag_invoke::tag_invoke_t113 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