Skip to content

Commit c5be204

Browse files
committed
flatten the structure of env<> for the sake of msvc
fixes #1979
1 parent 47bb920 commit c5be204

2 files changed

Lines changed: 87 additions & 49 deletions

File tree

include/stdexec/__detail/__env.hpp

Lines changed: 34 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "__meta.hpp"
2222
#include "__query.hpp"
2323
#include "__tag_invoke.hpp"
24+
#include "__tuple.hpp"
2425

2526
#include <exception> // IWYU pragma: keep for std::terminate
2627
#include <functional> // IWYU pragma: keep for unwrap_reference_t
@@ -29,6 +30,7 @@
2930
STDEXEC_PRAGMA_PUSH()
3031
STDEXEC_PRAGMA_IGNORE_EDG(probable_guiding_friend)
3132
STDEXEC_PRAGMA_IGNORE_EDG(type_qualifiers_ignored_on_reference)
33+
STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
3234

3335
namespace STDEXEC
3436
{
@@ -113,7 +115,7 @@ namespace STDEXEC
113115
}
114116
else
115117
{
116-
return env<_Env1, __fwd_env_t<_Env2>>{{static_cast<_Env1 &&>(__env1)},
118+
return env<_Env1, __fwd_env_t<_Env2>>{static_cast<_Env1 &&>(__env1),
117119
__fwd_fn()(static_cast<_Env2 &&>(__env2))};
118120
}
119121
}
@@ -201,70 +203,53 @@ namespace STDEXEC
201203
STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE
202204
prop(_Query, _Value) -> prop<_Query, std::unwrap_reference_t<_Value>>;
203205

204-
//////////////////////////////////////////////////////////////////////
205-
// env
206-
template <class... _Envs>
207-
struct env;
208-
209-
template <>
210-
struct env<>
211-
{
212-
STDEXEC_ATTRIBUTE(nodiscard, host, device)
213-
auto query() const = delete;
214-
};
215-
216-
template <class _Env>
217-
struct env<_Env> : _Env
218-
{};
219-
220-
template <class _Env>
221-
struct env<_Env &>
206+
namespace __detail
222207
{
223208
template <class _Query, class... _Args>
224-
requires __queryable_with<_Env, _Query, _Args...>
225-
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
226-
constexpr auto query(_Query, _Args &&...__args) const
227-
noexcept(__nothrow_queryable_with<_Env, _Query, _Args...>)
228-
-> __query_result_t<_Env, _Query, _Args...>
209+
struct __get_1st_env
229210
{
230-
return __query<_Query>()(__env_, static_cast<_Args &&>(__args)...);
231-
}
211+
STDEXEC_ATTRIBUTE(host, device, always_inline)
212+
constexpr void operator()() const noexcept {}
232213

233-
_Env &__env_;
234-
};
214+
template <class _Env0, class... _Envs>
215+
STDEXEC_ATTRIBUTE(host, device, always_inline)
216+
constexpr auto
217+
operator()(_Env0 const &__env0, _Envs const &...__envs) const noexcept -> decltype(auto)
218+
{
219+
if constexpr (__callable<__query<_Query>, _Env0 const &, _Args...>)
220+
return (__env0); // load-bearing parentheses, do not remove
221+
else
222+
return (*this)(__envs...);
223+
}
224+
};
225+
} // namespace __detail
235226

236-
template <class _Env1, class _Env2>
237-
struct env<_Env1, _Env2>
227+
//////////////////////////////////////////////////////////////////////
228+
// env
229+
template <class... _Envs>
230+
struct env
238231
{
232+
private:
239233
template <class _Query, class... _Args>
240-
requires __queryable_with<_Env1, _Query, _Args...>
241-
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
242-
constexpr auto query(_Query, _Args &&...__args) const
243-
noexcept(__nothrow_queryable_with<_Env1, _Query, _Args...>)
244-
-> __query_result_t<_Env1, _Query, _Args...>
245-
{
246-
return __query<_Query>()(__env1_, static_cast<_Args &&>(__args)...);
247-
}
234+
using __1st_env_t =
235+
__call_result_t<__detail::__get_1st_env<_Query, _Args...>, _Envs const &...>;
248236

237+
public:
249238
template <class _Query, class... _Args>
250-
requires __queryable_with<_Env1, _Query, _Args...>
251-
|| __queryable_with<_Env2, _Query, _Args...>
239+
requires __queryable_with<__1st_env_t<_Query, _Args...>, _Query, _Args...>
252240
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
253241
constexpr auto query(_Query, _Args &&...__args) const
254-
noexcept(__nothrow_queryable_with<_Env2, _Query, _Args...>)
255-
-> __query_result_t<_Env2, _Query, _Args...>
242+
noexcept(__nothrow_queryable_with<__1st_env_t<_Query, _Args...>, _Query, _Args...>)
243+
-> __query_result_t<__1st_env_t<_Query, _Args...>, _Query, _Args...>
256244
{
257-
return __query<_Query>()(__env2_, static_cast<_Args &&>(__args)...);
245+
auto const &__env = __apply(__detail::__get_1st_env<_Query, _Args...>(), __envs_);
246+
return __query<_Query>()(__env, static_cast<_Args &&>(__args)...);
258247
}
259248

260-
STDEXEC_ATTRIBUTE(no_unique_address) _Env1 __env1_;
261-
STDEXEC_ATTRIBUTE(no_unique_address) _Env2 __env2_;
249+
STDEXEC_ATTRIBUTE(no_unique_address)
250+
__tuple<_Envs...> __envs_;
262251
};
263252

264-
template <class _Env1, class _Env2, class... _Envs>
265-
struct env<_Env1, _Env2, _Envs...> : env<env<_Env1, _Env2>, _Envs...>
266-
{};
267-
268253
template <class... _Envs>
269254
STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE env(_Envs...) -> env<std::unwrap_reference_t<_Envs>...>;
270255

test/stdexec/queries/test_env.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
namespace ex = STDEXEC;
2323

24+
STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
25+
2426
namespace
2527
{
2628
template <typename T>
@@ -106,4 +108,55 @@ namespace
106108
auto sch = ex::get_completion_scheduler<ex::set_value_t>(attrs, ex::env{});
107109
CHECK(std::same_as<decltype(sch), ex::inline_scheduler>);
108110
}
111+
112+
#define DEFINE_QUERY(name) \
113+
constexpr struct name ## _t : ex::__query<name ## _t> \
114+
{ } name{}
115+
116+
DEFINE_QUERY(query_0);
117+
DEFINE_QUERY(query_1);
118+
DEFINE_QUERY(query_2);
119+
DEFINE_QUERY(query_3);
120+
DEFINE_QUERY(query_4);
121+
DEFINE_QUERY(query_5);
122+
DEFINE_QUERY(query_6);
123+
DEFINE_QUERY(query_7);
124+
DEFINE_QUERY(query_8);
125+
DEFINE_QUERY(query_9);
126+
DEFINE_QUERY(query_10);
127+
DEFINE_QUERY(query_11);
128+
DEFINE_QUERY(query_12);
129+
130+
TEST_CASE("env supports lots of child envs without exceeding compiler limits", "[queries][env]")
131+
{
132+
auto env = ex::env{
133+
ex::prop{ query_0, 0},
134+
ex::prop{ query_1, 1},
135+
ex::prop{ query_2, 2},
136+
ex::prop{ query_3, 3},
137+
ex::prop{ query_4, 4},
138+
ex::prop{ query_5, 5},
139+
ex::prop{ query_6, 6},
140+
ex::prop{ query_7, 7},
141+
ex::prop{ query_8, 8},
142+
ex::prop{ query_9, 9},
143+
ex::prop{query_10, 10},
144+
ex::prop{query_11, 11},
145+
ex::prop{query_12, 12}
146+
};
147+
148+
CHECK(env.query(query_0) == 0);
149+
CHECK(env.query(query_1) == 1);
150+
CHECK(env.query(query_2) == 2);
151+
CHECK(env.query(query_3) == 3);
152+
CHECK(env.query(query_4) == 4);
153+
CHECK(env.query(query_5) == 5);
154+
CHECK(env.query(query_6) == 6);
155+
CHECK(env.query(query_7) == 7);
156+
CHECK(env.query(query_8) == 8);
157+
CHECK(env.query(query_9) == 9);
158+
CHECK(env.query(query_10) == 10);
159+
CHECK(env.query(query_11) == 11);
160+
CHECK(env.query(query_12) == 12);
161+
}
109162
} // namespace

0 commit comments

Comments
 (0)