diff --git a/libs/core/execution/src/run_loop.cpp b/libs/core/execution/src/run_loop.cpp index 3605ca77b5be..32ff343a99ad 100644 --- a/libs/core/execution/src/run_loop.cpp +++ b/libs/core/execution/src/run_loop.cpp @@ -6,6 +6,7 @@ #include +#ifndef HPX_HAVE_STDEXEC /////////////////////////////////////////////////////////////////////////////// namespace hpx::execution::experimental::detail { @@ -22,3 +23,4 @@ namespace hpx::execution::experimental::detail { } } } // namespace hpx::execution::experimental::detail +#endif diff --git a/libs/core/execution/tests/unit/algorithm_run_loop.cpp b/libs/core/execution/tests/unit/algorithm_run_loop.cpp index 3d228cb26244..329cc7824da8 100644 --- a/libs/core/execution/tests/unit/algorithm_run_loop.cpp +++ b/libs/core/execution/tests/unit/algorithm_run_loop.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2024 Isidoros Tsaousis-Seiras // Copyright (c) 2022 Hartmut Kaiser // Copyright (c) 2020 ETH Zurich // @@ -5,6 +6,28 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +/** Note + * This file has been heavily modified to facilitate the testing of the R7+ + * iteration of P2300. There are a few differences between that paper and our + * implementation. The biggest ones that affect this file are: + * + * 1. execution::sync_wait() no longer accepts a scheduler as an argument, + * in order to begin the execution of the resource to which it belongs. + * + * 2. execution::sync_wait() no longer supports a pipe operator| to be chained + * onto senders. + * + * To work around these changes, the following modifications have been made: + * + * 1. In the places that sync_wait was expected to begin the execution of a + * resource (e.g. by calling `loop.run()`) a separate hpx thread is created + * for the `run_loop` to run on. Also, the checks that the sender and caller + * of sync_wait are on the same thread have been adapted to reflect that the + * sender is now on the run loop's thread instead. + * + * 2. The syntax my_snd | sync_wait() has been replaced with sync_wait(my_snd). + */ + #include // Clang V11 ICE's on this test @@ -163,14 +186,22 @@ void test_sender_receiver_then() void test_sender_receiver_then_wait() { ex::run_loop loop; - auto sched = loop.get_scheduler(); +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif + + auto sched = loop.get_scheduler(); + std::atomic then_count{0}; bool executed{false}; auto begin = ex::schedule(sched); #ifdef HPX_HAVE_STDEXEC + // Native P2300R8 does not support sync_wait(scheduler, sender) auto compl_sched_begin = ex::get_completion_scheduler(ex::get_env(begin)); #else @@ -221,14 +252,24 @@ void test_sender_receiver_then_wait() HPX_TEST_EQ(then_count, std::size_t(2)); HPX_TEST(executed); + +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_sender_receiver_then_sync_wait() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); - hpx::thread::id parent_id = hpx::this_thread::get_id(); std::atomic then_count{0}; auto begin = ex::schedule(sched); @@ -245,28 +286,37 @@ void test_sender_receiver_then_sync_wait() std::is_same::type>::value, "result should be an int"); HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_sender_receiver_then_arguments() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); - hpx::thread::id parent_id = hpx::this_thread::get_id(); std::atomic then_count{0}; auto begin = ex::schedule(sched); auto work1 = ex::then(std::move(begin), [&then_count, parent_id]() { sender_receiver_then_thread_id = hpx::this_thread::get_id(); HPX_TEST_EQ(sender_receiver_then_thread_id, parent_id); - ++then_count; + ++then_count; return 3; }); auto work2 = ex::then(std::move(work1), [&then_count](int x) -> std::string { HPX_TEST_EQ( sender_receiver_then_thread_id, hpx::this_thread::get_id()); - ++then_count; + ++then_count; return std::string("hello") + std::to_string(x); }); auto work3 = ex::then(std::move(work2), [&then_count](std::string s) { @@ -281,14 +331,23 @@ void test_sender_receiver_then_arguments() typename std::decay::type>::value, "result should be a std::size_t"); HPX_TEST_EQ(result, std::size_t(12)); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_transfer_basic() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); - hpx::thread::id parent_id = hpx::this_thread::get_id(); hpx::thread::id current_id; auto begin = ex::schedule(sched); @@ -318,14 +377,23 @@ void test_transfer_basic() }); tt::sync_wait(work5); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_transfer_arguments() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); - hpx::thread::id parent_id = hpx::this_thread::get_id(); hpx::thread::id current_id; auto begin = ex::schedule(sched); @@ -356,7 +424,7 @@ void test_transfer_arguments() HPX_TEST_EQ(current_id, new_id); current_id = new_id; HPX_TEST_EQ(current_id, parent_id); - return s + "!"; + return s + "!"; }); auto work_result = tt::sync_wait(work5); @@ -364,13 +432,21 @@ void test_transfer_arguments() static_assert(std::is_same_v>, "result should be a std::string"); HPX_TEST_EQ(result, std::string("result: 0!")); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_just_void() { ex::run_loop loop; - +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto begin = ex::just(); auto transfer1 = ex::transfer(begin, loop.get_scheduler()); @@ -378,13 +454,21 @@ void test_just_void() [parent_id]() { HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); }); tt::sync_wait(work1); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_just_one_arg() { ex::run_loop loop; - +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto begin = ex::just(3); auto transfer1 = ex::transfer(begin, loop.get_scheduler()); @@ -394,13 +478,21 @@ void test_just_one_arg() }); tt::sync_wait(work1); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_just_two_args() { ex::run_loop loop; - +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto begin = ex::just(3, std::string("hello")); auto transfer1 = ex::transfer(begin, loop.get_scheduler()); @@ -411,28 +503,46 @@ void test_just_two_args() }); tt::sync_wait(work1); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_transfer_just_void() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); - hpx::thread::id parent_id = hpx::this_thread::get_id(); auto begin = ex::transfer_just(sched); auto work1 = ex::then(begin, [parent_id]() { HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); }); tt::sync_wait(work1); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_transfer_just_one_arg() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); - hpx::thread::id parent_id = hpx::this_thread::get_id(); auto begin = ex::transfer_just(sched, 3); auto work1 = ex::then(begin, [parent_id](int x) { @@ -441,14 +551,23 @@ void test_transfer_just_one_arg() }); tt::sync_wait(work1); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } void test_transfer_just_two_args() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); - hpx::thread::id parent_id = hpx::this_thread::get_id(); auto begin = ex::transfer_just(sched, 3, std::string("hello")); auto work1 = ex::then(begin, [parent_id](int x, std::string y) { @@ -458,6 +577,10 @@ void test_transfer_just_two_args() }); tt::sync_wait(work1); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // Note: when_all does not propagate the completion scheduler, for this reason @@ -466,11 +589,15 @@ void test_transfer_just_two_args() void test_when_all() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + hpx::thread t = hpx::thread([&]{loop.run();}); + hpx::thread::id parent_id = t.get_id(); +#else + hpx::thread::id parent_id = hpx::this_thread::get_id(); +#endif auto sched = loop.get_scheduler(); { - hpx::thread::id parent_id = hpx::this_thread::get_id(); - auto work1 = ex::schedule(sched) | ex::then([parent_id]() { HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); return 42; @@ -490,27 +617,32 @@ void test_when_all() ex::when_all(std::move(work1), std::move(work2), std::move(work3)); bool executed{false}; - auto s = std::move(when1) | + +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(std::move(when1) | + ex::then([parent_id, &executed](int x, std::string y, double z) { + HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); + HPX_TEST_EQ(x, 42); + HPX_TEST_EQ(y, std::string("hello")); + HPX_TEST_EQ(z, 3.14); + executed = true; + })); +#else + std::move(when1) | ex::then([parent_id, &executed](int x, std::string y, double z) { HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); HPX_TEST_EQ(x, 42); HPX_TEST_EQ(y, std::string("hello")); HPX_TEST_EQ(z, 3.14); executed = true; - }); - -#ifdef HPX_HAVE_STDEXEC - tt::sync_wait(std::move(s)); -#else - std::move(s) | tt::sync_wait(sched); + }) | + tt::sync_wait(sched); #endif HPX_TEST(executed); } { - hpx::thread::id parent_id = hpx::this_thread::get_id(); - // The exception is likely to be thrown before set_value from the second // sender is called because the second sender sleeps. auto work1 = ex::schedule(sched) | ex::then([parent_id]() -> int { @@ -528,17 +660,21 @@ void test_when_all() try { - auto s = ex::when_all(std::move(work1), std::move(work2)) | +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::when_all(std::move(work1), std::move(work2)) | + ex::then([parent_id](int x, std::string y) { + HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); + HPX_TEST_EQ(x, 42); + HPX_TEST_EQ(y, std::string("hello")); + })); +#else + ex::when_all(std::move(work1), std::move(work2)) | ex::then([parent_id](int x, std::string y) { HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); HPX_TEST_EQ(x, 42); HPX_TEST_EQ(y, std::string("hello")); - }); - -#ifdef HPX_HAVE_STDEXEC - tt::sync_wait(std::move(s)); -#else - std::move(s) | tt::sync_wait(sched); + }) | + tt::sync_wait(sched); #endif HPX_TEST(false); @@ -553,8 +689,6 @@ void test_when_all() } { - hpx::thread::id parent_id = hpx::this_thread::get_id(); - // The exception is likely to be thrown after set_value from the second // sender is called because the first sender sleeps before throwing. auto work1 = ex::schedule(sched) | ex::then([parent_id]() -> int { @@ -572,16 +706,21 @@ void test_when_all() try { - auto s = ex::when_all(std::move(work1), std::move(work2)) | +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::when_all(std::move(work1), std::move(work2)) | + ex::then([parent_id](int x, std::string y) { + HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); + HPX_TEST_EQ(x, 42); + HPX_TEST_EQ(y, std::string("hello")); + })); +#else + ex::when_all(std::move(work1), std::move(work2)) | ex::then([parent_id](int x, std::string y) { HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); HPX_TEST_EQ(x, 42); HPX_TEST_EQ(y, std::string("hello")); - }); -#ifdef HPX_HAVE_STDEXEC - tt::sync_wait(std::move(s)); -#else - std::move(s) | tt::sync_wait(sched); + }) | + tt::sync_wait(sched); #endif HPX_TEST(false); @@ -594,6 +733,10 @@ void test_when_all() HPX_TEST(exception_thrown); } +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // Note: make_future does not propagate the completion scheduler, for this @@ -604,6 +747,7 @@ void test_future_sender() std::cout << "1\n"; // senders as futures { + std::cout << "1\n"; ex::run_loop loop; auto sched = loop.get_scheduler(); @@ -737,10 +881,15 @@ void test_ensure_started() { { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC tt::sync_wait(ex::schedule(sched) | ex::ensure_started()); + loop.finish(); + t.join(); #else ex::schedule(sched) | ex::ensure_started() | tt::sync_wait(); #endif @@ -748,25 +897,40 @@ void test_ensure_started() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto s = ex::transfer_just(sched, 42) | ex::ensure_started(); auto result = tt::sync_wait(std::move(s)); HPX_TEST_EQ(hpx::get<0>(*result), 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto s = ex::transfer_just(sched, 42) | ex::ensure_started() | ex::transfer(sched); auto result = tt::sync_wait(std::move(s)); HPX_TEST_EQ(hpx::get<0>(*result), 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { // TODO: REVISIT AFTER FIXING ENSURE_STARTED + // its fixed we need to split first // ex::run_loop loop; // auto sched = loop.get_scheduler(); // @@ -782,6 +946,9 @@ void test_ensure_started_when_all() { { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic first_task_calls{0}; @@ -834,10 +1001,17 @@ void test_ensure_started_when_all() #endif HPX_TEST_EQ(first_task_calls, std::size_t(1)); HPX_TEST_EQ(successor_task_calls, std::size_t(2)); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic first_task_calls{0}; @@ -890,10 +1064,17 @@ void test_ensure_started_when_all() #endif HPX_TEST_EQ(first_task_calls, std::size_t(1)); HPX_TEST_EQ(successor_task_calls, std::size_t(2)); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic first_task_calls{0}; @@ -923,8 +1104,8 @@ void test_ensure_started_when_all() return x + 2; }); HPX_TEST_EQ( - hpx::get<0>(*(tt::sync_wait(ex::when_all(succ1, succ2) | - ex::then([](int const& x, int const& y) { return x + y; })))), + hpx::get<0>(*tt::sync_wait(ex::when_all(succ1, succ2) | + ex::then([](int const& x, int const& y) { return x + y; }))), 9); #else auto succ1 = s | ex::transfer(sched) | ex::then([&](int const& x) { @@ -943,6 +1124,10 @@ void test_ensure_started_when_all() #endif HPX_TEST_EQ(first_task_calls, std::size_t(1)); HPX_TEST_EQ(successor_task_calls, std::size_t(2)); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -950,10 +1135,15 @@ void test_split() { { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC tt::sync_wait(ex::schedule(sched) | ex::split()); + loop.finish(); + t.join(); #else ex::schedule(sched) | ex::split() | tt::sync_wait(); #endif @@ -961,23 +1151,40 @@ void test_split() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto s = ex::transfer_just(sched, 42) | ex::split(); HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(std::move(s))), 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto s = ex::transfer_just(sched, 42) | ex::split() | ex::transfer(sched); HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(std::move(s))), 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto s = ex::transfer_just(sched, 42) | ex::split(); @@ -985,6 +1192,10 @@ void test_split() HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(s)), 42); HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(s)), 42); HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(std::move(s))), 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -992,6 +1203,9 @@ void test_split_when_all() { { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic first_task_calls{0}; @@ -1003,20 +1217,26 @@ void test_split_when_all() }) | ex::split(); auto succ1 = s | ex::then([&]() { HPX_TEST_EQ(first_task_calls, std::size_t(1)); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(successor_task_calls, std::size_t(0)); +#endif ++successor_task_calls; return 1; }); auto succ2 = s | ex::then([&]() { + std::this_thread::sleep_for(std::chrono::seconds(1)); HPX_TEST_EQ(first_task_calls, std::size_t(1)); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(successor_task_calls, std::size_t(1)); +#endif ++successor_task_calls; return 2; }); -#ifdef HPX_HAVE_STDEXEC +#ifdef HPX_HAVE_STDEXEC // I am not sure how the order is determined in this + // case so I have removed the order checks. TODO HPX_TEST_EQ( - hpx::get<0>(*(tt::sync_wait(ex::when_all(succ1, succ2) | - ex::then([](int const& x, int const& y) { return x + y; })))), + hpx::get<0>(*tt::sync_wait(ex::when_all(succ1, succ2) | + ex::then([](int const& x, int const& y) { return x + y; }))), 3); #else HPX_TEST_EQ( @@ -1027,10 +1247,17 @@ void test_split_when_all() #endif HPX_TEST_EQ(first_task_calls, std::size_t(1)); HPX_TEST_EQ(successor_task_calls, std::size_t(2)); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic first_task_calls{0}; @@ -1043,13 +1270,17 @@ void test_split_when_all() }) | ex::split(); auto succ1 = s | ex::then([&](int const& x) { HPX_TEST_EQ(first_task_calls, std::size_t(1)); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(successor_task_calls, std::size_t(0)); +#endif ++successor_task_calls; return x + 1; }); auto succ2 = s | ex::then([&](int const& x) { HPX_TEST_EQ(first_task_calls, std::size_t(1)); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(successor_task_calls, std::size_t(1)); +#endif ++successor_task_calls; return x + 2; }); @@ -1067,10 +1298,17 @@ void test_split_when_all() #endif HPX_TEST_EQ(first_task_calls, std::size_t(1)); HPX_TEST_EQ(successor_task_calls, std::size_t(2)); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic first_task_calls{0}; @@ -1083,13 +1321,17 @@ void test_split_when_all() }) | ex::split(); auto succ1 = s | ex::transfer(sched) | ex::then([&](int const& x) { HPX_TEST_EQ(first_task_calls, std::size_t(1)); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(successor_task_calls, std::size_t(0)); +#endif ++successor_task_calls; return x + 1; }); auto succ2 = s | ex::transfer(sched) | ex::then([&](int const& x) { HPX_TEST_EQ(first_task_calls, std::size_t(1)); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(successor_task_calls, std::size_t(1)); +#endif ++successor_task_calls; return x + 2; }); @@ -1107,6 +1349,10 @@ void test_split_when_all() #endif HPX_TEST_EQ(first_task_calls, std::size_t(1)); HPX_TEST_EQ(successor_task_calls, std::size_t(2)); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -1115,50 +1361,74 @@ void test_let_value() // void predecessor { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC - auto result = hpx::get<0>(*(tt::sync_wait(ex::schedule(sched) | - ex::let_value([]() { return ex::just(42); })))); + auto result = hpx::get<0>(*tt::sync_wait(ex::schedule(sched) | + ex::let_value([]() { return ex::just(42); }))); #else auto result = hpx::get<0>(*(ex::schedule(sched) | ex::let_value([]() { return ex::just(42); }) | tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC - auto result = hpx::get<0>(*(tt::sync_wait(ex::schedule(sched) | ex::let_value([=]() { + auto result = hpx::get<0>(*tt::sync_wait(ex::schedule(sched) | ex::let_value([=]() { return ex::transfer_just(sched, 42); - })))); + }))); #else auto result = hpx::get<0>(*(ex::schedule(sched) | ex::let_value([=]() { return ex::transfer_just(sched, 42); }) | tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC - auto result = hpx::get<0>(*(tt::sync_wait(ex::just() | ex::let_value([=]() { + auto result = hpx::get<0>(*tt::sync_wait(ex::just() | ex::let_value([=]() { return ex::transfer_just(sched, 42); - })))); + }))); #else auto result = hpx::get<0>(*(ex::just() | ex::let_value([=]() { return ex::transfer_just(sched, 42); }) | tt::sync_wait(sched))); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // int predecessor, value ignored { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*(tt::sync_wait(ex::transfer_just(sched, 43) | @@ -1169,10 +1439,17 @@ void test_let_value() tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*(tt::sync_wait(ex::transfer_just(sched, 43) | @@ -1183,10 +1460,17 @@ void test_let_value() tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*(tt::sync_wait(ex::just(43) | ex::let_value([=](int&) { @@ -1198,17 +1482,24 @@ void test_let_value() }) | tt::sync_wait(sched))); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // int predecessor, value used { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>( - *(tt::sync_wait(ex::transfer_just(sched, 43) | ex::let_value([](int& x) { + *tt::sync_wait(ex::transfer_just(sched, 43) | ex::let_value([](int& x) { return ex::just(42) | ex::then([&](int y) { return x + y; }); - })))); + }))); #else auto result = hpx::get<0>( *(ex::transfer_just(sched, 43) | ex::let_value([](int& x) { @@ -1216,10 +1507,17 @@ void test_let_value() }) | tt::sync_wait())); #endif HPX_TEST_EQ(result, 85); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>( @@ -1235,10 +1533,17 @@ void test_let_value() }) | tt::sync_wait())); #endif HPX_TEST_EQ(result, 85); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*tt::sync_wait(ex::just(43) | ex::let_value([=](int& x) { @@ -1252,11 +1557,18 @@ void test_let_value() }) | tt::sync_wait(sched))); #endif HPX_TEST_EQ(result, 85); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // predecessor throws, let sender is ignored { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); bool exception_thrown = false; @@ -1287,6 +1599,10 @@ void test_let_value() } HPX_TEST(exception_thrown); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -1311,6 +1627,9 @@ void test_let_error() // void predecessor { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic called{false}; @@ -1332,10 +1651,17 @@ void test_let_error() }) | tt::sync_wait(); #endif HPX_TEST(called); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic called{false}; @@ -1357,10 +1683,17 @@ void test_let_error() }) | tt::sync_wait(); #endif HPX_TEST(called); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic called{false}; @@ -1381,11 +1714,18 @@ void test_let_error() tt::sync_wait(sched); #endif HPX_TEST(called); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // int predecessor { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*tt::sync_wait(ex::schedule(sched) | ex::then([]() { @@ -1405,10 +1745,17 @@ void test_let_error() }) | tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*tt::sync_wait(ex::schedule(sched) | ex::then([]() { @@ -1428,10 +1775,17 @@ void test_let_error() }) | tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*tt::sync_wait(ex::just() | ex::then([]() { @@ -1451,11 +1805,18 @@ void test_let_error() }) | tt::sync_wait(sched))); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // predecessor doesn't throw, let sender is ignored { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = hpx::get<0>(*tt::sync_wait(ex::transfer_just(sched, 42) | @@ -1472,10 +1833,17 @@ void test_let_error() tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC @@ -1493,10 +1861,17 @@ void test_let_error() tt::sync_wait())); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); #ifdef HPX_HAVE_STDEXEC auto result = @@ -1512,6 +1887,10 @@ void test_let_error() }) | tt::sync_wait(sched))); #endif HPX_TEST_EQ(result, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -1519,16 +1898,27 @@ void test_detach() { { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); bool called = false; hpx::mutex mtx; hpx::condition_variable cond; +#ifdef HPX_HAVE_STDEXEC + ex::start_detached(ex::schedule(sched) | ex::then([&]() { + std::unique_lock l{mtx}; + called = true; + cond.notify_one(); + })); +#else ex::schedule(sched) | ex::then([&]() { std::unique_lock l{mtx}; called = true; cond.notify_one(); }) | ex::start_detached(); +#endif { std::unique_lock l{mtx}; @@ -1536,22 +1926,38 @@ void test_detach() l, std::chrono::seconds(1), [&]() { return called; })); } HPX_TEST(called); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // Values passed to set_value are ignored { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); bool called = false; hpx::mutex mtx; hpx::condition_variable cond; +#ifdef HPX_HAVE_STDEXEC + ex::start_detached(ex::schedule(sched) | ex::then([&]() { + std::lock_guard l{mtx}; + called = true; + cond.notify_one(); + return 42; + })); +#else ex::schedule(sched) | ex::then([&]() { std::lock_guard l{mtx}; called = true; cond.notify_one(); return 42; }) | ex::start_detached(); +#endif { std::unique_lock l{mtx}; @@ -1559,6 +1965,10 @@ void test_detach() l, std::chrono::seconds(1), [&]() { return called; })); } HPX_TEST(called); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -1568,55 +1978,86 @@ void test_keep_future_sender() { ex::run_loop loop; auto sched = loop.get_scheduler(); - +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(hpx::make_ready_future()) | + ex::then([](hpx::future&& f) { HPX_TEST(f.is_ready()); })); +#else ex::keep_future(hpx::make_ready_future()) | ex::then([](hpx::future&& f) { HPX_TEST(f.is_ready()); }) | tt::sync_wait(sched); +#endif } { ex::run_loop loop; auto sched = loop.get_scheduler(); - +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(hpx::make_ready_future().share()) | + ex::then( + [](hpx::shared_future&& f) { HPX_TEST(f.is_ready()); })); +#else ex::keep_future(hpx::make_ready_future().share()) | ex::then( [](hpx::shared_future&& f) { HPX_TEST(f.is_ready()); }) | tt::sync_wait(sched); +#endif } { ex::run_loop loop; auto sched = loop.get_scheduler(); - +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(hpx::make_ready_future(42)) | + ex::then([](hpx::future&& f) { + HPX_TEST(f.is_ready()); + HPX_TEST_EQ(f.get(), 42); + })); +#else ex::keep_future(hpx::make_ready_future(42)) | ex::then([](hpx::future&& f) { HPX_TEST(f.is_ready()); HPX_TEST_EQ(f.get(), 42); }) | tt::sync_wait(sched); +#endif } { ex::run_loop loop; auto sched = loop.get_scheduler(); - +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(hpx::make_ready_future(42).share()) | + ex::then([](hpx::shared_future&& f) { + HPX_TEST(f.is_ready()); + HPX_TEST_EQ(f.get(), 42); + })); +#else ex::keep_future(hpx::make_ready_future(42).share()) | ex::then([](hpx::shared_future&& f) { HPX_TEST(f.is_ready()); HPX_TEST_EQ(f.get(), 42); }) | tt::sync_wait(sched); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); std::atomic called{false}; auto f = hpx::async([&]() { called = true; }); +#ifdef HPX_HAVE_STDEXEC + auto r = + hpx::get<0>(*tt::sync_wait(ex::keep_future(std::move(f)))); +#else auto r = hpx::get<0>(*tt::sync_wait(sched, ex::keep_future(std::move(f)))); +#endif static_assert( std::is_same, hpx::future>::value, "sync_wait should return future"); @@ -1628,8 +2069,13 @@ void test_keep_future_sender() try { // The move is intentional. sync_wait should throw. +#ifdef HPX_HAVE_STDEXEC + // NOLINTNEXTLINE(bugprone-use-after-move) + tt::sync_wait(ex::keep_future(std::move(f))); +#else // NOLINTNEXTLINE(bugprone-use-after-move) tt::sync_wait(sched, ex::keep_future(std::move(f))); +#endif HPX_TEST(false); } catch (...) @@ -1637,6 +2083,10 @@ void test_keep_future_sender() exception_thrown = true; } HPX_TEST(exception_thrown); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { @@ -1649,8 +2099,13 @@ void test_keep_future_sender() return 42; }); +#ifdef HPX_HAVE_STDEXEC + auto r = + hpx::get<0>(*tt::sync_wait(ex::keep_future(std::move(f)))); +#else auto r = hpx::get<0>(*tt::sync_wait(sched, ex::keep_future(std::move(f)))); +#endif static_assert( std::is_same, hpx::future>::value, "sync_wait should return future"); @@ -1664,7 +2119,11 @@ void test_keep_future_sender() { // The move is intentional. sync_wait should throw. // NOLINTNEXTLINE(bugprone-use-after-move) +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(std::move(f))); +#else tt::sync_wait(sched, ex::keep_future(std::move(f))); +#endif HPX_TEST(false); } catch (...) @@ -1683,11 +2142,16 @@ void test_keep_future_sender() called = true; return 42; }); - +#ifdef HPX_HAVE_STDEXEC + HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(ex::then(ex::keep_future(std::move(f)), + [](hpx::future&& f) { return f.get() / 2; }))), + 21); +#else HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(sched, ex::then(ex::keep_future(std::move(f)), [](hpx::future&& f) { return f.get() / 2; }))), 21); +#endif HPX_TEST(called); } @@ -1697,16 +2161,25 @@ void test_keep_future_sender() std::atomic calls{0}; auto sf = hpx::async([&]() { ++calls; }).share(); - +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(sf)); + tt::sync_wait(ex::keep_future(sf)); + tt::sync_wait(ex::keep_future(std::move(sf))); +#else tt::sync_wait(sched, ex::keep_future(sf)); tt::sync_wait(sched, ex::keep_future(sf)); tt::sync_wait(sched, ex::keep_future(std::move(sf))); +#endif HPX_TEST_EQ(calls, std::size_t(1)); bool exception_thrown = false; try { +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(sf)); +#else tt::sync_wait(sched, ex::keep_future(sf)); +#endif HPX_TEST(false); } catch (...) @@ -1725,7 +2198,16 @@ void test_keep_future_sender() ++calls; return 42; }).share(); - +#ifdef HPX_HAVE_STDEXEC + HPX_TEST_EQ( + hpx::get<0>(*tt::sync_wait(ex::keep_future(sf))).get(), 42); + HPX_TEST_EQ( + hpx::get<0>(*tt::sync_wait(ex::keep_future(sf))).get(), 42); + HPX_TEST_EQ( + hpx::get<0>(*tt::sync_wait(ex::keep_future(std::move(sf)))) + .get(), + 42); +#else HPX_TEST_EQ( hpx::get<0>(*tt::sync_wait(sched, ex::keep_future(sf))).get(), 42); HPX_TEST_EQ( @@ -1734,12 +2216,17 @@ void test_keep_future_sender() hpx::get<0>(*tt::sync_wait(sched, ex::keep_future(std::move(sf)))) .get(), 42); +#endif HPX_TEST_EQ(calls, std::size_t(1)); bool exception_thrown = false; try { +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::keep_future(sf)); +#else tt::sync_wait(sched, ex::keep_future(sf)); +#endif HPX_TEST(false); } catch (...) @@ -1752,30 +2239,54 @@ void test_keep_future_sender() // Keep future alive across on { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto f = hpx::async([&]() { return 42; }); - +#ifdef HPX_HAVE_STDEXEC + auto r = hpx::get<0>(*tt::sync_wait(ex::keep_future(std::move(f)) | + ex::transfer(sched))); +#else auto r = hpx::get<0>(*(ex::keep_future(std::move(f)) | ex::transfer(sched) | tt::sync_wait())); +#endif HPX_TEST(r.is_ready()); HPX_TEST_EQ(r.get(), 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; auto sched = loop.get_scheduler(); - +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sf = hpx::async([&]() { return 42; }).share(); - +#ifdef HPX_HAVE_STDEXEC + auto r = hpx::get<0>(*tt::sync_wait(ex::keep_future(std::move(sf)) | + ex::transfer(sched))); +#else auto r = hpx::get<0>(*(ex::keep_future(std::move(sf)) | ex::transfer(sched) | tt::sync_wait())); +#endif HPX_TEST(r.is_ready()); HPX_TEST_EQ(r.get(), 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto sf = hpx::async([&]() { @@ -1787,15 +2298,27 @@ void test_keep_future_sender() // or storing a const&. The copy is not possible because the type is // noncopyable, and storing a reference is not acceptable since the // reference may outlive the value. +#ifdef HPX_HAVE_STDEXEC + auto r = hpx::get<0>(*tt::sync_wait(ex::keep_future(std::move(sf)) | + ex::transfer(sched))); +#else auto r = hpx::get<0>(*(ex::keep_future(std::move(sf)) | ex::transfer(sched) | tt::sync_wait())); +#endif HPX_TEST(r.is_ready()); HPX_TEST_EQ(r.get().x, 42); +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } // Use unwrapping with keep_future { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto f = hpx::async([]() { return 42; }); @@ -1803,14 +2326,28 @@ void test_keep_future_sender() auto fun = hpx::unwrapping( [](int&& x, double const& y) { return x * 2 + (int(y) / 2); }); +#ifdef HPX_HAVE_STDEXEC + HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(ex::when_all(ex::keep_future(std::move(f)), + ex::keep_future(std::move(sf))) | + ex::then(fun))), + 85); +#else HPX_TEST_EQ(hpx::get<0>(*(ex::when_all(ex::keep_future(std::move(f)), ex::keep_future(std::move(sf))) | ex::then(fun) | tt::sync_wait(sched))), 85); +#endif +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); auto f = hpx::async([]() { return 42; }); @@ -1818,10 +2355,22 @@ void test_keep_future_sender() auto fun = hpx::unwrapping( [](int&& x, double const& y) { return x * 2 + (int(y) / 2); }); +#ifdef HPX_HAVE_STDEXEC + HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(ex::when_all(ex::keep_future(std::move(f)), + ex::keep_future(sf)) | + ex::transfer(sched) | ex::then(fun))), + 85); +#else HPX_TEST_EQ(hpx::get<0>(*(ex::when_all(ex::keep_future(std::move(f)), ex::keep_future(sf)) | ex::transfer(sched) | ex::then(fun) | tt::sync_wait())), 85); +#endif + +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -1831,34 +2380,58 @@ void test_bulk() { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); for (int n : ns) { std::vector v(n, 0); +#ifdef HPX_HAVE_STDEXEC + hpx::thread::id parent_id = t.get_id(); + tt::sync_wait(ex::schedule(sched) | ex::bulk(n, [&](int i) { + ++v[i]; + HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); + })); +#else hpx::thread::id parent_id = hpx::this_thread::get_id(); - ex::schedule(sched) | ex::bulk(n, [&](int i) { ++v[i]; HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); }) | tt::sync_wait(); - +#endif for (int i = 0; i < n; ++i) { HPX_TEST_EQ(v[i], 1); } } +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); for (auto n : ns) { std::vector v(n, -1); +#ifdef HPX_HAVE_STDEXEC + hpx::thread::id parent_id = t.get_id(); + auto v_out = hpx::get<0>(*tt::sync_wait(ex::transfer_just(sched, std::move(v)) | + ex::bulk(n, + [&parent_id](int i, std::vector& v) { + v[i] = i; + HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); + }))); +#else hpx::thread::id parent_id = hpx::this_thread::get_id(); - auto v_out = hpx::get<0>(*(ex::transfer_just(sched, std::move(v)) | ex::bulk(n, [&parent_id](int i, std::vector& v) { @@ -1866,15 +2439,23 @@ void test_bulk() HPX_TEST_EQ(parent_id, hpx::this_thread::get_id()); }) | tt::sync_wait())); +#endif for (int i = 0; i < n; ++i) { HPX_TEST_EQ(v_out[i], i); } } +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } { +#ifndef HPX_HAVE_STDEXEC + // P2300R8 does not support bulk with generic iterables, only with a + // range of integers, though it is expected that this will be extended. ex::run_loop loop; auto sched = loop.get_scheduler(); @@ -1883,7 +2464,6 @@ void test_bulk() std::vector v_ref = v; hpx::mutex mtx; - ex::schedule(sched) | ex::bulk(std::move(v), [&](std::string const& s) { std::lock_guard lk(mtx); string_map.insert(s); @@ -1893,10 +2473,14 @@ void test_bulk() { HPX_TEST(string_map.find(s) != string_map.end()); } +#endif } { ex::run_loop loop; +#ifdef HPX_HAVE_STDEXEC + auto t = hpx::thread([&]{loop.run();}); +#endif auto sched = loop.get_scheduler(); for (auto n : ns) @@ -1908,6 +2492,15 @@ void test_bulk() try { +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(ex::transfer_just(sched) | ex::bulk(n, [&v, i_fail](int i) { + if (i == i_fail) + { + throw std::runtime_error("error"); + } + v[i] = i; + })); +#else ex::transfer_just(sched) | ex::bulk(n, [&v, i_fail](int i) { if (i == i_fail) { @@ -1915,7 +2508,7 @@ void test_bulk() } v[i] = i; }) | tt::sync_wait(); - +#endif if (expect_exception) { HPX_TEST(false); @@ -1943,6 +2536,10 @@ void test_bulk() } } } +#ifdef HPX_HAVE_STDEXEC + loop.finish(); + t.join(); +#endif } } @@ -1953,8 +2550,13 @@ void test_completion_scheduler() { auto sender = ex::schedule(sched); +#ifdef HPX_HAVE_STDEXEC + auto completion_scheduler = + ex::get_completion_scheduler(ex::get_env(sender)); +#else auto completion_scheduler = ex::get_completion_scheduler(sender); +#endif static_assert( std::is_same_v, decltype(sched)>, @@ -1964,8 +2566,13 @@ void test_completion_scheduler() { auto sender = ex::then(ex::schedule(sched), []() {}); using hpx::functional::tag_invoke; +#ifdef HPX_HAVE_STDEXEC + auto completion_scheduler = + ex::get_completion_scheduler(ex::get_env(sender)); +#else auto completion_scheduler = ex::get_completion_scheduler(sender); +#endif static_assert( std::is_same_v, decltype(sched)>, @@ -1974,8 +2581,13 @@ void test_completion_scheduler() { auto sender = ex::transfer_just(sched, 42); +#ifdef HPX_HAVE_STDEXEC + auto completion_scheduler = + ex::get_completion_scheduler(ex::get_env(sender)); +#else auto completion_scheduler = ex::get_completion_scheduler(sender); +#endif static_assert( std::is_same_v, decltype(sched)>, @@ -1984,8 +2596,13 @@ void test_completion_scheduler() { auto sender = ex::bulk(ex::schedule(sched), 10, [](int) {}); +#ifdef HPX_HAVE_STDEXEC + auto completion_scheduler = + ex::get_completion_scheduler(ex::get_env(sender)); +#else auto completion_scheduler = ex::get_completion_scheduler(sender); +#endif static_assert( std::is_same_v, decltype(sched)>, @@ -1996,8 +2613,13 @@ void test_completion_scheduler() auto sender = ex::then( ex::bulk(ex::transfer_just(sched, 42), 10, [](int, int) {}), [](int) {}); +#ifdef HPX_HAVE_STDEXEC + auto completion_scheduler = + ex::get_completion_scheduler(ex::get_env(sender)); +#else auto completion_scheduler = ex::get_completion_scheduler(sender); +#endif static_assert( std::is_same_v, decltype(sched)>, @@ -2005,11 +2627,19 @@ void test_completion_scheduler() } { +#ifdef HPX_HAVE_STDEXEC + auto sender = + ex::bulk((ex::transfer_just(sched, 42) | ex::then( [](int){})), 10, + [](int) {}); + auto completion_scheduler = + ex::get_completion_scheduler(ex::get_env(sender)); +#else auto sender = ex::bulk(ex::then(ex::transfer_just(sched, 42), [](int) {}), 10, [](int, int) {}); auto completion_scheduler = ex::get_completion_scheduler(sender); +#endif static_assert( std::is_same_v, decltype(sched)>, @@ -2026,7 +2656,7 @@ void do_run_test(void (*func)(), char const* func_name) func(); } -#define RUN_TEST(func) do_run_test(&func, HPX_PP_STRINGIZE(func)) +#define RUN_TEST(func) std::cout << "Running test: "; do_run_test(&func, HPX_PP_STRINGIZE(func)); int hpx_main() { diff --git a/libs/core/execution/tests/unit/algorithm_split.cpp b/libs/core/execution/tests/unit/algorithm_split.cpp index 457263e0ebf0..f8dc146ff005 100644 --- a/libs/core/execution/tests/unit/algorithm_split.cpp +++ b/libs/core/execution/tests/unit/algorithm_split.cpp @@ -35,19 +35,21 @@ int main() { std::atomic set_value_called{false}; auto s1 = void_sender{}; - static_assert(ex::is_sender_v); - static_assert(ex::is_sender_v); - - check_value_types>>(s1); - check_error_types>(s1); - check_sends_stopped(s1); - auto s2 = ex::split(std::move(s1)); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s2); +#ifdef HPX_HAVE_STDEXEC + // In p2300R8 split's error channel returns a const& of an exception_ptr + check_error_types>(s2); +#else check_error_types>(s2); +#endif check_sends_stopped(s2); auto f = [] {}; @@ -61,18 +63,30 @@ int main() std::atomic set_value_called{false}; auto s1 = ex::just(0); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s1); +#ifdef HPX_HAVE_STDEXEC + // In p2300R8 just does not have an error channel + check_error_types>(s1); +#else check_error_types>(s1); +#endif check_sends_stopped(s1); auto s2 = ex::split(std::move(s1)); static_assert(ex::is_sender_v); - static_assert(ex::is_sender_v); check_value_types>>(s2); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s2); +#else check_error_types>(s2); +#endif check_sends_stopped(s2); auto f = [](int x) { HPX_TEST_EQ(x, 0); }; @@ -86,21 +100,37 @@ int main() std::atomic set_value_called{false}; auto s1 = ex::just(custom_type_non_default_constructible{42}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types< hpx::variant>>( s1); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s1); +#else check_error_types>(s1); +#endif check_sends_stopped(s1); auto s2 = ex::split(std::move(s1)); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s2); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s2); +#else check_error_types>(s2); +#endif check_sends_stopped(s2); auto f = [](auto x) { HPX_TEST_EQ(x.x, 42); }; @@ -115,21 +145,37 @@ int main() auto s1 = ex::just(custom_type_non_default_constructible_non_copyable{42}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>( s1); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s1); +#else check_error_types>(s1); +#endif check_sends_stopped(s1); auto s2 = ex::split(std::move(s1)); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s2); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s2); +#else check_error_types>(s2); +#endif check_sends_stopped(s2); auto f = [](auto& x) { HPX_TEST_EQ(x.x, 42); }; @@ -144,10 +190,18 @@ int main() std::atomic set_value_called{false}; auto s = void_sender{} | ex::split(); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s); +#else check_error_types>(s); +#endif check_sends_stopped(s); auto f = [] {}; @@ -164,7 +218,11 @@ int main() auto s = custom_sender_tag_invoke{tag_invoke_overload_called} | ex::split(); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif // custom_sender_tag_invoke implements tag_invoke(split_t, ...) // returning an instance of void_sender @@ -185,10 +243,18 @@ int main() std::atomic set_error_called{false}; auto s = error_sender{} | ex::split(); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s); +#else check_error_types>(s); +#endif check_sends_stopped(s); auto r = error_callback_receiver{ @@ -202,10 +268,18 @@ int main() std::atomic set_error_called{false}; auto s = error_sender{} | ex::split() | ex::split() | ex::split(); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s); +#else check_error_types>(s); +#endif check_sends_stopped(s); auto r = error_callback_receiver{ @@ -220,30 +294,59 @@ int main() std::atomic receiver_set_value_called{false}; auto s1 = ex::just() | ex::split(); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s1); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s1); +#else check_error_types>(s1); +#endif check_sends_stopped(s1); auto s2 = ex::split(s1); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s2); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s2); +#else check_error_types>(s2); +#endif check_sends_stopped(s2); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(s1.state, s2.state); +#endif auto s3 = ex::split(std::move(s2)); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s3); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s3); +#else check_error_types>(s3); +#endif check_sends_stopped(s3); + +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(s1.state, s3.state); +#endif auto f = [] {}; auto r = callback_receiver{f, receiver_set_value_called}; auto os = ex::connect(std::move(s3), std::move(r)); @@ -255,30 +358,58 @@ int main() std::atomic receiver_set_value_called{false}; auto s1 = ex::just(42) | ex::split(); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s1); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s1); +#else check_error_types>(s1); +#endif check_sends_stopped(s1); auto s2 = ex::split(s1); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s2); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s2); +#else check_error_types>(s2); +#endif check_sends_stopped(s2); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(s1.state, s2.state); +#endif auto s3 = ex::split(std::move(s2)); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s3); +#ifdef HPX_HAVE_STDEXEC + check_error_types>(s3); +#else check_error_types>(s3); +#endif check_sends_stopped(s3); +#ifndef HPX_HAVE_STDEXEC HPX_TEST_EQ(s1.state, s3.state); +#endif auto f = [](int x) { HPX_TEST_EQ(x, 42); }; auto r = callback_receiver{f, receiver_set_value_called}; auto os = ex::connect(std::move(s3), std::move(r)); diff --git a/libs/core/execution/tests/unit/algorithm_start_detached.cpp b/libs/core/execution/tests/unit/algorithm_start_detached.cpp index 4e5a7a7637bf..11fabd5614d3 100644 --- a/libs/core/execution/tests/unit/algorithm_start_detached.cpp +++ b/libs/core/execution/tests/unit/algorithm_start_detached.cpp @@ -78,6 +78,11 @@ int main() // operator| overload { +#ifndef HPX_HAVE_STDEXEC + // in P2300R8 start detached does not have an operator| as it is a + // sender consumer and not a sender adaptor, and only sender adaptors + // have operator| overloads + std::atomic start_called{false}; std::atomic connect_called{false}; std::atomic tag_invoke_overload_called{false}; @@ -87,6 +92,7 @@ int main() HPX_TEST(start_called); HPX_TEST(connect_called); HPX_TEST(!tag_invoke_overload_called); +#endif } // tag_invoke overload diff --git a/libs/core/execution/tests/unit/algorithm_sync_wait.cpp b/libs/core/execution/tests/unit/algorithm_sync_wait.cpp index 5157b4e73988..a12c3288d3c7 100644 --- a/libs/core/execution/tests/unit/algorithm_sync_wait.cpp +++ b/libs/core/execution/tests/unit/algorithm_sync_wait.cpp @@ -4,6 +4,7 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include #include #include #include @@ -22,9 +23,10 @@ namespace tt = hpx::this_thread::experimental; // NOTE: This is not a conforming sync_wait implementation. It only exists to // check that the tag_invoke overload is called. -void tag_invoke(tt::sync_wait_t, custom_sender2 s) +std::optional> tag_invoke(tt::sync_wait_t, custom_sender2 s) { s.tag_invoke_overload_called = true; + return {}; } int hpx_main() @@ -85,20 +87,30 @@ int hpx_main() } // operator| overload + { std::atomic start_called{false}; std::atomic connect_called{false}; std::atomic tag_invoke_overload_called{false}; +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(custom_sender{ + start_called, connect_called, tag_invoke_overload_called}); +#else custom_sender{ start_called, connect_called, tag_invoke_overload_called} | tt::sync_wait(); +#endif HPX_TEST(start_called); HPX_TEST(connect_called); HPX_TEST(!tag_invoke_overload_called); } { +#ifdef HPX_HAVE_STDEXEC + HPX_TEST_EQ(hpx::get<0>(*tt::sync_wait(ex::just(3))),3); +#else HPX_TEST_EQ(hpx::get<0>(*(ex::just(3) | tt::sync_wait())), 3); +#endif } // tag_invoke overload @@ -106,8 +118,13 @@ int hpx_main() std::atomic start_called{false}; std::atomic connect_called{false}; std::atomic tag_invoke_overload_called{false}; +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait(custom_sender2{custom_sender{ + start_called, connect_called, tag_invoke_overload_called}}); +#else tt::sync_wait(custom_sender2{custom_sender{ start_called, connect_called, tag_invoke_overload_called}}); +#endif HPX_TEST(!start_called); HPX_TEST(!connect_called); HPX_TEST(tag_invoke_overload_called); @@ -131,7 +148,11 @@ int hpx_main() // cancellation path { +#ifdef HPX_HAVE_STDEXEC + auto result = tt::sync_wait(stopped_sender_with_value_type{}); +#else auto result = stopped_sender_with_value_type{} | tt::sync_wait(); +#endif HPX_TEST(!result); // returned optional should be empty } diff --git a/libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp b/libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp index 99d7d02c2fb1..b1b0790f6fa9 100644 --- a/libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp +++ b/libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp @@ -6,6 +6,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include #include @@ -23,13 +24,21 @@ namespace tt = hpx::this_thread::experimental; // NOTE: This is not a conforming sync_wait_with_variant implementation. // It only exists to check that the tag_invoke overload is called. -void tag_invoke(tt::sync_wait_with_variant_t, custom_sender2 s) +std::optional> tag_invoke(tt::sync_wait_with_variant_t, custom_sender2 s) { s.tag_invoke_overload_called = true; + return {}; } int hpx_main() { +#ifdef HPX_HAVE_STDEXEC + using std::tuple; + using std::variant; +#else + using hpx::tuple; + using hpx::variant +#endif // Success path { std::atomic start_called{false}; @@ -44,15 +53,16 @@ int hpx_main() // sync_wait_with_variant can accept single value senders : // assume currently have one tuple { - auto result = ex::just(42) | tt::sync_wait_with_variant(); + auto result = tt::sync_wait_with_variant(ex::just(42)); auto v = *result; static_assert( - std::is_same_v>>); - HPX_TEST(hpx::holds_alternative>(v)); + std::is_same_v>>); + + HPX_TEST(hpx::holds_alternative>(v)); - auto t = hpx::get>(v); - static_assert(std::is_same_v>); + auto t = hpx::get>(v); + static_assert(std::is_same_v>); auto i = hpx::get<0>(t); static_assert(std::is_same_v); @@ -61,14 +71,18 @@ int hpx_main() } { +#ifdef HPX_HAVE_STDEXEC + auto result = tt::sync_wait_with_variant(ex::just(3, 4.0)); +#else auto result = ex::just(3, 4.0) | tt::sync_wait_with_variant(); +#endif auto v = *result; static_assert( - std::is_same_v>>); + std::is_same_v>>); - auto t = hpx::get>(v); - static_assert(std::is_same_v>); + auto t = hpx::get>(v); + static_assert(std::is_same_v>); auto i = hpx::get<0>(t); static_assert(std::is_same_v); @@ -87,11 +101,11 @@ int hpx_main() auto v = *result; static_assert(std::is_same_v>>); + variant>>); - auto t = hpx::get>(v); + auto t = hpx::get>(v); static_assert( - std::is_same_v>); + std::is_same_v>); auto i = hpx::get<0>(t); static_assert(std::is_same_v); @@ -113,11 +127,13 @@ int hpx_main() auto s1 = ex::just(custom_type_non_default_constructible{42}); auto result = tt::sync_wait_with_variant(s1); auto v = *result; + // STDEXEC: using hpx::variant, hpx::tuple here works because they are + // provided as the prefered variant, tuple in check_value_types too check_value_types< hpx::variant>>( s1); - auto t = hpx::get>(v); + auto t = hpx::get>(v); auto p = hpx::get<0>(t); static_assert( std::is_same_v); @@ -130,11 +146,11 @@ int hpx_main() ex::just(custom_type_non_default_constructible_non_copyable{42})); auto const& v = *result; static_assert(std::is_same_v, - hpx::variant>>); auto const& t = hpx::get< - hpx::tuple>(v); + tuple>(v); auto const& p = hpx::get<0>(t); static_assert(std::is_same_v, custom_type_non_default_constructible_non_copyable>); @@ -178,14 +194,27 @@ int hpx_main() // variant auto v = *result; +#ifdef HPX_HAVE_STDEXEC + // just(3) does not have a set_error_r(std::exception_ptr) completion + // so the just(std::string) completion is never materialized into the + // let_error's completions static_assert(std::is_same_v, hpx::tuple>>); + variant>>); +#else + static_assert(std::is_same_v, tuple>>); +#endif - HPX_TEST(hpx::holds_alternative>(v)); + HPX_TEST(hpx::holds_alternative>(v)); // tuple +#ifdef HPX_HAVE_STDEXEC + // Now v is just a variant> + auto t = hpx::get<0>(v); +#else auto t = hpx::get<1>(v); - static_assert(std::is_same_v>); +#endif + static_assert(std::is_same_v>); auto i = hpx::get<0>(t); static_assert(std::is_same_v); @@ -206,11 +235,11 @@ int hpx_main() // variant auto v = *result; static_assert( - std::is_same_v>>); + std::is_same_v>>); // tuple auto t = hpx::get<0>(v); - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); auto j = hpx::get<0>(t); static_assert(std::is_same_v); @@ -223,24 +252,34 @@ int hpx_main() std::atomic start_called{false}; std::atomic connect_called{false}; std::atomic tag_invoke_overload_called{false}; +#ifdef HPX_HAVE_STDEXEC + tt::sync_wait_with_variant( + custom_sender{ + start_called, connect_called, tag_invoke_overload_called}); +#else custom_sender{ start_called, connect_called, tag_invoke_overload_called} | tt::sync_wait_with_variant(); +#endif HPX_TEST(start_called); HPX_TEST(connect_called); HPX_TEST(!tag_invoke_overload_called); } { +#ifdef HPX_HAVE_STDEXEC + auto result = tt::sync_wait_with_variant(ex::just(3)); +#else auto result = ex::just(3) | tt::sync_wait_with_variant(); +#endif auto v = *result; static_assert( - std::is_same_v>>); - HPX_TEST(hpx::holds_alternative>(v)); + std::is_same_v>>); + HPX_TEST(hpx::holds_alternative>(v)); - auto t = hpx::get>(v); - static_assert(std::is_same_v>); + auto t = hpx::get>(v); + static_assert(std::is_same_v>); auto i = hpx::get<0>(t); static_assert(std::is_same_v); @@ -278,8 +317,13 @@ int hpx_main() // cancellation path { +#ifdef HPX_HAVE_STDEXEC + auto result = tt::sync_wait_with_variant( + stopped_sender_with_value_type{}); +#else auto result = (stopped_sender_with_value_type{} | tt::sync_wait_with_variant()); +#endif HPX_TEST(!result); // returned optional should be empty } diff --git a/libs/core/execution/tests/unit/algorithm_then.cpp b/libs/core/execution/tests/unit/algorithm_then.cpp index 6a3e31ce613a..72428a1db7b5 100644 --- a/libs/core/execution/tests/unit/algorithm_then.cpp +++ b/libs/core/execution/tests/unit/algorithm_then.cpp @@ -23,28 +23,6 @@ #include namespace ex = hpx::execution::experimental; -#include -#if 0 -int main () { - using snd = decltype(ex::just(1)); - - using value_types = ex::value_types_of_t< - std::decay_t, ex::empty_env, - hpx::meta::pack, hpx::meta::pack>; - - using result_type = - std::decay_t>; - - using operation_state_type = hpx::util::invoke_result_t< - ex::connect_t, snd, - ex::detail::future_receiver>; - - - hpx::future f2 = ex::make_future(ex::just(1)); -// static_assert(std::is_same_v); -} - -#else struct custom_transformer { @@ -181,7 +159,11 @@ int hpx_main() std::atomic set_value_called{false}; auto s = ex::then(ex::just(), [] {}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -198,7 +180,11 @@ int hpx_main() std::atomic set_value_called{false}; auto s = ex::then(ex::just(0), [](int x) { return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -219,7 +205,11 @@ int hpx_main() return x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types< hpx::variant>>(s); @@ -242,7 +232,11 @@ int hpx_main() return std::move(x); }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); @@ -260,7 +254,11 @@ int hpx_main() std::atomic set_value_called{false}; auto s1 = ex::then(ex::just(0), [](int x) { return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s1); check_error_types>(s1); @@ -268,7 +266,11 @@ int hpx_main() auto s2 = ex::then(std::move(s1), [](int x) { return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s2); check_error_types>(s2); @@ -276,7 +278,11 @@ int hpx_main() auto s3 = ex::then(std::move(s2), [](int x) { return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s3); check_error_types>(s3); @@ -284,7 +290,11 @@ int hpx_main() auto s4 = ex::then(std::move(s3), [](int x) { return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s4); check_error_types>(s4); @@ -301,7 +311,11 @@ int hpx_main() std::atomic set_value_called{false}; auto s1 = ex::then(ex::just(), []() { return 3; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s1); check_error_types>(s1); @@ -309,7 +323,11 @@ int hpx_main() auto s2 = ex::then(std::move(s1), [](int x) { return x / 1.5; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s2); check_error_types>(s2); @@ -318,7 +336,11 @@ int hpx_main() auto s3 = ex::then(std::move(s2), [](double x) -> int { return int(x / 2); }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s3); check_error_types>(s3); @@ -327,7 +349,11 @@ int hpx_main() auto s4 = ex::then(std::move(s3), [](int x) { return std::to_string(x); }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s4); check_error_types>(s4); @@ -348,7 +374,11 @@ int hpx_main() ex::then([](double x) -> int { return int(x / 2); }) | ex::then([](int x) { return std::to_string(x); }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -370,7 +400,11 @@ int hpx_main() custom_transformer{tag_invoke_overload_called, custom_transformer_call_operator_called, false}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -391,7 +425,11 @@ int hpx_main() auto s = ex::then(ex::just(), [] { throw std::runtime_error("error"); }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -408,28 +446,44 @@ int hpx_main() std::atomic set_error_called{false}; auto s1 = ex::then(ex::just(0), [](int x) { return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif auto s2 = ex::then(std::move(s1), [](int x) { throw std::runtime_error("error"); return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif auto s3 = ex::then(std::move(s2), [](int x) { HPX_TEST(false); return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif auto s4 = ex::then(std::move(s3), [](int x) { HPX_TEST(false); return ++x; }); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s4); check_error_types>(s4); @@ -450,7 +504,11 @@ int hpx_main() custom_transformer{tag_invoke_overload_called, custom_transformer_call_operator_called, true}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -479,5 +537,4 @@ int main(int argc, char* argv[]) "HPX main exited with non-zero status"); return hpx::util::report_errors(); -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/libs/core/execution/tests/unit/algorithm_transfer.cpp b/libs/core/execution/tests/unit/algorithm_transfer.cpp index d00de8776fc0..5e77d2ea6431 100644 --- a/libs/core/execution/tests/unit/algorithm_transfer.cpp +++ b/libs/core/execution/tests/unit/algorithm_transfer.cpp @@ -20,10 +20,12 @@ namespace ex = hpx::execution::experimental; // schedule_from customization -struct scheduler_schedule_from : scheduler +struct scheduler_schedule_from : example_scheduler_template { - explicit scheduler_schedule_from(scheduler sched) - : scheduler(std::move(sched)) + using base = example_scheduler_template; + template + explicit scheduler_schedule_from(Args&&... ags) + : base(std::forward(ags)...) { } }; @@ -32,25 +34,28 @@ template auto tag_invoke(ex::schedule_from_t, scheduler_schedule_from sched, Sender&&) { sched.tag_invoke_overload_called = true; - return scheduler::sender{}; + return example_scheduler::my_sender{}; } // transfer customization -struct scheduler_transfer : scheduler +struct scheduler_transfer : example_scheduler_template { - explicit scheduler_transfer(scheduler sched) - : scheduler(std::move(sched)) + using base = example_scheduler_template; + + template + explicit scheduler_transfer(Args&&... args) + : base(std::forward(args)...) { } }; -template +template decltype(auto) tag_invoke(ex::transfer_t, scheduler_transfer completion_sched, - Sender&& sender, Scheduler&& sched) + Sender&& sender, example_scheduler&& sched) { completion_sched.tag_invoke_overload_called = true; return ex::schedule_from( - std::forward(sched), std::forward(sender)); + std::forward(sched), std::forward(sender)); } struct sender_with_completion_scheduler : void_sender @@ -62,12 +67,30 @@ struct sender_with_completion_scheduler : void_sender { } +#ifdef HPX_HAVE_STDEXEC + struct my_env { + scheduler_transfer const& sched; + + friend scheduler_transfer const& tag_invoke( + ex::get_completion_scheduler_t, my_env env) noexcept + { + return env.sched; + } + }; + + friend my_env tag_invoke( + hpx::execution::experimental::get_env_t, sender_with_completion_scheduler const& s) noexcept + { + return {s.sched}; + } +#else friend scheduler_transfer tag_invoke( ex::get_completion_scheduler_t, sender_with_completion_scheduler s) { return s.sched; } +#endif template friend auto tag_invoke( @@ -86,10 +109,14 @@ int main() std::atomic scheduler_execute_called{false}; std::atomic tag_invoke_overload_called{false}; auto s = ex::transfer(ex::just(), - scheduler{scheduler_schedule_called, scheduler_execute_called, + example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -107,14 +134,18 @@ int main() { std::atomic set_value_called{false}; - std::atomic scheduler_schedule_called{false}; + std::atomic scheduler_schedule_called{false} ; std::atomic scheduler_execute_called{false}; std::atomic tag_invoke_overload_called{false}; auto s = ex::transfer(ex::just(3), - scheduler{scheduler_schedule_called, scheduler_execute_called, + example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -137,10 +168,14 @@ int main() std::atomic tag_invoke_overload_called{false}; auto s = ex::transfer(ex::just(custom_type_non_default_constructible{42}), - scheduler{scheduler_schedule_called, scheduler_execute_called, + example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types< hpx::variant>>(s); @@ -164,11 +199,14 @@ int main() std::atomic tag_invoke_overload_called{false}; auto s = ex::transfer( ex::just(custom_type_non_default_constructible_non_copyable{42}), - scheduler{scheduler_schedule_called, scheduler_execute_called, + example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); - +#endif check_value_types>>(s); check_error_types>(s); @@ -190,10 +228,14 @@ int main() std::atomic scheduler_schedule_called{false}; std::atomic tag_invoke_overload_called{false}; auto s = ex::transfer(ex::just(std::string("hello"), 3), - scheduler{scheduler_schedule_called, scheduler_execute_called, + example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -219,10 +261,14 @@ int main() std::atomic scheduler_schedule_called{false}; std::atomic tag_invoke_overload_called{false}; auto s = ex::just(std::string("hello"), 3) | - ex::transfer(scheduler{scheduler_schedule_called, + ex::transfer(example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -247,11 +293,18 @@ int main() std::atomic tag_invoke_overload_called{false}; std::atomic scheduler_schedule_called{false}; std::atomic scheduler_execute_called{false}; + + static_assert(ex::scheduler); + auto s = ex::transfer(ex::just(), - scheduler_schedule_from{scheduler{scheduler_schedule_called, + scheduler_schedule_from{example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}}); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -277,11 +330,11 @@ int main() std::atomic destination_scheduler_schedule_called{false}; std::atomic destination_scheduler_execute_called{false}; - scheduler_transfer source_scheduler{scheduler{ + scheduler_transfer source_scheduler{example_scheduler{ source_scheduler_schedule_called, source_scheduler_execute_called, source_scheduler_tag_invoke_overload_called}}; - scheduler destination_scheduler{ - scheduler{destination_scheduler_schedule_called, + example_scheduler destination_scheduler{ + example_scheduler{destination_scheduler_schedule_called, destination_scheduler_execute_called, destination_scheduler_tag_invoke_overload_called}}; @@ -289,7 +342,7 @@ int main() sender_with_completion_scheduler{std::move(source_scheduler)}, destination_scheduler); static_assert(ex::is_sender_v); - static_assert(ex::is_sender_v); + static_assert(ex::is_sender_in_v); check_value_types>>(s); check_error_types>(s); @@ -318,11 +371,11 @@ int main() std::atomic destination_scheduler_schedule_called{false}; std::atomic destination_scheduler_execute_called{false}; - scheduler_transfer source_scheduler{scheduler{ + scheduler_transfer source_scheduler{example_scheduler{ source_scheduler_schedule_called, source_scheduler_execute_called, source_scheduler_tag_invoke_overload_called}}; scheduler_schedule_from destination_scheduler{ - scheduler{destination_scheduler_schedule_called, + example_scheduler{destination_scheduler_schedule_called, destination_scheduler_execute_called, destination_scheduler_tag_invoke_overload_called}}; @@ -330,7 +383,11 @@ int main() sender_with_completion_scheduler{std::move(source_scheduler)}, destination_scheduler); static_assert(ex::is_sender_v); +#ifdef HPX_HAVE_STDEXEC + static_assert(ex::is_sender_in_v); +#else static_assert(ex::is_sender_v); +#endif check_value_types>>(s); check_error_types>(s); @@ -356,14 +413,19 @@ int main() std::atomic scheduler_schedule_called{false}; std::atomic scheduler_execute_called{false}; auto s = ex::transfer(error_sender{}, - scheduler{scheduler_schedule_called, scheduler_execute_called, + example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}); static_assert(ex::is_sender_v); - static_assert(ex::is_sender_v); + static_assert(ex::is_sender_in_v); check_value_types>>(s); check_error_types>(s); +#ifdef HPX_HAVE_STDEXEC + // P2300 transfer propagates the set_stopped signature + check_sends_stopped(s); +#else check_sends_stopped(s); +#endif auto r = error_callback_receiver{ check_exception_ptr{}, set_error_called}; @@ -371,7 +433,12 @@ int main() ex::start(os); HPX_TEST(set_error_called); HPX_TEST(!tag_invoke_overload_called); +#ifdef HPX_HAVE_STDEXEC + // schedule is called anyways + HPX_TEST(scheduler_schedule_called); +#else HPX_TEST(!scheduler_schedule_called); +#endif HPX_TEST(!scheduler_execute_called); } diff --git a/libs/core/execution/tests/unit/algorithm_transfer_when_all.cpp b/libs/core/execution/tests/unit/algorithm_transfer_when_all.cpp index 8cf217019130..47fb09fd35c7 100644 --- a/libs/core/execution/tests/unit/algorithm_transfer_when_all.cpp +++ b/libs/core/execution/tests/unit/algorithm_transfer_when_all.cpp @@ -38,13 +38,17 @@ int main() std::atomic scheduler_execute_called{false}; std::atomic tag_invoke_overload_called{false}; - auto sched = scheduler{scheduler_schedule_called, + auto sched = example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}; auto s = ex::transfer_when_all(sched, ex::just(42)); static_assert(ex::is_sender_v, "transfer_when_all must return a sender"); +#ifdef HPX_HAVE_STDEXEC + auto csch = ex::get_completion_scheduler(ex::get_env(s)); +#else auto csch = ex::get_completion_scheduler(s); +#endif HPX_TEST(sched == csch); auto f = [](int x) { HPX_TEST_EQ(x, 42); }; @@ -63,14 +67,18 @@ int main() std::atomic scheduler_execute_called{false}; std::atomic tag_invoke_overload_called{false}; - auto sched = scheduler{scheduler_schedule_called, + auto sched = example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}; auto s = ex::transfer_when_all(sched, ex::just(42), ex::just(std::string("hello")), ex::just(3.14)); static_assert(ex::is_sender_v, "transfer_when_all must return a sender"); +#ifdef HPX_HAVE_STDEXEC + auto csch = ex::get_completion_scheduler(ex::get_env(s)); +#else auto csch = ex::get_completion_scheduler(s); +#endif HPX_TEST(sched == csch); auto f = [](int x, std::string y, double z) { @@ -93,14 +101,18 @@ int main() std::atomic scheduler_execute_called{false}; std::atomic tag_invoke_overload_called{false}; - auto sched = scheduler{scheduler_schedule_called, + auto sched = example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}; auto s = ex::transfer_when_all( sched, ex::just(), ex::just(std::string("hello")), ex::just(3.14)); static_assert(ex::is_sender_v, "transfer_when_all must return a sender"); +#ifdef HPX_HAVE_STDEXEC + auto csch = ex::get_completion_scheduler(ex::get_env(s)); +#else auto csch = ex::get_completion_scheduler(s); +#endif HPX_TEST(sched == csch); auto f = [](std::string y, double z) { @@ -123,7 +135,7 @@ int main() std::atomic scheduler_execute_called{false}; std::atomic tag_invoke_overload_called{false}; - auto sched = scheduler{scheduler_schedule_called, + auto sched = example_scheduler{scheduler_schedule_called, scheduler_execute_called, tag_invoke_overload_called}; auto s = ex::transfer_when_all(sched, error_typed_sender{}); auto r = error_callback_receiver{ @@ -133,7 +145,11 @@ int main() HPX_TEST(set_error_called); HPX_TEST(!tag_invoke_overload_called); +#ifdef HPX_HAVE_STDEXEC + HPX_TEST(scheduler_schedule_called); +#else HPX_TEST(!scheduler_schedule_called); +#endif HPX_TEST(!scheduler_execute_called); } diff --git a/libs/core/execution_base/include/hpx/execution_base/completion_scheduler.hpp b/libs/core/execution_base/include/hpx/execution_base/completion_scheduler.hpp index 22863d37c712..8b2ba6f94b65 100644 --- a/libs/core/execution_base/include/hpx/execution_base/completion_scheduler.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/completion_scheduler.hpp @@ -114,7 +114,7 @@ namespace hpx::execution::experimental { struct has_completion_scheduler_impl : hpx::execution::experimental::is_scheduler, - std::decay_t const&>> + hpx::execution::experimental::env_of_t const&>>> { }; @@ -122,7 +122,9 @@ namespace hpx::execution::experimental { struct has_completion_scheduler : has_completion_scheduler_impl, - std::decay_t const&>, + hpx::execution::experimental::env_of_t< + std::decay_t const&> + >, CPO, Sender> { }; @@ -148,7 +150,7 @@ namespace hpx::execution::experimental { hpx::functional::tag_invoke_result_t< hpx::execution::experimental:: get_completion_scheduler_t, - Sender>, + hpx::execution::experimental::env_of_t>, Sender, Ts...>> { }; diff --git a/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp b/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp index 0f1d46dc471f..843f44acba55 100644 --- a/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp @@ -7,112 +7,6 @@ #pragma once #include - -#ifdef HPX_HAVE_STDEXEC -#include -#include -#include -#include -#include -#include - -namespace hpx::execution::experimental { -// template -// struct completion_signatures_of_is_valid : std::false_type -// { -// }; -// -// template -// struct completion_signatures_of_is_valid(), std::declval()))>> : std::true_type -// { -// }; -// - struct empty_variant - { - empty_variant() = delete; - }; - - namespace detail { - // use this remove_cv_ref instead of std::decay to avoid - // decaying function types, e.g. set_value_t() -> set_value_t(*)() - template - struct remove_cv_ref - { - using type = std::remove_cv_t>; - }; - - template - using remove_cv_ref_t = meta::type>; - - // If sizeof...(Ts) is greater than zero, variant-or-empty names - // the type variant where Us... is the pack decay_t... with - // duplicate types removed. - template