|
19 | 19 | #include "test_common/catch2.hpp" |
20 | 20 | #include "test_common/type_helpers.hpp" |
21 | 21 |
|
| 22 | +#include <atomic> |
22 | 23 | #include <numeric> |
23 | 24 | #include <utility> |
24 | 25 | #include <vector> |
@@ -108,6 +109,92 @@ namespace |
108 | 109 | CHECK(res == 30); |
109 | 110 | } |
110 | 111 |
|
| 112 | + TEST_CASE("libdispatch queue bulk_chunked uses one task per index for parallel policies") |
| 113 | + { |
| 114 | + exec::libdispatch_queue queue; |
| 115 | + auto sch = queue.get_scheduler(); |
| 116 | + |
| 117 | + std::vector<int> visited(5, 0); |
| 118 | + std::atomic<int> chunks{0}; |
| 119 | + |
| 120 | + auto sender = STDEXEC::schedule(sch) |
| 121 | + | STDEXEC::bulk_chunked(STDEXEC::par, |
| 122 | + 5, |
| 123 | + [&](int begin, int end) |
| 124 | + { |
| 125 | + ++chunks; |
| 126 | + for (; begin != end; ++begin) |
| 127 | + visited[begin] = 1; |
| 128 | + }); |
| 129 | + |
| 130 | + REQUIRE(STDEXEC::sync_wait(std::move(sender)).has_value()); |
| 131 | + |
| 132 | + CHECK(chunks.load() == 5); |
| 133 | + CHECK(visited == std::vector<int>{1, 1, 1, 1, 1}); |
| 134 | + } |
| 135 | + |
| 136 | + TEST_CASE("libdispatch queue runs a non-parallel bulk_chunked in a single task") |
| 137 | + { |
| 138 | + exec::libdispatch_queue queue; |
| 139 | + auto sch = queue.get_scheduler(); |
| 140 | + |
| 141 | + std::vector<int> bounds; |
| 142 | + |
| 143 | + auto sender = STDEXEC::schedule(sch) |
| 144 | + | STDEXEC::bulk_chunked(STDEXEC::seq, |
| 145 | + 5, |
| 146 | + [&](int begin, int end) |
| 147 | + { |
| 148 | + bounds.push_back(begin); |
| 149 | + bounds.push_back(end); |
| 150 | + }); |
| 151 | + |
| 152 | + REQUIRE(STDEXEC::sync_wait(std::move(sender)).has_value()); |
| 153 | + |
| 154 | + // `seq` forbids splitting the index space, so a single chunk covers all of it |
| 155 | + CHECK(bounds == std::vector<int>{0, 5}); |
| 156 | + } |
| 157 | + |
| 158 | + TEST_CASE("libdispatch queue bulk_unchunked should call callback function with every index") |
| 159 | + { |
| 160 | + exec::libdispatch_queue queue; |
| 161 | + auto sch = queue.get_scheduler(); |
| 162 | + |
| 163 | + std::vector<int> data{1, 2, 3, 4, 5}; |
| 164 | + auto size = data.size(); |
| 165 | + auto expensive_computation = [](auto i, auto &data) |
| 166 | + { |
| 167 | + data[i] = 2 * data[i]; |
| 168 | + }; |
| 169 | + auto add = [](auto const &data) |
| 170 | + { |
| 171 | + return std::accumulate(std::begin(data), std::end(data), 0); |
| 172 | + }; |
| 173 | + auto sender = STDEXEC::just(std::move(data)) | STDEXEC::continues_on(sch) |
| 174 | + | STDEXEC::bulk_unchunked(STDEXEC::par, size, expensive_computation) |
| 175 | + | STDEXEC::then(add); |
| 176 | + |
| 177 | + auto [res] = STDEXEC::sync_wait(sender).value(); |
| 178 | + CHECK(res == 30); |
| 179 | + } |
| 180 | + |
| 181 | + TEST_CASE("libdispatch queue runs a non-parallel bulk_unchunked in a single task") |
| 182 | + { |
| 183 | + exec::libdispatch_queue queue; |
| 184 | + auto sch = queue.get_scheduler(); |
| 185 | + |
| 186 | + std::vector<int> indices; |
| 187 | + |
| 188 | + auto sender = STDEXEC::schedule(sch) |
| 189 | + | STDEXEC::bulk_unchunked(STDEXEC::seq, |
| 190 | + 4, |
| 191 | + [&](int idx) { indices.push_back(idx); }); |
| 192 | + |
| 193 | + REQUIRE(STDEXEC::sync_wait(std::move(sender)).has_value()); |
| 194 | + |
| 195 | + CHECK(indices == std::vector<int>{0, 1, 2, 3}); |
| 196 | + } |
| 197 | + |
111 | 198 | #if !STDEXEC_NO_STDCPP_EXCEPTIONS() |
112 | 199 | TEST_CASE("libdispatch bulk should handle exceptions gracefully") |
113 | 200 | { |
@@ -241,10 +328,11 @@ namespace |
241 | 328 | TEST_CASE("libdispatch bulk connects an lvalue child sender as an lvalue") |
242 | 329 | { |
243 | 330 | exec::libdispatch_queue queue; |
244 | | - auto fun = [](int, int &) noexcept {}; |
245 | | - using sender_t = exec::__libdispatch::bulk_sender<lvalue_connect_sender, int, decltype(fun)>; |
| 331 | + auto fun = [](int, int, int &) noexcept {}; |
| 332 | + using sender_t = |
| 333 | + exec::__libdispatch::bulk_sender<lvalue_connect_sender, int, decltype(fun), true>; |
246 | 334 |
|
247 | | - sender_t sender{queue, lvalue_connect_sender{}, 0, std::move(fun)}; |
| 335 | + sender_t sender{queue, lvalue_connect_sender{}, 0, std::move(fun), true}; |
248 | 336 | auto result = STDEXEC::sync_wait(sender); |
249 | 337 |
|
250 | 338 | REQUIRE(result.has_value()); |
|
0 commit comments