Skip to content

Commit ec3fde2

Browse files
authored
initial implementation for std::execution::task (#1820)
1 parent 1687898 commit ec3fde2

File tree

19 files changed

+1014
-127
lines changed

19 files changed

+1014
-127
lines changed

include/exec/task.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -477,12 +477,12 @@ namespace exec {
477477
public:
478478
// Make this task awaitable within a particular context:
479479
template <class _ParentPromise>
480-
constexpr // requires __std::constructible_from<
481-
// awaiter_context_t<__promise, _ParentPromise>,
482-
// __promise_context_t&,
483-
// _ParentPromise&
484-
// >
485-
auto as_awaitable(_ParentPromise&) && noexcept { //-> __task_awaitable<_ParentPromise> {
480+
requires __std::constructible_from<
481+
awaiter_context_t<__promise, _ParentPromise>,
482+
__promise_context_t&,
483+
_ParentPromise&
484+
>
485+
constexpr auto as_awaitable(_ParentPromise&) && noexcept -> __task_awaitable<_ParentPromise> {
486486
return __task_awaitable<_ParentPromise>{std::exchange(__coro_, {})};
487487
}
488488

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (c) 2026 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 "__sender_concepts.hpp"
19+
#include "__schedulers.hpp"
20+
21+
namespace STDEXEC {
22+
struct affine_on_t {
23+
template <sender _Sender, scheduler _Scheduler>
24+
constexpr auto operator()(_Sender&& __sndr, _Scheduler&&) const -> auto&& {
25+
// BUGBUG TODO: implement me
26+
return static_cast<_Sender&&>(__sndr);
27+
}
28+
};
29+
30+
inline constexpr affine_on_t affine_on{};
31+
} // namespace STDEXEC

include/stdexec/__detail/__as_awaitable.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ namespace STDEXEC {
3636
extern const __q<__decayed_std_tuple> __as_single;
3737

3838
template <>
39-
inline const __q<__midentity> __as_single<1>;
39+
inline constexpr __q<__midentity> __as_single<1>;
4040

4141
template <>
42-
inline const __mconst<void> __as_single<0>;
42+
inline constexpr __mconst<void> __as_single<0>;
4343

4444
template <class... _Values>
4545
using __single_value = __minvoke<decltype(__as_single<sizeof...(_Values)>), _Values...>;
4646

4747
template <class _Sender, class _Promise>
4848
using __value_t = __decay_t<
4949
__value_types_of_t<_Sender, env_of_t<_Promise&>, __q<__single_value>, __msingle_or<void>>
50-
>;
50+
>;
5151
} // namespace __detail
5252

5353
/////////////////////////////////////////////////////////////////////////////

include/stdexec/__detail/__concepts.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,9 @@ namespace STDEXEC {
290290

291291
namespace __detail {
292292
template <class _Alloc>
293-
constexpr auto __test_alloc_pointer(int) -> typename _Alloc::pointer;
293+
constexpr auto __test_alloc_pointer(int) -> _Alloc::pointer;
294294
template <class _Alloc>
295-
constexpr auto __test_alloc_pointer(long) -> typename _Alloc::value_type*;
295+
constexpr auto __test_alloc_pointer(long) -> _Alloc::value_type*;
296296

297297
template <class _Alloc>
298298
using __alloc_pointer_t = decltype(__detail::__test_alloc_pointer<__decay_t<_Alloc>>(0));

include/stdexec/__detail/__execution_fwd.hpp

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -200,42 +200,10 @@ namespace STDEXEC {
200200

201201
namespace __cmplsigs {
202202
struct get_completion_signatures_t;
203-
204-
#if STDEXEC_NO_STD_CONSTEXPR_EXCEPTIONS()
205-
// Without constexpr exceptions, we cannot always produce a valid
206-
// completion_signatures type. We must permit get_completion_signatures to return an
207-
// error type because we can't throw it.
208-
template <class _Completions>
209-
concept __well_formed_completions_helper =
210-
__valid_completion_signatures<_Completions>
211-
|| STDEXEC_IS_BASE_OF(STDEXEC::dependent_sender_error, _Completions)
212-
|| __is_instance_of<_Completions, _ERROR_>;
213-
#else
214-
// When we have constexpr exceptions, we can require that get_completion_signatures
215-
// always produces a valid completion_signatures type.
216-
template <class _Completions>
217-
concept __well_formed_completions_helper = __valid_completion_signatures<_Completions>;
218-
#endif
219203
} // namespace __cmplsigs
220204

221205
using __cmplsigs::get_completion_signatures_t;
222206

223-
// The cast to bool is to hide the disjunction in __well_formed_completions_helper.
224-
template <class _Completions>
225-
concept __well_formed_completions = bool(
226-
__cmplsigs::__well_formed_completions_helper<_Completions>);
227-
228-
// template <class _Sender>
229-
// consteval auto get_completion_signatures();
230-
231-
// template <class _Sender, class _Env>
232-
// consteval auto get_completion_signatures();
233-
234-
// // Legacy interface:
235-
// template <class _Sender, class... _Env>
236-
// requires(sizeof...(_Env) <= 1)
237-
// constexpr auto get_completion_signatures(_Sender&&, const _Env&...) noexcept;
238-
239207
#if STDEXEC_NO_STD_CONSTEXPR_EXCEPTIONS()
240208

241209
template <class... _What, class... _Values>

include/stdexec/__detail/__meta.hpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -812,27 +812,39 @@ namespace STDEXEC {
812812
using __f = __minvoke<__mzip_with2_<_Cp, _Dp>, _Fn, _Continuation>;
813813
};
814814

815+
template <class _Ty, class _Uy>
816+
using __msame_as = __mbool<STDEXEC_IS_SAME(_Ty, _Uy)>;
817+
818+
template <class _Ty, class _Uy>
819+
using __mconvertible_to = __mbool<STDEXEC_IS_CONVERTIBLE_TO(_Ty, _Uy)>;
820+
815821
template <bool>
816-
struct __mfind_ {
817-
template <class _Needle, class _Continuation, class _Head, class... _Tail>
822+
struct __mfind_if_ {
823+
template <class _Fn, class _Continuation, class _Head, class... _Tail>
818824
using __f = __minvoke_if_c<
819-
__same_as<_Needle, _Head>,
825+
__mcall1<_Fn, _Head>::value,
820826
__mbind_front<_Continuation, _Head>,
821-
__mbind_front<__mfind_<(sizeof...(_Tail) != 0)>, _Needle, _Continuation>,
827+
__mbind_front<__mfind_if_<(sizeof...(_Tail) != 0)>, _Fn, _Continuation>,
822828
_Tail...
823829
>;
824830
};
825831

826832
template <>
827-
struct __mfind_<false> {
828-
template <class _Needle, class _Continuation>
833+
struct __mfind_if_<false> {
834+
template <class _Fn, class _Continuation>
829835
using __f = __minvoke<_Continuation>;
830836
};
831837

838+
template <class _Fn, class _Continuation = __q<__mlist>>
839+
struct __mfind_if {
840+
template <class... _Args>
841+
using __f = __minvoke<__mfind_if_<(sizeof...(_Args) != 0)>, _Fn, _Continuation, _Args...>;
842+
};
843+
832844
template <class _Needle, class _Continuation = __q<__mlist>>
833845
struct __mfind {
834846
template <class... _Args>
835-
using __f = __minvoke<__mfind_<(sizeof...(_Args) != 0)>, _Needle, _Continuation, _Args...>;
847+
using __f = __mcall<__mfind_if<__mbind_front_q<__msame_as, _Needle>, _Continuation>, _Args...>;
836848
};
837849

838850
template <class _Needle>

include/stdexec/__detail/__optional.hpp

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ namespace STDEXEC {
135135
if (!__has_value_) {
136136
STDEXEC_THROW(__bad_optional_access());
137137
}
138-
return static_cast<_Tp&&>(__value_);
138+
return static_cast<_Tp&&>(static_cast<_Tp&>(__value_));
139139
}
140140

141141
constexpr auto operator*() & noexcept -> _Tp& {
@@ -150,17 +150,17 @@ namespace STDEXEC {
150150

151151
constexpr auto operator*() && noexcept -> _Tp&& {
152152
STDEXEC_ASSERT(__has_value_);
153-
return static_cast<_Tp&&>(__value_);
153+
return static_cast<_Tp&&>(static_cast<_Tp&>(__value_));
154154
}
155155

156-
constexpr auto operator->() & noexcept -> _Tp* {
156+
constexpr auto operator->() & noexcept -> std::add_pointer_t<_Tp> {
157157
STDEXEC_ASSERT(__has_value_);
158-
return &__value_;
158+
return std::addressof(static_cast<_Tp&>(__value_));
159159
}
160160

161-
constexpr auto operator->() const & noexcept -> const _Tp* {
161+
constexpr auto operator->() const & noexcept -> std::add_pointer_t<const _Tp> {
162162
STDEXEC_ASSERT(__has_value_);
163-
return &__value_;
163+
return std::addressof(static_cast<const _Tp&>(__value_));
164164
}
165165

166166
[[nodiscard]]
@@ -175,6 +175,71 @@ namespace STDEXEC {
175175
}
176176
}
177177
};
178+
179+
// __optional<T&>
180+
template <class _Tp>
181+
struct __optional<_Tp&> {
182+
_Tp* __value_ = nullptr;
183+
184+
__optional() noexcept = default;
185+
186+
__optional(__nullopt_t) noexcept {
187+
}
188+
189+
template <__not_decays_to<__optional> _Up>
190+
requires __std::constructible_from<_Tp&, _Up>
191+
constexpr __optional(_Up&& __val) noexcept(__nothrow_constructible_from<_Tp&, _Up>) {
192+
emplace(static_cast<_Up&&>(__val));
193+
}
194+
195+
template <__not_decays_to<__optional> _Up>
196+
requires __std::constructible_from<_Tp&, _Up>
197+
constexpr __optional(std::in_place_t, _Up&& __val)
198+
noexcept(__nothrow_constructible_from<_Tp&, _Up>) {
199+
emplace(static_cast<_Up&&>(__val));
200+
}
201+
202+
template <class _Up>
203+
requires __std::constructible_from<_Tp&, _Up>
204+
constexpr auto emplace(_Up&& __us) noexcept(__nothrow_constructible_from<_Tp&, _Up>) -> _Tp& {
205+
__value_ = std::addressof(static_cast<_Up&&>(__us));
206+
return *__value_;
207+
}
208+
209+
template <class _Fn, class... _Args>
210+
requires __std::same_as<_Tp&, __call_result_t<_Fn, _Args...>>
211+
auto __emplace_from(_Fn&& __f, _Args&&... __args) noexcept(__nothrow_callable<_Fn, _Args...>)
212+
-> _Tp& {
213+
__value_ = std::addressof(static_cast<_Fn&&>(__f)(static_cast<_Args&&>(__args)...));
214+
return *__value_;
215+
}
216+
217+
constexpr auto value() const -> _Tp& {
218+
if (__value_ == nullptr) {
219+
STDEXEC_THROW(__bad_optional_access());
220+
}
221+
return *__value_;
222+
}
223+
224+
constexpr auto operator*() const -> _Tp& {
225+
STDEXEC_ASSERT(__value_ != nullptr);
226+
return *__value_;
227+
}
228+
229+
constexpr auto operator->() const -> _Tp* {
230+
STDEXEC_ASSERT(__value_ != nullptr);
231+
return __value_;
232+
}
233+
234+
[[nodiscard]]
235+
constexpr auto has_value() const noexcept -> bool {
236+
return __value_ != nullptr;
237+
}
238+
239+
constexpr void reset() noexcept {
240+
__value_ = nullptr;
241+
}
242+
};
178243
} // namespace __opt
179244

180245
using __opt::__optional;

include/stdexec/__detail/__scope.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include "__config.hpp"
1919
#include "__utility.hpp"
2020

21-
#include <functional>
21+
#include <type_traits>
2222

2323
namespace STDEXEC {
2424
template <class _Fn, class... _Ts>

0 commit comments

Comments
 (0)