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 "__execution_fwd.hpp"
19
20 // include these after __execution_fwd.hpp
21 #include "__basic_sender.hpp"
22 #include "__completion_signatures.hpp"
23 #include "__concepts.hpp"
24 #include "__diagnostics.hpp"
25 #include "__env.hpp"
26 #include "__meta.hpp"
27 #include "__optional.hpp"
28 #include "__receivers.hpp"
29 #include "__tag_invoke.hpp"
30
31 #include <exception>
32
33 namespace stdexec
34 {
35 namespace __read
36 {
37 template <class _Tag, class _ReceiverId>
38 using __result_t = __call_result_t<_Tag, env_of_t<stdexec::__t<_ReceiverId>>>;
39
40 template <class _Tag, class _ReceiverId>
41 concept __nothrow_t =
42 __nothrow_callable<_Tag, env_of_t<stdexec::__t<_ReceiverId>>>;
43
44 inline constexpr __mstring __query_failed_diag =
45 "The current execution environment doesn't have a value for the given query."_mstr;
46
47 template <class _Tag, class _Env>
48 using __query_failed_error = //
49 __mexception< //
50 _NOT_CALLABLE_<"In stdexec::read()..."_mstr, __query_failed_diag>,
51 _WITH_QUERY_<_Tag>, _WITH_ENVIRONMENT_<_Env>>;
52
53 template <class _Tag, class _Env>
54 requires __callable<_Tag, _Env>
55 using __completions_t = //
56 __if_c<__nothrow_callable<_Tag, _Env>,
57 completion_signatures<set_value_t(__call_result_t<_Tag, _Env>)>,
58 completion_signatures<set_value_t(__call_result_t<_Tag, _Env>),
59 set_error_t(std::exception_ptr)>>;
60
61 template <class _Tag, class _Ty>
62 struct __state
63 {
64 using __query = _Tag;
65 using __result = _Ty;
66 __optional<_Ty> __result_;
67 };
68
69 template <class _Tag, class _Ty>
70 requires __same_as<_Ty, _Ty&&>
71 struct __state<_Tag, _Ty>
72 {
73 using __query = _Tag;
74 using __result = _Ty;
75 };
76
77 struct __read_env_t
78 {
79 template <class _Tag>
operator ()stdexec::__read::__read_env_t80 constexpr auto operator()(_Tag) const noexcept
81 {
82 return __make_sexpr<__read_env_t>(_Tag());
83 }
84 };
85
86 struct __read_env_impl : __sexpr_defaults
87 {
88 template <class _Tag, class _Env>
89 using __completions_t = __minvoke<
90 __mtry_catch_q<__read::__completions_t, __q<__query_failed_error>>,
91 _Tag, _Env>;
92
93 static constexpr auto get_completion_signatures = //
94 []<class _Self, class _Env>(const _Self&, _Env&&) noexcept
95 -> __completions_t<__data_of<_Self>, _Env> { return {}; };
96
97 static constexpr auto get_state = //
98 []<class _Self, class _Receiver>(const _Self&, _Receiver&) noexcept {
99 using __query = __data_of<_Self>;
100 using __result = __call_result_t<__query, env_of_t<_Receiver>>;
101 return __state<__query, __result>();
102 };
103
104 static constexpr auto start = //
105 []<class _State, class _Receiver>(_State& __state,
106 _Receiver& __rcvr) noexcept -> void {
107 using __query = typename _State::__query;
108 using __result = typename _State::__result;
109 if constexpr (__same_as<__result, __result&&>)
110 {
111 // The query returns a reference type; pass it straight through to
112 // the receiver.
113 stdexec::__set_value_invoke(static_cast<_Receiver&&>(__rcvr),
114 __query(), stdexec::get_env(__rcvr));
115 }
116 else
117 {
118 constexpr bool _Nothrow =
119 __nothrow_callable<__query, env_of_t<_Receiver>>;
__anona47160310102stdexec::__read::__read_env_impl120 auto __query_fn = [&]() noexcept(_Nothrow) -> __result&& {
121 __state.__result_.emplace(
122 __emplace_from{[&]() noexcept(_Nothrow) {
123 return __query()(stdexec::get_env(__rcvr));
124 }});
125 return static_cast<__result&&>(*__state.__result_);
126 };
127 stdexec::__set_value_invoke(static_cast<_Receiver&&>(__rcvr),
128 __query_fn);
129 }
130 };
131 };
132 } // namespace __read
133
134 inline constexpr __read::__read_env_t read{};
135 inline constexpr __read::__read_env_t read_env{};
136
137 template <>
138 struct __sexpr_impl<__read::__read_env_t> : __read::__read_env_impl
139 {};
140
141 namespace __queries
142 {
143 template <class _Tag>
operator ()() const144 inline auto get_scheduler_t::operator()() const noexcept
145 {
146 return read_env(get_scheduler);
147 }
148
149 template <class _Tag>
operator ()() const150 inline auto get_delegation_scheduler_t::operator()() const noexcept
151 {
152 return read_env(get_delegation_scheduler);
153 }
154
155 template <class _Tag>
operator ()() const156 inline auto get_allocator_t::operator()() const noexcept
157 {
158 return read_env(get_allocator);
159 }
160
161 template <class _Tag>
operator ()() const162 inline auto get_stop_token_t::operator()() const noexcept
163 {
164 return read_env(get_stop_token);
165 }
166 } // namespace __queries
167 } // namespace stdexec
168