Skip to content

Commit 4e95646

Browse files
committed
Implement execution::just factory
1 parent 4285ea5 commit 4e95646

File tree

4 files changed

+167
-0
lines changed

4 files changed

+167
-0
lines changed

stl/inc/execution

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5403,6 +5403,64 @@ namespace execution {
54035403
template <_One_of<set_value_t, set_error_t, set_done_t> _Target>
54045404
inline constexpr _Get_completion_scheduler::_Cpo<_Target> get_completion_scheduler;
54055405
}
5406+
5407+
// TRANSITION: Specialize for 1 argument
5408+
template <class... _Types>
5409+
struct _Just_sender {
5410+
tuple<_Types...> _Values;
5411+
5412+
template <template <class...> class _Tuple, template <class...> class _Variant>
5413+
using value_types = _Variant<_Tuple<_Types...>>;
5414+
5415+
template <template <class...> class _Variant>
5416+
using error_types = _Variant<exception_ptr>;
5417+
5418+
static const constexpr auto sends_done = false;
5419+
5420+
template <receiver _Receiver>
5421+
struct operation_state {
5422+
tuple<_Types...> _Values;
5423+
_Receiver _Rec;
5424+
5425+
friend constexpr void tag_invoke(start_t, operation_state& _State) noexcept {
5426+
_TRY_BEGIN
5427+
apply(
5428+
[&_State](_Types&... _Values) { //
5429+
_EXEC set_value(_STD move(_State._Rec), _STD move(_Values)...);
5430+
},
5431+
_State._Values);
5432+
_CATCH_ALL
5433+
_EXEC set_error(_STD move(_State._Rec), _STD current_exception());
5434+
_CATCH_END
5435+
}
5436+
};
5437+
5438+
// clang-format off
5439+
template <receiver _Receiver>
5440+
requires (receiver_of<_Receiver, _Types...> && (copyable<_Types> && ...))
5441+
_NODISCARD friend constexpr auto tag_invoke(connect_t, const _Just_sender& _Sender, _Receiver&& _Rec) noexcept(
5442+
(is_nothrow_copy_constructible_v<_Types> && ...) //
5443+
&& is_nothrow_constructible_v<remove_cvref_t<_Receiver>, _Receiver>) {
5444+
// clang-format on
5445+
return operation_state<_Receiver>{_Sender._Values, _STD forward<_Receiver>(_Rec)};
5446+
}
5447+
5448+
// clang-format off
5449+
template <receiver _Receiver>
5450+
requires receiver_of<_Receiver, _Types...>
5451+
_NODISCARD friend constexpr auto tag_invoke(connect_t, _Just_sender&& _Sender, _Receiver&& _Rec) noexcept(
5452+
(is_nothrow_move_constructible_v<_Types> && ...)
5453+
&& is_nothrow_constructible_v<remove_cvref_t<_Receiver>, _Receiver>) {
5454+
// clang-format on
5455+
return operation_state<_Receiver>{_STD move(_Sender._Values), _STD forward<_Receiver>(_Rec)};
5456+
}
5457+
};
5458+
5459+
template <_Movable_value... _Types>
5460+
_NODISCARD constexpr _Just_sender<remove_cvref_t<_Types>...> just(_Types&&... _Values) noexcept(
5461+
(is_nothrow_constructible_v<remove_cvref_t<_Types>, _Types> && ...)) {
5462+
return {_STD make_tuple(_STD forward<_Types>(_Values)...)};
5463+
}
54065464
} // namespace execution
54075465
#endif // __cpp_lib_executors
54085466
_STD_END

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ tests\P1951R1_default_arguments_pair_forward_ctor
452452
tests\P2136R3_invoke_r
453453
tests\P2162R2_std_visit_for_derived_classes_from_variant
454454
tests\P2231R1_complete_constexpr_optional_variant
455+
tests\P2300R2_executors_factories
455456
tests\P2300R2_executors_receiver
456457
tests\P2300R2_executors_scheduler
457458
tests\P2300R2_executors_sender
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#include <cassert>
5+
#include <concepts>
6+
#include <execution>
7+
#include <tuple>
8+
using namespace std;
9+
using execution::connect, execution::operation_state, execution::receiver_of, execution::sender_of, execution::start,
10+
execution::typed_sender;
11+
12+
struct Tracker {
13+
bool set_values_called = false;
14+
bool set_error_called = false;
15+
bool set_done_called = false;
16+
};
17+
struct Dummy {};
18+
struct CustomError {};
19+
20+
enum class DoesThrowOnSetValue : bool { No, Yes };
21+
template <DoesThrowOnSetValue ThrowOnSetValue, class... Types>
22+
struct test_receiver {
23+
constexpr test_receiver(Tracker& tracker) noexcept : _tracker(tracker) {}
24+
friend constexpr auto tag_invoke(execution::set_done_t, test_receiver rec) noexcept {
25+
rec._tracker.set_done_called = true;
26+
}
27+
friend auto tag_invoke(execution::set_error_t, test_receiver rec, exception_ptr) noexcept {
28+
rec._tracker.set_error_called = true;
29+
}
30+
friend constexpr auto tag_invoke(execution::set_error_t, test_receiver rec, CustomError) noexcept {
31+
rec._tracker.set_error_called = true;
32+
}
33+
friend constexpr auto tag_invoke(execution::set_value_t, test_receiver rec, Types...) noexcept(
34+
ThrowOnSetValue == DoesThrowOnSetValue::No) {
35+
rec._tracker.set_values_called = true;
36+
if constexpr (ThrowOnSetValue == DoesThrowOnSetValue::Yes) {
37+
throw 42;
38+
}
39+
}
40+
41+
struct fake_operation_state {
42+
friend constexpr void tag_invoke(execution::start_t, fake_operation_state&) noexcept {}
43+
};
44+
45+
Tracker& _tracker;
46+
};
47+
template <class... Types>
48+
using nothrow_receiver = test_receiver<DoesThrowOnSetValue::No, Types...>;
49+
template <class... Types>
50+
using throws_on_set_values_receiver = test_receiver<DoesThrowOnSetValue::Yes, Types...>;
51+
52+
static_assert(receiver_of<nothrow_receiver<int>, int>);
53+
static_assert(operation_state<nothrow_receiver<int>::fake_operation_state>);
54+
static_assert(receiver_of<throws_on_set_values_receiver<int>, int>);
55+
static_assert(operation_state<throws_on_set_values_receiver<int>::fake_operation_state>);
56+
57+
constexpr bool test_just() {
58+
{
59+
Tracker tracker;
60+
const sender_of<int> auto sender = execution::just(5);
61+
operation_state auto state = connect(sender, nothrow_receiver<int>{tracker});
62+
assert(!tracker.set_values_called);
63+
start(state);
64+
assert(tracker.set_values_called);
65+
66+
static_assert(!invocable<execution::connect_t, decltype(sender), nothrow_receiver<Dummy>>);
67+
}
68+
69+
{
70+
Tracker tracker;
71+
operation_state auto state = connect(execution::just(5), nothrow_receiver<int>{tracker});
72+
assert(!tracker.set_values_called);
73+
start(state);
74+
assert(tracker.set_values_called);
75+
}
76+
77+
{
78+
Tracker tracker;
79+
const sender_of<int, Dummy> auto sender = execution::just(5, Dummy{});
80+
operation_state auto state = connect(sender, nothrow_receiver<int, Dummy>{tracker});
81+
assert(!tracker.set_values_called);
82+
start(state);
83+
assert(tracker.set_values_called);
84+
85+
static_assert(!invocable<execution::connect_t, decltype(sender), nothrow_receiver<Dummy, int>>);
86+
}
87+
88+
if (!is_constant_evaluated()) {
89+
Tracker tracker;
90+
operation_state auto state = connect(execution::just(5), throws_on_set_values_receiver<int>{tracker});
91+
assert(!tracker.set_values_called);
92+
assert(!tracker.set_error_called);
93+
start(state);
94+
assert(tracker.set_values_called);
95+
assert(tracker.set_error_called);
96+
}
97+
98+
return true;
99+
}
100+
101+
int main() {
102+
test_just();
103+
static_assert(test_just());
104+
}

0 commit comments

Comments
 (0)