xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__tag_invoke.hpp (revision a23d26bd8cd0cc40ff6311e86e0de2c7f43f55ea)
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