Skip to content

Commit 9154664

Browse files
authored
make __tuple and env constexpr (#1575)
* make `__tuple` and `env` `constexpr` * constexpr-ify `<exec/env.hpp>` * enforce mandates in [exec.prop]/p2
1 parent dd8bd6b commit 9154664

4 files changed

Lines changed: 38 additions & 27 deletions

File tree

include/exec/env.hpp

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ namespace exec {
2727
namespace __envs {
2828
struct __with_t {
2929
template <class _Tag, class _Value>
30-
auto operator()(_Tag, _Value&& __val) const {
30+
constexpr auto operator()(_Tag, _Value&& __val) const {
3131
return stdexec::prop{_Tag(), static_cast<_Value&&>(__val)};
3232
}
3333
};
3434

3535
struct __without_t {
3636
template <class _Env, class _Tag>
37-
auto operator()(_Env&& __env, _Tag) const -> decltype(auto) {
37+
constexpr auto operator()(_Env&& __env, _Tag) const -> decltype(auto) {
3838
return stdexec::__env::__without(static_cast<_Env&&>(__env), _Tag());
3939
}
4040
};
@@ -46,13 +46,13 @@ namespace exec {
4646
stdexec::__nothrow_move_constructible _Base,
4747
stdexec::__nothrow_move_constructible _Env
4848
>
49-
auto operator()(_Base&& __base, _Env&& __env) const noexcept
49+
constexpr auto operator()(_Base&& __base, _Env&& __env) const noexcept
5050
-> stdexec::__join_env_t<_Env, _Base> {
5151
return stdexec::__env::__join(static_cast<_Env&&>(__env), static_cast<_Base&&>(__base));
5252
}
5353

5454
template <stdexec::__nothrow_move_constructible _Env>
55-
auto operator()(_Env&& __env) const noexcept -> _Env {
55+
constexpr auto operator()(_Env&& __env) const noexcept -> _Env {
5656
return static_cast<_Env&&>(__env);
5757
}
5858
};
@@ -81,7 +81,7 @@ namespace exec {
8181
STDEXEC_ATTRIBUTE(no_unique_address) _Default __default_;
8282
_Receiver __rcvr_;
8383

84-
void start() & noexcept {
84+
constexpr void start() & noexcept {
8585
STDEXEC_TRY {
8686
if constexpr (__callable<_Tag, env_of_t<_Receiver>>) {
8787
const auto& __env = get_env(__rcvr_);
@@ -91,7 +91,6 @@ namespace exec {
9191
}
9292
}
9393
STDEXEC_CATCH_ALL {
94-
9594
stdexec::set_error(std::move(__rcvr_), std::current_exception());
9695
}
9796
}
@@ -120,14 +119,14 @@ namespace exec {
120119

121120
template <__decays_to<__sender> _Self, class _Receiver>
122121
requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>>
123-
static auto connect(_Self&& __self, _Receiver __rcvr)
122+
static constexpr auto connect(_Self&& __self, _Receiver __rcvr)
124123
noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
125124
-> __operation_t<_Tag, __default_t<env_of_t<_Receiver>>, _Receiver> {
126125
return {{}, static_cast<_Self&&>(__self).__default_, static_cast<_Receiver&&>(__rcvr)};
127126
}
128127

129128
template <class _Env>
130-
auto get_completion_signatures(_Env&&) -> __completions_t<_Env> {
129+
constexpr auto get_completion_signatures(_Env&&) -> __completions_t<_Env> {
131130
return {};
132131
}
133132
};
@@ -160,19 +159,19 @@ namespace exec {
160159
_Sender __sndr_;
161160
_Attrs __attrs_;
162161

163-
auto get_env() const noexcept -> __join_env_t<const _Attrs&, env_of_t<_Sender>> {
162+
constexpr auto get_env() const noexcept -> __join_env_t<const _Attrs&, env_of_t<_Sender>> {
164163
return stdexec::__env::__join(__attrs_, stdexec::get_env(__sndr_));
165164
}
166165

167166
template <__decays_to<__t> _Self, class... _Env>
168-
static auto get_completion_signatures(_Self&&, _Env&&...)
167+
static constexpr auto get_completion_signatures(_Self&&, _Env&&...)
169168
-> completion_signatures_of_t<__copy_cvref_t<_Self, _Sender>, _Env...> {
170169
return {};
171170
}
172171

173172
template <__decays_to<__t> _Self, class _Receiver>
174173
requires sender_in<__copy_cvref_t<_Self, _Sender>, env_of_t<_Receiver>>
175-
static auto connect(_Self&& __self, _Receiver __rcvr)
174+
static constexpr auto connect(_Self&& __self, _Receiver __rcvr)
176175
-> connect_result_t<__copy_cvref_t<_Self, _Sender>, _Receiver> {
177176
return stdexec::connect(std::forward<_Self>(__self).__sndr_, std::move(__rcvr));
178177
}
@@ -182,7 +181,7 @@ namespace exec {
182181
struct __write_attrs_t {
183182
template <class _Sender, class _Attrs>
184183
STDEXEC_ATTRIBUTE(host, device)
185-
auto
184+
constexpr auto
186185
operator()(_Sender snd, _Attrs __attrs_) const -> __write_attrs::__sender<_Sender, _Attrs> {
187186
return __t<__write_attrs::__sender<__id<_Sender>, _Attrs>>{
188187
static_cast<_Sender&&>(snd), static_cast<_Attrs&&>(__attrs_)};
@@ -194,15 +193,15 @@ namespace exec {
194193

195194
template <class _Sender>
196195
STDEXEC_ATTRIBUTE(host, device)
197-
friend auto operator|(_Sender __sndr_, __closure _clsr) {
196+
friend constexpr auto operator|(_Sender __sndr_, __closure _clsr) {
198197
return __t<__write_attrs::__sender<__id<_Sender>, _Attrs>>{
199198
static_cast<_Sender&&>(__sndr_), static_cast<_Attrs&&>(_clsr.__attrs_)};
200199
}
201200
};
202201

203202
template <class _Attrs>
204203
STDEXEC_ATTRIBUTE(host, device)
205-
auto operator()(_Attrs __attrs_) const {
204+
constexpr auto operator()(_Attrs __attrs_) const {
206205
return __closure<_Attrs>{static_cast<_Attrs&&>(__attrs_)};
207206
}
208207
};

include/stdexec/__detail/__env.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "__tag_invoke.hpp"
2525
#include "__tuple.hpp"
2626

27+
#include <exception> // IWYU pragma: keep for std::terminate
2728
#include <functional> // IWYU pragma: keep for unwrap_reference_t
2829
#include <type_traits>
2930
#include <utility>
@@ -363,12 +364,23 @@ namespace stdexec {
363364
template <class _Env, class _Query, class... _Args>
364365
using __query_result_t = tag_invoke_result_t<_Query, const _Env&, _Args...>;
365366

367+
template <class ValueType>
368+
struct __prop_like {
369+
template <class _Query>
370+
STDEXEC_ATTRIBUTE(nodiscard)
371+
constexpr auto query(_Query) const noexcept -> const ValueType& {
372+
STDEXEC_TERMINATE();
373+
}
374+
};
375+
366376
// A singleton environment from a query/value pair
367377
template <class _Query, class _Value>
368378
struct prop {
369379
using __t = prop;
370380
using __id = prop;
371381

382+
static_assert(__callable<_Query, __prop_like<_Value>>);
383+
372384
STDEXEC_ATTRIBUTE(no_unique_address) _Query __query;
373385

374386
STDEXEC_ATTRIBUTE(no_unique_address) _Value __value;

include/stdexec/__detail/__execution_fwd.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
#pragma once
1717

18-
#include "__config.hpp"
18+
#include "__config.hpp" // IWYU pragma: export
1919
#include "__meta.hpp"
2020
#include "__concepts.hpp"
2121
#include "__type_traits.hpp"

include/stdexec/__detail/__tuple.hpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,33 +87,33 @@ namespace stdexec {
8787
requires(sizeof...(_Ts) - 1 > 3) // intentional unsigned wrap-around for sizeof...(Ts) is zero
8888
struct __tuple<_Idx, _Ts...> : __box<_Ts, _Is>... {
8989
template <class... _Us>
90-
static auto __convert_from(__tuple<_Idx, _Us...> &&__tup) -> __tuple {
90+
static constexpr auto __convert_from(__tuple<_Idx, _Us...> &&__tup) -> __tuple {
9191
return __tuple{
9292
{static_cast<_Us &&>(__tup.STDEXEC_CWG1835_TEMPLATE __box<_Us, _Is>::__value)}...};
9393
}
9494

9595
template <class... _Us>
96-
static auto __convert_from(__tuple<_Idx, _Us...> const &__tup) -> __tuple {
96+
static constexpr auto __convert_from(__tuple<_Idx, _Us...> const &__tup) -> __tuple {
9797
return __tuple{{__tup.STDEXEC_CWG1835_TEMPLATE __box<_Us, _Is>::__value}...};
9898
}
9999

100100
template <std::size_t _Np, class _Self>
101101
STDEXEC_ATTRIBUTE(host, device, always_inline)
102-
static auto __get(_Self &&__self) noexcept
102+
static constexpr auto __get(_Self &&__self) noexcept
103103
-> decltype(__tup::__get<_Np>(static_cast<_Self &&>(__self))) {
104104
return __tup::__get<_Np>(static_cast<_Self &&>(__self));
105105
}
106106

107107
// clang-format off
108108
template <class _Fn, class _Self, class... _Us>
109-
STDEXEC_ATTRIBUTE(host, device, always_inline) static auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us)
109+
STDEXEC_ATTRIBUTE(host, device, always_inline) static constexpr auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us)
110110
STDEXEC_AUTO_RETURN(
111111
static_cast<_Fn &&>(__fn)(
112112
static_cast<_Us &&>(__us)...,
113113
static_cast<_Self &&>(__self).STDEXEC_CWG1835_TEMPLATE __box<_Ts, _Is>::__value...))
114114

115115
template <class _Fn, class _Self, class... _Us>
116-
STDEXEC_ATTRIBUTE(host, device, always_inline) static auto for_each(_Fn &&__fn, _Self &&__self)
116+
STDEXEC_ATTRIBUTE(host, device, always_inline) static constexpr auto for_each(_Fn &&__fn, _Self &&__self)
117117
STDEXEC_AUTO_RETURN(
118118
(static_cast<void>(
119119
__fn(static_cast<_Self &&>(__self).STDEXEC_CWG1835_TEMPLATE __box<_Ts, _Is>::__value)),
@@ -145,34 +145,34 @@ namespace stdexec {
145145
STDEXEC_REPEAT(_N, STDEXEC_TUPLE_ELEM_DEFN) \
146146
\
147147
template <STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_DEFN))> \
148-
static auto __convert_from(__tuple<_Idx STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_USE)> &&__tup) \
148+
static constexpr auto __convert_from(__tuple<_Idx STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_USE)> &&__tup) \
149149
-> __tuple { \
150150
return __tuple{ \
151151
STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TUPLE_OTHER_ELEM_RVALUE))}; \
152152
} \
153153
\
154154
template <STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_DEFN))> \
155-
static auto __convert_from( \
155+
static constexpr auto __convert_from( \
156156
__tuple<_Idx STDEXEC_REPEAT(_N, STDEXEC_TPARAM_OTHER_USE)> const &__tup) -> __tuple { \
157157
return __tuple{ \
158158
STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TUPLE_OTHER_ELEM_LVALUE))}; \
159159
} \
160160
\
161161
template <std::size_t _Np, class _Self> \
162162
STDEXEC_ATTRIBUTE(host, device, always_inline) \
163-
static auto __get(_Self &&__self) noexcept -> decltype(auto) requires(_Np < _N) { \
163+
static constexpr auto __get(_Self &&__self) noexcept -> decltype(auto) requires(_Np < _N) { \
164164
STDEXEC_REPEAT(_N, STDEXEC_TUPLE_GET_ELEM); \
165165
} \
166166
\
167167
template <class _Fn, class _Self, class... _Us> \
168168
STDEXEC_ATTRIBUTE(host, device, always_inline) \
169-
static auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us) STDEXEC_AUTO_RETURN( \
169+
static constexpr auto apply(_Fn &&__fn, _Self &&__self, _Us &&...__us) STDEXEC_AUTO_RETURN( \
170170
static_cast<_Fn &&>(__fn)(static_cast<_Us &&>(__us)... \
171171
STDEXEC_REPEAT(_N, STDEXEC_TUPLE_ELEM_USE))) \
172172
\
173173
template <class _Fn, class _Self> \
174174
STDEXEC_ATTRIBUTE(host, device, always_inline) \
175-
static auto for_each(_Fn &&__fn, _Self &&__self) STDEXEC_AUTO_RETURN( \
175+
static constexpr auto for_each(_Fn &&__fn, _Self &&__self) STDEXEC_AUTO_RETURN( \
176176
STDEXEC_EVAL(STDEXEC_TAIL, STDEXEC_REPEAT(_N, STDEXEC_TUPLE_FOR_EACH_ELEM))) \
177177
};
178178
// clang-format on
@@ -209,15 +209,15 @@ namespace stdexec {
209209

210210
template <class _Fn, class _Tuple>
211211
STDEXEC_ATTRIBUTE(host, device, always_inline)
212-
auto operator<<(_Tuple &&__tup, _Fn __fn) noexcept(__nothrow_move_constructible<_Fn>) {
212+
constexpr auto operator<<(_Tuple &&__tup, _Fn __fn) noexcept(__nothrow_move_constructible<_Fn>) {
213213
return [&__tup, __fn = static_cast<_Fn &&>(__fn)]<class... _Us>(_Us &&...__us) noexcept(
214214
__nothrow_applicable<_Fn, _Tuple, _Us...>) -> __apply_result_t<_Fn, _Tuple, _Us...> {
215215
return __tup.apply(__fn, static_cast<_Tuple &&>(__tup), static_cast<_Us &&>(__us)...);
216216
};
217217
}
218218

219219
template <class _Fn, class... _Tuples>
220-
auto __cat_apply(_Fn __fn, _Tuples &&...__tups)
220+
constexpr auto __cat_apply(_Fn __fn, _Tuples &&...__tups)
221221
STDEXEC_AUTO_RETURN((static_cast<_Tuples &&>(__tups) << ... << __fn)())
222222

223223
STDEXEC_PRAGMA_PUSH() STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")

0 commit comments

Comments
 (0)