1 /*
2  * Copyright (c) 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 "__config.hpp"
19 #include "__execution_fwd.hpp"
20 
21 ///////////////////////////////////////////////////////////////////////////////
22 /// To hook a customization point like stdexec::get_env, first bring the names
23 /// in stdexec::tags into scope:
24 ///
25 /// @code
26 /// using namespace stdexec::tags;
27 /// @endcode
28 ///
29 /// Then define a member function like this:
30 ///
31 /// @code
32 /// STDEXEC_MEMFN_DECL(auto get_env)(this const MySender& self) {
33 ///   return ...;
34 /// }
35 /// @endcode
36 #define STDEXEC_MEMFN_DECL(...)                                                \
37     friend STDEXEC_EVAL(STDEXEC_MEMFN_DECL_TAG_INVOKE,                         \
38                         STDEXEC_MEMFN_DECL_WHICH(__VA_ARGS__), __VA_ARGS__)
39 
40 #define STDEXEC_MEMFN_DECL_WHICH(_A1, ...)                                     \
41     STDEXEC_CAT(STDEXEC_MEMFN_DECL_WHICH_, STDEXEC_FRONT(__VA_OPT__(1, ) 0))   \
42     (_A1, __VA_ARGS__)
43 #define STDEXEC_MEMFN_DECL_WHICH_0(_A1, ...)                                   \
44     STDEXEC_CHECK(STDEXEC_MEMFN_DECL_PROBE_##_A1),                             \
45         STDEXEC_CHECK(_A1##_STDEXEC_MEMFN_DECL_PROBE)
46 #define STDEXEC_MEMFN_DECL_WHICH_1(_A1, ...)                                   \
47     0, STDEXEC_CHECK(                                                          \
48            STDEXEC_CAT(STDEXEC_BACK(__VA_ARGS__), _STDEXEC_MEMFN_DECL_PROBE))
49 
50 #define STDEXEC_MEMFN_DECL_TAG_INVOKE(_WHICH, _QUERY, ...)                     \
51   STDEXEC_MEMFN_DECL_RETURN_ ## _WHICH(__VA_ARGS__)                                                \
52   tag_invoke(STDEXEC_MEMFN_DECL_TAG_ ## _WHICH ## _QUERY(__VA_ARGS__)
53 
54 #define STDEXEC_MEMFN_DECL_ARGS(...)                                           \
55   STDEXEC_CAT(STDEXEC_EAT_THIS_, __VA_ARGS__))
56 
57 #define STDEXEC_MEMFN_DECL_QUERY(_SELF, _TAG, ...)                             \
58   _TAG, STDEXEC_CAT(STDEXEC_EAT_THIS_, _SELF) __VA_OPT__(, __VA_ARGS__))
59 
60 #define STDEXEC_EAT_THIS_this
61 #define STDEXEC_EAT_AUTO_auto
62 #define STDEXEC_EAT_VOID_void
63 
64 #define query_STDEXEC_MEMFN_DECL_PROBE STDEXEC_PROBE(~, 1)
65 #define STDEXEC_MEMFN_DECL_PROBE_auto STDEXEC_PROBE(~, 1)
66 #define STDEXEC_MEMFN_DECL_PROBE_void STDEXEC_PROBE(~, 2)
67 
68 #define STDEXEC_MEMFN_DECL_RETURN_0(...)                                       \
69     ::stdexec::__arg_type_t<void(__VA_ARGS__())>
70 #define STDEXEC_MEMFN_DECL_RETURN_1(...) auto
71 #define STDEXEC_MEMFN_DECL_RETURN_2(...) void
72 
73 #define STDEXEC_MEMFN_DECL_TAG_00(...)                                         \
74     const ::stdexec::__tag_type_t<__VA_ARGS__##_t::*>&, STDEXEC_MEMFN_DECL_ARGS
75 #define STDEXEC_MEMFN_DECL_TAG_10(...)                                         \
76     const STDEXEC_EAT_AUTO_##__VA_ARGS__##_t&, STDEXEC_MEMFN_DECL_ARGS
77 #define STDEXEC_MEMFN_DECL_TAG_20(...)                                         \
78     const STDEXEC_EAT_VOID_##__VA_ARGS__##_t&, STDEXEC_MEMFN_DECL_ARGS
79 #define STDEXEC_MEMFN_DECL_TAG_01(...) STDEXEC_MEMFN_DECL_QUERY
80 #define STDEXEC_MEMFN_DECL_TAG_11(...) STDEXEC_MEMFN_DECL_QUERY
81 #define STDEXEC_MEMFN_DECL_TAG_21(...) STDEXEC_MEMFN_DECL_QUERY
82 
83 #define STDEXEC_MEMFN_FRIEND(_TAG)                                             \
84     using STDEXEC_CAT(_TAG, _t) = STDEXEC_CAT(stdexec::_TAG, _t)
85 
86 #if STDEXEC_MSVC()
87 #pragma deprecated(STDEXEC_CUSTOM)
88 #endif
89 
90 #if STDEXEC_GCC() || (STDEXEC_CLANG() && __clang_major__ < 14)
91 #define STDEXEC_CUSTOM                                                                   \
92     _Pragma(                                                                             \
93         "GCC warning \"STDEXEC_CUSTOM is deprecated; use STDEXEC_MEMFN_DECL instead.\"") \
94         STDEXEC_MEMFN_DECL
95 #else
96 #define STDEXEC_CUSTOM STDEXEC_MEMFN_DECL
97 #endif
98 
99 #if STDEXEC_CLANG() && __clang_major__ >= 14
100 #pragma clang deprecated(STDEXEC_CUSTOM, "use STDEXEC_MEMFN_DECL instead.")
101 #endif
102 
103 namespace stdexec
104 {
105 template <class>
106 struct __arg_type;
107 
108 template <class _Arg>
109 struct __arg_type<void(_Arg (*)())>
110 {
111     using type = _Arg;
112 };
113 
114 template <class _Fn>
115 using __arg_type_t = typename __arg_type<_Fn>::type;
116 
117 template <class>
118 struct __tag_type;
119 
120 template <class _Ret, class _Tag>
121 struct __tag_type<_Ret _Tag::*>
122 {
123     using type = _Tag;
124 };
125 
126 template <class _Fn>
127 using __tag_type_t = typename __tag_type<_Fn>::type;
128 
129 namespace tags
130 {
131 using stdexec::connect_t;
132 using stdexec::get_completion_signatures_t;
133 using stdexec::get_env_t;
134 using stdexec::set_error_t;
135 using stdexec::set_stopped_t;
136 using stdexec::set_value_t;
137 using stdexec::start_t;
138 } // namespace tags
139 } // namespace stdexec
140