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