16 #if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
18 using generator_future_int_type = copp::generator_future<int>;
19 using generator_future_void_type = copp::generator_future<void>;
22 std::list<generator_future_int_type::context_pointer_type> g_pending_int_contexts;
23 std::list<generator_future_void_type::context_pointer_type> g_pending_void_contexts;
24 size_t g_resume_generator_count = 0;
25 size_t g_suspend_generator_count = 0;
27 size_t resume_pending_contexts(std::list<int> values,
int max_count = 32767) {
29 while (max_count > 0 && (!g_pending_int_contexts.empty() || !g_pending_void_contexts.empty())) {
31 if (!g_pending_int_contexts.empty()) {
32 auto ctx = *g_pending_int_contexts.begin();
33 g_pending_int_contexts.pop_front();
35 if (!values.empty()) {
36 int val = values.front();
44 }
else if (!g_pending_void_contexts.empty()) {
45 auto ctx = *g_pending_void_contexts.begin();
46 g_pending_void_contexts.pop_front();
58 static copp::callable_future<int> callable_func_await_int() {
59 generator_future_int_type gen_left_value{
60 [](generator_future_int_type::context_pointer_type ctx) {
61 ++g_suspend_generator_count;
62 g_pending_int_contexts.push_back(ctx);
64 [](
const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
69 CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
70 int x1 = co_await gen_left_value;
73 CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kDone);
79 int x2 = co_await generator_future_int_type{
80 [](generator_future_int_type::context_pointer_type ctx) {
81 ++g_suspend_generator_count;
82 g_pending_int_contexts.push_back(ctx);
84 [](
const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
86 generator_future_void_type gen_left_void{
87 [](generator_future_void_type::context_pointer_type ctx) {
88 ++g_suspend_generator_count;
89 g_pending_void_contexts.push_back(ctx);
91 [](
const generator_future_void_type::context_type &) { ++g_resume_generator_count; }};
96 CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
97 co_await gen_left_void;
100 CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kDone);
103 co_await gen_left_void;
106 co_await generator_future_void_type{
107 [](generator_future_void_type::context_pointer_type ctx) {
108 ++g_suspend_generator_count;
109 g_pending_void_contexts.push_back(ctx);
111 [](
const generator_future_void_type::context_type &) { ++g_resume_generator_count; }};
116 CASE_TEST(generator_promise, basic_int_generator) {
117 size_t old_resume_generator_count = g_resume_generator_count;
118 size_t old_suspend_generator_count = g_suspend_generator_count;
120 copp::callable_future<int> f = callable_func_await_int();
122 CASE_EXPECT_NE(
static_cast<int>(copp::promise_status::kDone),
static_cast<int>(f.get_status()));
125 resume_pending_contexts({13100, 13});
130 CASE_EXPECT_EQ(old_resume_generator_count + 4, g_resume_generator_count);
131 CASE_EXPECT_EQ(old_suspend_generator_count + 4, g_suspend_generator_count);
134 static copp::callable_future<int> callable_func_await_int_killed() {
135 generator_future_int_type gen_left_value{[](generator_future_int_type::context_pointer_type ctx) {
136 ++g_suspend_generator_count;
137 g_pending_int_contexts.push_back(ctx);
139 [](
const generator_future_int_type::context_type &ctx) {
142 ++g_resume_generator_count;
148 CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
149 int x1 = co_await gen_left_value;
152 CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
154 auto current_callable_status = co_yield copp::callable_future<int>::yield_status();
158 co_await gen_left_value;
160 generator_future_void_type gen_left_void{[](generator_future_void_type::context_pointer_type ctx) {
161 ++g_suspend_generator_count;
162 g_pending_void_contexts.push_back(ctx);
164 [](
const generator_future_void_type::context_type &ctx) {
167 ++g_resume_generator_count;
173 CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
174 co_await gen_left_void;
177 CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
182 static copp::callable_future<void> callable_func_await_void_killed() {
183 generator_future_void_type gen_left_void{[](generator_future_void_type::context_pointer_type ctx) {
184 ++g_suspend_generator_count;
185 g_pending_void_contexts.push_back(ctx);
187 [](
const generator_future_void_type::context_type &ctx) {
190 ++g_resume_generator_count;
196 CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
197 co_await gen_left_void;
200 CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
203 co_await gen_left_void;
205 generator_future_int_type gen_left_value{[](generator_future_int_type::context_pointer_type ctx) {
206 ++g_suspend_generator_count;
207 g_pending_int_contexts.push_back(ctx);
209 [](
const generator_future_int_type::context_type &ctx) {
212 ++g_resume_generator_count;
218 CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
219 co_await gen_left_value;
222 CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
224 auto current_callable_status = co_yield copp::callable_future<int>::yield_status();
230 CASE_TEST(generator_promise, caller_killed) {
232 size_t old_resume_generator_count = g_resume_generator_count;
233 size_t old_suspend_generator_count = g_suspend_generator_count;
235 copp::callable_future<int> f = callable_func_await_int_killed();
238 f.kill(copp::promise_status::kKilled,
true);
241 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
242 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
246 size_t old_resume_generator_count = g_resume_generator_count;
247 size_t old_suspend_generator_count = g_suspend_generator_count;
249 copp::callable_future<void> f = callable_func_await_void_killed();
252 f.kill(copp::promise_status::kKilled,
true);
255 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
256 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
259 resume_pending_contexts({});
262 static copp::callable_future<int> callable_func_await_int_killed_by_destroy_generator(
263 std::unique_ptr<generator_future_int_type> &gen_left_value) {
264 gen_left_value.reset(
new generator_future_int_type(
265 [](generator_future_int_type::context_pointer_type) {
266 ++g_suspend_generator_count;
270 [](
const generator_future_int_type::context_type &ctx) {
272 CASE_EXPECT_EQ(*ctx.data(), -
static_cast<int>(copp::promise_status::kKilled));
273 ++g_resume_generator_count;
279 CASE_EXPECT_TRUE(gen_left_value->get_status() == copp::promise_status::kRunning);
280 int x1 = co_await *gen_left_value;
283 CASE_EXPECT_EQ(x1, -
static_cast<int>(copp::promise_status::kKilled));
288 CASE_TEST(generator_promise, caller_killed_by_destroy_generator) {
289 std::unique_ptr<generator_future_int_type> gen_left_value;
291 size_t old_resume_generator_count = g_resume_generator_count;
292 size_t old_suspend_generator_count = g_suspend_generator_count;
294 copp::callable_future<int> f = callable_func_await_int_killed_by_destroy_generator(gen_left_value);
297 gen_left_value.reset();
300 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
301 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
304 static copp::callable_future<int> callable_func_await_int_killed_by_destroy_generator_in_callback(
305 std::unique_ptr<generator_future_int_type> &gen_left_value) {
306 gen_left_value.reset(
new generator_future_int_type(
307 [&gen_left_value](generator_future_int_type::context_pointer_type) {
308 ++g_suspend_generator_count;
312 gen_left_value.reset();
314 [](
const generator_future_int_type::context_type &ctx) {
316 CASE_EXPECT_EQ(*ctx.data(), -
static_cast<int>(copp::promise_status::kKilled));
317 ++g_resume_generator_count;
323 CASE_EXPECT_TRUE(gen_left_value->get_status() == copp::promise_status::kRunning);
324 int x1 = co_await *gen_left_value;
327 CASE_EXPECT_EQ(x1, -
static_cast<int>(copp::promise_status::kKilled));
332 CASE_TEST(generator_promise, caller_killed_by_destroy_generator_in_callback) {
333 std::unique_ptr<generator_future_int_type> gen_left_value;
335 size_t old_resume_generator_count = g_resume_generator_count;
336 size_t old_suspend_generator_count = g_suspend_generator_count;
338 copp::callable_future<int> f = callable_func_await_int_killed_by_destroy_generator_in_callback(gen_left_value);
343 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
344 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
347 class test_context_transform_error_code_type {
351 test_context_transform_error_code_type() : code(0) {}
352 test_context_transform_error_code_type(
int c) : code(c) {}
353 test_context_transform_error_code_type(
const test_context_transform_error_code_type &) =
default;
354 test_context_transform_error_code_type &operator=(
const test_context_transform_error_code_type &) =
default;
355 test_context_transform_error_code_type(test_context_transform_error_code_type &&) =
default;
356 test_context_transform_error_code_type &operator=(test_context_transform_error_code_type &&) =
default;
357 ~test_context_transform_error_code_type() {}
360 LIBCOPP_COPP_NAMESPACE_BEGIN
362 struct promise_error_transform<test_context_transform_error_code_type> {
363 using type = test_context_transform_error_code_type;
364 type operator()(promise_status in)
const {
365 if (in == promise_status::kTimeout) {
366 return test_context_transform_error_code_type{-500};
368 return test_context_transform_error_code_type{
static_cast<int>(in)};
371 LIBCOPP_COPP_NAMESPACE_END
374 using test_context_transform_error_code_generator = copp::generator_future<test_context_transform_error_code_type>;
375 std::list<test_context_transform_error_code_generator::context_pointer_type>
376 g_test_context_transform_error_code_generator_executor;
378 static copp::callable_future<int> test_context_transform_error_code_generator_l2() {
379 auto result = co_await test_context_transform_error_code_generator{
380 [](test_context_transform_error_code_generator::context_pointer_type ctx) {
381 g_test_context_transform_error_code_generator_executor.emplace_back(std::move(ctx));
383 co_return result.code;
386 static copp::callable_future<void> test_context_transform_error_code_generator_l1() {
387 auto result = co_await test_context_transform_error_code_generator_l2();
393 CASE_TEST(generator_promise, transform_error_code) {
394 auto f2 = test_context_transform_error_code_generator_l1();
395 f2.kill(copp::promise_status::kTimeout,
true);
397 g_test_context_transform_error_code_generator_executor.clear();
400 static copp::callable_future<int> callable_func_multiple_await_int(generator_future_int_type &shared_generator) {
401 auto result = co_await shared_generator;
405 CASE_TEST(generator_promise, miltiple_wait_int_generator) {
406 size_t old_resume_generator_count = g_resume_generator_count;
407 size_t old_suspend_generator_count = g_suspend_generator_count;
409 generator_future_int_type int_generator{
410 [](generator_future_int_type::context_pointer_type ctx) {
411 ++g_suspend_generator_count;
412 if (g_pending_int_contexts.end() ==
413 std::find(g_pending_int_contexts.begin(), g_pending_int_contexts.end(), ctx)) {
414 g_pending_int_contexts.push_back(ctx);
417 [](
const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
419 copp::callable_future<int> f1 = callable_func_multiple_await_int(int_generator);
420 copp::callable_future<int> f2 = callable_func_multiple_await_int(int_generator);
422 CASE_EXPECT_NE(
static_cast<int>(copp::promise_status::kDone),
static_cast<int>(f1.get_status()));
424 CASE_EXPECT_NE(
static_cast<int>(copp::promise_status::kDone),
static_cast<int>(f2.get_status()));
434 CASE_EXPECT_EQ(old_resume_generator_count + 2, g_resume_generator_count);
435 CASE_EXPECT_EQ(old_suspend_generator_count + 2, g_suspend_generator_count);
438 static copp::callable_future<int> callable_func_resume_when_suspend() {
439 auto result = co_await generator_future_int_type{
440 [](generator_future_int_type::context_pointer_type ctx) {
441 ++g_suspend_generator_count;
444 [](
const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
448 CASE_TEST(generator_promise, resume_when_suspend) {
449 size_t old_resume_generator_count = g_resume_generator_count;
450 size_t old_suspend_generator_count = g_suspend_generator_count;
452 copp::callable_future<int> f1 = callable_func_resume_when_suspend();
454 CASE_EXPECT_EQ(
static_cast<int>(copp::promise_status::kDone),
static_cast<int>(f1.get_status()));
458 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
459 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
462 static copp::callable_future<int> callable_func_some_generator_in_container(
size_t expect_ready_count,
463 copp::promise_status expect_status) {
464 size_t old_resume_generator_count = g_resume_generator_count;
465 size_t old_suspend_generator_count = g_suspend_generator_count;
467 size_t resume_ready_count = 0;
468 auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
469 ++g_suspend_generator_count;
470 g_pending_int_contexts.push_back(ctx);
472 auto resume_callback = [&resume_ready_count](
const generator_future_int_type::context_type &ctx) {
473 ++g_resume_generator_count;
474 if (ctx.is_ready()) {
475 ++resume_ready_count;
479 std::vector<generator_future_int_type> generators;
480 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
481 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
482 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
484 copp::some_ready<generator_future_int_type>::type readys;
485 auto some_result = co_await copp::some(readys, 2, generators);
486 CASE_EXPECT_EQ(
static_cast<int>(expect_status),
static_cast<int>(some_result));
489 for (
auto &ready_generator : readys) {
490 result += *ready_generator->get_context()->data();
493 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
494 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
498 some_result = co_await copp::some(readys, 2, generators);
499 CASE_EXPECT_EQ(
static_cast<int>(expect_status),
static_cast<int>(some_result));
502 if (expect_status > copp::promise_status::kDone) {
503 CASE_EXPECT_EQ(old_resume_generator_count + 6 - resume_ready_count, g_resume_generator_count);
504 CASE_EXPECT_EQ(old_suspend_generator_count + 6 - resume_ready_count, g_suspend_generator_count);
507 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
508 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
515 CASE_TEST(generator_promise, finish_some_in_container) {
516 auto f = callable_func_some_generator_in_container(2, copp::promise_status::kDone);
521 resume_pending_contexts({471}, 1);
523 resume_pending_contexts({473}, 1);
528 resume_pending_contexts({});
531 CASE_TEST(generator_promise, kill_some_in_container) {
532 auto f = callable_func_some_generator_in_container(0, copp::promise_status::kKilled);
542 resume_pending_contexts({});
545 static copp::callable_future<int> callable_func_some_generator_in_initialize_list(
size_t expect_ready_count,
546 copp::promise_status expect_status) {
547 size_t old_resume_generator_count = g_resume_generator_count;
548 size_t old_suspend_generator_count = g_suspend_generator_count;
550 size_t resume_ready_count = 0;
551 auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
552 ++g_suspend_generator_count;
553 g_pending_int_contexts.push_back(ctx);
555 auto resume_callback = [&resume_ready_count](
const generator_future_int_type::context_type &ctx) {
556 ++g_resume_generator_count;
557 if (ctx.is_ready()) {
558 ++resume_ready_count;
562 generator_future_int_type gen1{suspend_callback, resume_callback};
563 generator_future_int_type gen2{suspend_callback, resume_callback};
564 generator_future_int_type gen3{suspend_callback, resume_callback};
566 copp::some_ready<generator_future_int_type>::type readys;
567 std::array<std::reference_wrapper<generator_future_int_type>, 3> pending = {gen1, gen2, gen3};
569 CASE_EXPECT_EQ(
static_cast<int>(expect_status),
static_cast<int>(some_result));
572 for (
auto &ready_generator : readys) {
573 result += *ready_generator->get_context()->data();
576 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
577 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
583 CASE_TEST(generator_promise, finish_some_in_initialize_list) {
584 auto f = callable_func_some_generator_in_initialize_list(2, copp::promise_status::kDone);
589 resume_pending_contexts({471}, 1);
591 resume_pending_contexts({473}, 1);
596 resume_pending_contexts({});
599 static copp::callable_future<int> callable_func_any_generator_in_container(
size_t expect_ready_count,
600 copp::promise_status expect_status) {
601 size_t old_resume_generator_count = g_resume_generator_count;
602 size_t old_suspend_generator_count = g_suspend_generator_count;
604 size_t resume_ready_count = 0;
605 auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
606 ++g_suspend_generator_count;
607 g_pending_int_contexts.push_back(ctx);
609 auto resume_callback = [&resume_ready_count](
const generator_future_int_type::context_type &ctx) {
610 ++g_resume_generator_count;
611 if (ctx.is_ready()) {
612 ++resume_ready_count;
616 std::vector<generator_future_int_type> generators;
617 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
618 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
619 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
621 copp::any_ready<generator_future_int_type>::type readys;
622 auto any_result = co_await copp::any(readys, generators);
623 CASE_EXPECT_EQ(
static_cast<int>(expect_status),
static_cast<int>(any_result));
626 for (
auto &ready_generator : readys) {
627 result += *ready_generator->get_context()->data();
630 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
631 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
635 std::vector<copp::gsl::not_null<generator_future_int_type *>> generators_not_null_type;
636 for (
auto &generator : generators) {
639 any_result = co_await copp::any(readys, generators_not_null_type);
640 CASE_EXPECT_EQ(
static_cast<int>(expect_status),
static_cast<int>(any_result));
643 if (expect_status > copp::promise_status::kDone) {
644 CASE_EXPECT_EQ(old_resume_generator_count + 6 - resume_ready_count, g_resume_generator_count);
645 CASE_EXPECT_EQ(old_suspend_generator_count + 6 - resume_ready_count, g_suspend_generator_count);
648 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
649 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
656 CASE_TEST(generator_promise, finish_any_in_container) {
657 auto f = callable_func_any_generator_in_container(1, copp::promise_status::kDone);
662 resume_pending_contexts({671}, 1);
667 resume_pending_contexts({});
670 static copp::callable_future<int> callable_func_all_generator_in_container(
size_t expect_ready_count,
671 copp::promise_status expect_status) {
672 size_t old_resume_generator_count = g_resume_generator_count;
673 size_t old_suspend_generator_count = g_suspend_generator_count;
675 size_t resume_ready_count = 0;
676 auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
677 ++g_suspend_generator_count;
678 g_pending_int_contexts.push_back(ctx);
680 auto resume_callback = [&resume_ready_count](
const generator_future_int_type::context_type &ctx) {
681 ++g_resume_generator_count;
682 if (ctx.is_ready()) {
683 ++resume_ready_count;
687 std::vector<generator_future_int_type> generators;
688 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
689 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
690 generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
692 copp::all_ready<generator_future_int_type>::type readys;
693 auto all_result = co_await copp::all(readys, generators);
694 CASE_EXPECT_EQ(
static_cast<int>(expect_status),
static_cast<int>(all_result));
697 for (
auto &ready_generator : readys) {
698 result += *ready_generator->get_context()->data();
701 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
702 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
706 all_result = co_await copp::all(readys, generators);
707 CASE_EXPECT_EQ(
static_cast<int>(expect_status),
static_cast<int>(all_result));
710 if (expect_status > copp::promise_status::kDone) {
711 CASE_EXPECT_EQ(old_resume_generator_count + 6 - resume_ready_count, g_resume_generator_count);
712 CASE_EXPECT_EQ(old_suspend_generator_count + 6 - resume_ready_count, g_suspend_generator_count);
715 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
716 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
723 CASE_TEST(generator_promise, finish_all_in_container) {
724 auto f = callable_func_all_generator_in_container(3, copp::promise_status::kDone);
729 resume_pending_contexts({671}, 1);
732 resume_pending_contexts({791, 793}, 2);
737 resume_pending_contexts({});
CASE_TEST(generator_promise, disabled)
auto make_not_null(T &&t) noexcept
constexpr span< TELEMENT > make_span(TELEMENT *ptr, typename span< TELEMENT >::size_type count)
#define CASE_EXPECT_FALSE(c)
#define CASE_EXPECT_EQ(l, r)
#define CASE_EXPECT_NE(l, r)
#define CASE_EXPECT_TRUE(c)