18 #include <type_traits>
24 namespace seqan3::detail
55 template <std::ranges::viewable_range resource_t,
56 std::semiregular algorithm_t,
57 std::semiregular algorithm_result_t,
58 typename execution_handler_t = execution_handler_sequential>
60 requires std::ranges::forward_range<resource_t> &&
61 std::invocable<algorithm_t, std::ranges::range_reference_t<resource_t>,
64 class algorithm_executor_blocking
70 using resource_type = std::views::all_t<resource_t>;
73 using resource_iterator_type = std::ranges::iterator_t<resource_type>;
82 using bucket_iterator_type = std::ranges::iterator_t<bucket_type>;
86 using buffer_iterator_type = std::ranges::iterator_t<buffer_type>;
102 algorithm_executor_blocking() =
delete;
105 algorithm_executor_blocking(algorithm_executor_blocking
const &) =
delete;
124 algorithm_executor_blocking(algorithm_executor_blocking && other) noexcept
130 algorithm_executor_blocking & operator=(algorithm_executor_blocking
const &) =
delete;
134 algorithm_executor_blocking & operator=(algorithm_executor_blocking && other)
141 ~algorithm_executor_blocking() =
default;
159 algorithm_executor_blocking(resource_t resource,
160 algorithm_t algorithm,
161 algorithm_result_t
const SEQAN3_DOXYGEN_ONLY(result) = algorithm_result_t{},
162 execution_handler_t && exec_handler = execution_handler_t{}) :
164 resource{std::views::all(resource)},
168 if constexpr (std::same_as<execution_handler_t, execution_handler_parallel>)
169 buffer_size =
static_cast<size_t>(std::ranges::distance(resource));
171 buffer.resize(buffer_size);
172 buffer_it = buffer.end();
173 buffer_end_it = buffer_it;
197 do {
status = fill_buffer(); }
while (status == fill_status::empty_buffer);
199 if (status == fill_status::end_of_resource)
200 return {std::nullopt};
202 assert(status == fill_status::non_empty_buffer);
203 assert(bucket_it != buffer_it->end());
213 return resource_it == std::ranges::end(resource);
218 fill_status fill_buffer()
220 if (!is_buffer_empty())
221 return fill_status::non_empty_buffer;
224 return fill_status::end_of_resource;
230 for (buffer_end_it = buffer_it; buffer_end_it != buffer.end() && !
is_eof(); ++buffer_end_it, ++resource_it)
232 exec_handler.execute(algorithm, *resource_it, [target_buffer_it = buffer_end_it] (
auto && algorithm_result)
234 target_buffer_it->push_back(
std::move(algorithm_result));
241 find_next_non_empty_bucket();
243 if (is_buffer_empty())
244 return fill_status::empty_buffer;
246 return fill_status::non_empty_buffer;
252 bool is_buffer_empty()
const
254 return buffer_it == buffer_end_it;
268 for (
auto & bucket : buffer)
272 buffer_it = buffer.begin();
283 void find_next_non_empty_bucket()
285 assert(buffer_it <= buffer_end_it);
287 buffer_it =
std::find_if(buffer_it, buffer_end_it, [] (
auto const & buffer)
289 return !buffer.empty();
292 if (buffer_it != buffer_end_it)
293 bucket_it = buffer_it->begin();
303 void go_to_next_result()
305 if (++bucket_it == buffer_it->end())
308 find_next_non_empty_bucket();
314 void move_initialise(algorithm_executor_blocking && other) noexcept
317 buffer_size =
std::move(other.buffer_size);
319 auto old_resource_position = std::ranges::distance(std::ranges::begin(other.resource),
323 resource_it = std::ranges::next(std::ranges::begin(resource), old_resource_position);
326 auto buffer_it_position = other.buffer_it - other.buffer.begin();
327 auto buffer_end_it_position = other.buffer_end_it - other.buffer.begin();
330 if (buffer_it_position != buffer_end_it_position)
331 bucket_it_position = other.bucket_it - other.buffer_it->begin();
335 buffer_it = buffer.begin() + buffer_it_position;
336 buffer_end_it = buffer.begin() + buffer_end_it_position;
338 if (buffer_it_position != buffer_end_it_position)
339 bucket_it = buffer_it->begin() + bucket_it_position;
343 execution_handler_t exec_handler{};
346 resource_type resource{};
348 resource_iterator_type resource_it{};
350 algorithm_t algorithm{};
353 buffer_type buffer{};
355 buffer_iterator_type buffer_it{};
357 buffer_iterator_type buffer_end_it{};
359 bucket_iterator_type bucket_it{};
361 size_t buffer_size{1};
369 template <
typename resource_rng_t, std::semiregular algorithm_t, std::semiregular algorithm_result_t>
371 algorithm_executor_blocking(resource_rng_t &&, algorithm_t, algorithm_result_t
const &) ->
372 algorithm_executor_blocking<resource_rng_t, algorithm_t, algorithm_result_t, execution_handler_sequential>;