Skip to content

Commit 78a2c3f

Browse files
committed
WIP
1 parent 5d4d76d commit 78a2c3f

1 file changed

Lines changed: 136 additions & 43 deletions

File tree

  • tests/std/tests/P2300R2_executors_adaptors_on

tests/std/tests/P2300R2_executors_adaptors_on/test.cpp

Lines changed: 136 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4+
#include <atomic>
45
#include <cassert>
6+
#include <chrono>
57
#include <execution>
8+
#include <thread>
9+
610
using namespace std;
711
using execution::receiver, execution::scheduler, execution::sender;
812

13+
atomic<bool> scheduled_start_has_finished = false;
14+
atomic<bool> delayed_start_has_finished = false;
15+
916
struct CustomError {};
10-
enum class CanTagInvokeOn { No, NoSender, Yes };
11-
enum class OnStartDoes { Nothing, SetValues, SetError, SetDone };
17+
enum class CanTagInvokeOn { No, Yes };
18+
enum class OnStartDoes { Nothing, SetValues, SetError, SetDone, SetValuesDelayed, SetErrorDelayed, SetDoneDelayed };
1219
template <CanTagInvokeOn TagInvokeOn, OnStartDoes OnStart = OnStartDoes::Nothing>
1320
struct sender_on : public execution::sender_base {
1421
int _id = 0;
@@ -31,13 +38,47 @@ struct sender_on : public execution::sender_base {
3138
friend constexpr void tag_invoke(execution::start_t, sender_on_state& state) noexcept {
3239
++state._id;
3340
if constexpr (OnStart == OnStartDoes::SetValues) {
34-
tag_invoke(execution::set_value, state._rec, state._id);
41+
tag_invoke(execution::set_value, move(state._rec), state._id);
3542
} else if constexpr (OnStart == OnStartDoes::SetError) {
36-
tag_invoke(execution::set_error, state._rec, CustomError{});
43+
tag_invoke(execution::set_error, move(state._rec), CustomError{});
3744
} else if constexpr (OnStart == OnStartDoes::SetDone) {
38-
tag_invoke(execution::set_done, state._rec);
45+
tag_invoke(execution::set_done, move(state._rec));
46+
} else if constexpr (OnStart == OnStartDoes::SetValuesDelayed) {
47+
if (is_constant_evaluated()) {
48+
tag_invoke(execution::set_value, move(state._rec), state._id);
49+
} else {
50+
delayed_start(state);
51+
}
52+
} else if constexpr (OnStart == OnStartDoes::SetErrorDelayed) {
53+
if (is_constant_evaluated()) {
54+
tag_invoke(execution::set_error, move(state._rec), CustomError{});
55+
} else {
56+
delayed_start(state);
57+
}
58+
} else if constexpr (OnStart == OnStartDoes::SetDoneDelayed) {
59+
if (is_constant_evaluated()) {
60+
tag_invoke(execution::set_done, move(state._rec));
61+
} else {
62+
delayed_start(state);
63+
}
3964
}
4065
}
66+
67+
static void delayed_start(sender_on_state& state) noexcept {
68+
thread([&state]() {
69+
scheduled_start_has_finished.wait(false);
70+
this_thread::sleep_for(1000ms);
71+
if constexpr (OnStart == OnStartDoes::SetValuesDelayed) {
72+
tag_invoke(execution::set_value, move(state._rec), state._id);
73+
} else if constexpr (OnStart == OnStartDoes::SetErrorDelayed) {
74+
tag_invoke(execution::set_error, move(state._rec), CustomError{});
75+
} else if constexpr (OnStart == OnStartDoes::SetDoneDelayed) {
76+
tag_invoke(execution::set_done, move(state._rec));
77+
}
78+
delayed_start_has_finished.store(true);
79+
delayed_start_has_finished.notify_all();
80+
}).detach();
81+
}
4182
};
4283

4384
template <receiver Receiver>
@@ -113,8 +154,45 @@ struct scheduler_on {
113154
tag_invoke(execution::set_error, move(state._rec), CustomError{});
114155
} else if constexpr (OnStart == OnStartDoes::SetDone) {
115156
tag_invoke(execution::set_done, move(state._rec));
157+
} else if constexpr (OnStart == OnStartDoes::SetValuesDelayed) {
158+
if (is_constant_evaluated()) {
159+
tag_invoke(execution::set_value, move(state._rec));
160+
} else {
161+
delayed_start(state);
162+
}
163+
} else if constexpr (OnStart == OnStartDoes::SetErrorDelayed) {
164+
if (is_constant_evaluated()) {
165+
tag_invoke(execution::set_error, move(state._rec), CustomError{});
166+
} else {
167+
delayed_start(state);
168+
}
169+
} else if constexpr (OnStart == OnStartDoes::SetDoneDelayed) {
170+
if (is_constant_evaluated()) {
171+
tag_invoke(execution::set_done, move(state._rec));
172+
} else {
173+
delayed_start(state);
174+
}
116175
}
117176
}
177+
178+
static void delayed_start(sender_scheduled_state& state) noexcept {
179+
thread([&state]() {
180+
this_thread::sleep_for(1000ms);
181+
if constexpr (OnStart == OnStartDoes::SetValuesDelayed) {
182+
tag_invoke(execution::set_value, move(state._rec));
183+
} else if constexpr (OnStart == OnStartDoes::SetErrorDelayed) {
184+
tag_invoke(execution::set_error, move(state._rec), CustomError{});
185+
delayed_start_has_finished.store(true); // we never call start on the inner sender so fake it
186+
delayed_start_has_finished.notify_all();
187+
} else if constexpr (OnStart == OnStartDoes::SetDoneDelayed) {
188+
tag_invoke(execution::set_done, move(state._rec));
189+
delayed_start_has_finished.store(true); // we never call start on the inner sender so fake it
190+
delayed_start_has_finished.notify_all();
191+
}
192+
scheduled_start_has_finished.store(true);
193+
scheduled_start_has_finished.notify_all();
194+
}).detach();
195+
}
118196
};
119197

120198
template <receiver Receiver>
@@ -134,37 +212,26 @@ static_assert(scheduler<scheduler_on<OnStartDoes::SetValues>>);
134212
static_assert(scheduler<scheduler_on<OnStartDoes::SetError>>);
135213
static_assert(scheduler<scheduler_on<OnStartDoes::SetDone>>);
136214

137-
template <OnStartDoes OnStart>
138-
constexpr void test_with_tag_invoke() {
215+
template <CanTagInvokeOn WithTagInvoke, OnStartDoes OnStart>
216+
constexpr void test_all() {
217+
if (!is_constant_evaluated()) {
218+
scheduled_start_has_finished.store(WithTagInvoke == CanTagInvokeOn::Yes);
219+
delayed_start_has_finished.store(false);
220+
}
221+
139222
receiver_tracker tracker;
140-
sender auto new_sender = execution::on(scheduler_on<OnStart>{}, sender_on<CanTagInvokeOn::Yes, OnStart>{});
223+
sender auto new_sender = execution::on(scheduler_on<OnStart>{}, sender_on<WithTagInvoke, OnStart>{});
141224
execution::operation_state auto new_state = execution::connect(new_sender, receiver_on{tracker});
142225

143-
assert(new_sender._id == 1);
144-
assert(new_state._id == 2);
145-
execution::start(new_state);
146-
assert(new_state._id == 3);
147-
if constexpr (OnStart == OnStartDoes::Nothing) {
148-
assert(tracker.nothing_called());
149-
} else if constexpr (OnStart == OnStartDoes::SetValues) {
150-
assert(tracker.set_value_called());
151-
} else if constexpr (OnStart == OnStartDoes::SetError) {
152-
assert(tracker.set_error_called());
153-
} else if constexpr (OnStart == OnStartDoes::SetDone) {
154-
assert(tracker.set_done_called());
226+
if constexpr (WithTagInvoke == CanTagInvokeOn::Yes) {
227+
assert(new_sender._id == 1);
228+
assert(new_state._id == 2);
155229
}
156230

157-
static_assert(same_as<decltype(new_sender), sender_on<CanTagInvokeOn::Yes, OnStart>>);
158-
static_assert(same_as<decltype(new_state),
159-
typename sender_on<CanTagInvokeOn::Yes, OnStart>::template sender_on_state<receiver_on>>);
160-
}
161-
162-
template <OnStartDoes OnStart>
163-
constexpr void test_without_tag_invoke() {
164-
receiver_tracker tracker;
165-
sender auto new_sender = execution::on(scheduler_on<OnStart>{}, sender_on<CanTagInvokeOn::No, OnStart>{});
166-
execution::operation_state auto new_state = execution::connect(new_sender, receiver_on{tracker});
167231
execution::start(new_state);
232+
if constexpr (WithTagInvoke == CanTagInvokeOn::Yes) {
233+
assert(new_state._id == 3);
234+
}
168235

169236
if constexpr (OnStart == OnStartDoes::Nothing) {
170237
assert(tracker.nothing_called());
@@ -174,24 +241,50 @@ constexpr void test_without_tag_invoke() {
174241
assert(tracker.set_error_called());
175242
} else if constexpr (OnStart == OnStartDoes::SetDone) {
176243
assert(tracker.set_done_called());
244+
} else if constexpr (OnStart == OnStartDoes::SetValuesDelayed) {
245+
if (!is_constant_evaluated()) {
246+
delayed_start_has_finished.wait(false);
247+
}
248+
assert(tracker.set_value_called());
249+
} else if constexpr (OnStart == OnStartDoes::SetErrorDelayed) {
250+
if (!is_constant_evaluated()) {
251+
delayed_start_has_finished.wait(false);
252+
}
253+
assert(tracker.set_error_called());
254+
} else if constexpr (OnStart == OnStartDoes::SetDoneDelayed) {
255+
if (!is_constant_evaluated()) {
256+
delayed_start_has_finished.wait(false);
257+
}
258+
assert(tracker.set_done_called());
177259
}
178260

179-
static_assert(same_as<decltype(new_sender),
180-
execution::_On::_OutputSender<scheduler_on<OnStart>, sender_on<CanTagInvokeOn::No, OnStart>>>);
181-
static_assert(same_as<decltype(new_state), execution::_On::_OutputSenderState<scheduler_on<OnStart>,
182-
sender_on<CanTagInvokeOn::No, OnStart>, receiver_on>>);
261+
if constexpr (WithTagInvoke == CanTagInvokeOn::Yes) {
262+
static_assert(same_as<decltype(new_sender), sender_on<WithTagInvoke, OnStart>>);
263+
static_assert(same_as<decltype(new_state),
264+
typename sender_on<WithTagInvoke, OnStart>::template sender_on_state<receiver_on>>);
265+
} else {
266+
static_assert(same_as<decltype(new_sender),
267+
execution::_On::_OutputSender<scheduler_on<OnStart>, sender_on<CanTagInvokeOn::No, OnStart>>>);
268+
static_assert(same_as<decltype(new_state), execution::_On::_OutputSenderState<scheduler_on<OnStart>,
269+
sender_on<CanTagInvokeOn::No, OnStart>, receiver_on>>);
270+
}
183271
}
184272

185273
constexpr bool test_on() {
186-
test_with_tag_invoke<OnStartDoes::Nothing>();
187-
test_with_tag_invoke<OnStartDoes::SetValues>();
188-
test_with_tag_invoke<OnStartDoes::SetError>();
189-
test_with_tag_invoke<OnStartDoes::SetDone>();
190-
191-
test_without_tag_invoke<OnStartDoes::Nothing>();
192-
test_without_tag_invoke<OnStartDoes::SetValues>();
193-
test_without_tag_invoke<OnStartDoes::SetError>();
194-
test_without_tag_invoke<OnStartDoes::SetDone>();
274+
test_all<CanTagInvokeOn::Yes, OnStartDoes::Nothing>();
275+
test_all<CanTagInvokeOn::Yes, OnStartDoes::SetValues>();
276+
test_all<CanTagInvokeOn::Yes, OnStartDoes::SetError>();
277+
test_all<CanTagInvokeOn::Yes, OnStartDoes::SetDone>();
278+
test_all<CanTagInvokeOn::Yes, OnStartDoes::SetValuesDelayed>();
279+
test_all<CanTagInvokeOn::Yes, OnStartDoes::SetErrorDelayed>();
280+
test_all<CanTagInvokeOn::Yes, OnStartDoes::SetDoneDelayed>();
281+
282+
test_all<CanTagInvokeOn::No, OnStartDoes::Nothing>();
283+
test_all<CanTagInvokeOn::No, OnStartDoes::SetValues>();
284+
test_all<CanTagInvokeOn::No, OnStartDoes::SetError>();
285+
test_all<CanTagInvokeOn::No, OnStartDoes::SetDone>();
286+
test_all<CanTagInvokeOn::No, OnStartDoes::SetValuesDelayed>();
287+
test_all<CanTagInvokeOn::No, OnStartDoes::SetErrorDelayed>();
195288

196289
return true;
197290
}

0 commit comments

Comments
 (0)