SeqAn3  3.0.1
The Modern C++ library for sequence analysis.
alignment_executor_two_way.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
13 #pragma once
14 
15 #include <functional>
16 #include <optional>
17 #include <type_traits>
18 
29 #include <seqan3/std/ranges>
30 
31 namespace seqan3::detail
32 {
33 
47 template <std::ranges::viewable_range resource_t,
48  typename alignment_algorithm_t,
49  typename execution_handler_t = execution_handler_sequential>
51  requires std::ranges::forward_range<resource_t> &&
54 class alignment_executor_two_way
55 {
56 private:
60  using chunked_resource_type = typename chunked_indexed_sequence_pairs<resource_t>::type;
63  using chunked_resource_iterator = std::ranges::iterator_t<chunked_resource_type>;
65 
69  using alignment_result_type = typename alignment_algorithm_t::result_type;
72  using buffer_value_type = std::ranges::range_value_t<alignment_result_type>;
74  using buffer_type = std::vector<buffer_value_type>;
76  using buffer_pointer = std::ranges::iterator_t<buffer_type>;
78 
79 public:
80 
84  using value_type = buffer_value_type;
89  using difference_type = typename buffer_type::difference_type;
91 
96  alignment_executor_two_way() = delete;
99  alignment_executor_two_way(alignment_executor_two_way const &) = delete;
100 
118  alignment_executor_two_way(alignment_executor_two_way && other) noexcept
119  {
120  move_initialise(std::move(other));
121  }
122 
124  alignment_executor_two_way & operator=(alignment_executor_two_way const &) = delete;
125 
128  alignment_executor_two_way & operator=(alignment_executor_two_way && other)
129  {
130  move_initialise(std::move(other));
131  return *this;
132  }
133 
135  ~alignment_executor_two_way() = default;
136 
153  template <typename exec_policy_t = sequenced_policy>
155  requires is_execution_policy_v<exec_policy_t>
157  alignment_executor_two_way(resource_t resrc,
158  alignment_algorithm_t fn,
159  size_t chunk_size = 1u,
160  exec_policy_t const & SEQAN3_DOXYGEN_ONLY(exec) = seq) :
161  kernel{std::move(fn)},
162  _chunk_size{chunk_size}
163  {
164 
165  if (chunk_size == 0u)
166  throw std::invalid_argument{"The chunk size must be greater than 0."};
167 
168  chunked_resource = views::zip(std::forward<resource_t>(resrc), std::views::iota(0)) | views::chunk(_chunk_size);
169  chunked_resource_it = chunked_resource.begin();
170 
172  init_buffer(std::ranges::distance(resrc));
173  else
174  init_buffer(_chunk_size);
175  }
176 
178 
196  {
197  if (underflow() == eof)
198  return {std::nullopt};
199 
200  assert(gptr < egptr);
201  return {std::move(*gptr++)};
202  }
203 
205  constexpr size_t in_avail() const noexcept
206  {
207  return egptr - gptr;
208  }
210 
214  bool is_eof() noexcept
216  {
217  return chunked_resource_it == std::ranges::end(chunked_resource);
218  }
219 
221  constexpr size_t chunk_size() const noexcept
222  {
223  return _chunk_size;
224  }
226 
227 private:
228 
233  void setg(buffer_pointer beg, buffer_pointer end)
235  {
236  gptr = beg;
237  egptr = end;
238  }
239 
241  size_t underflow()
242  {
243  if (gptr < egptr) // Case: buffer not completely consumed
244  return in_avail();
245 
246  if (is_eof()) // Case: reached end of resource.
247  return eof;
248 
249  // Reset the get pointer.
250  setg(std::ranges::begin(buffer), std::ranges::end(buffer));
251 
252  using std::get;
253 
254  // Apply the alignment execution.
255  size_t count = 0;
256  size_t buffer_limit = in_avail();
257 
258  for (size_t current_chunk_size = std::ranges::distance(*chunked_resource_it);
259  count < buffer_limit && !is_eof();
260  count += current_chunk_size, gptr += current_chunk_size, ++chunked_resource_it)
261  {
262  auto && current_chunk = std::ranges::iter_move(chunked_resource_it);
263  current_chunk_size = std::ranges::distance(current_chunk);
264  assert(in_avail() >= current_chunk_size);
265 
266  exec_handler.execute(kernel, std::move(current_chunk), [write_to = gptr] (auto && alignment_results)
267  {
268  std::ranges::move(alignment_results, write_to);
269  });
270  }
271 
272  exec_handler.wait();
273 
274  // Update the available get positions to cover the part of the buffer that was filled.
275  setg(std::ranges::begin(buffer), std::ranges::begin(buffer) + count);
276 
277  return in_avail();
278  }
280 
288  void init_buffer(size_t const size)
289  {
290  buffer.resize(size);
291  setg(std::ranges::end(buffer), std::ranges::end(buffer));
292  }
293 
296  void move_initialise(alignment_executor_two_way && other) noexcept
297  {
298  kernel = std::move(other.kernel);
299  _chunk_size = std::move(other._chunk_size);
300  // Get the old resource position.
301  std::ptrdiff_t old_resource_pos = std::ranges::distance(other.chunked_resource.begin(),
302  other.chunked_resource_it);
303  // Move the resource and set the iterator state accordingly.
304  chunked_resource = std::move(other.chunked_resource);
305  chunked_resource_it = std::ranges::next(chunked_resource.begin(), old_resource_pos);
306 
307  // Get the old get pointer positions.
308  std::ptrdiff_t old_gptr_pos = other.gptr - buffer.begin();
309  std::ptrdiff_t old_egptr_pos = other.egptr - buffer.begin();
310  // Move the buffer and set the get pointer accordingly.
311  buffer = std::move(other.buffer);
312  setg(buffer.begin() + old_gptr_pos, buffer.begin() + old_egptr_pos);
313  }
315 
317  static constexpr size_t eof{std::numeric_limits<size_t>::max()};
318 
320  execution_handler_t exec_handler{};
321 
323  chunked_resource_type chunked_resource{};
325  chunked_resource_iterator chunked_resource_it{};
327  alignment_algorithm_t kernel{};
328 
330  buffer_type buffer{};
332  buffer_pointer gptr{};
334  buffer_pointer egptr{};
336  size_t _chunk_size{};
337 };
338 
344 template <typename resource_rng_t, typename func_t>
346 alignment_executor_two_way(resource_rng_t &&, func_t) ->
347  alignment_executor_two_way<resource_rng_t, func_t, execution_handler_sequential>;
348 
350 template <typename resource_rng_t, typename func_t, typename exec_policy_t>
351  requires is_execution_policy_v<exec_policy_t>
352 alignment_executor_two_way(resource_rng_t &&, func_t, size_t, exec_policy_t const &) ->
353  alignment_executor_two_way<resource_rng_t,
354  func_t,
356  execution_handler_parallel,
357  execution_handler_sequential>>;
358 
360 } // namespace seqan3::detail
shortcuts.hpp
Provides various shortcuts for common std::ranges functions.
zip.hpp
Provides seqan3::views::zip.
seqan3::field::seq
The "sequence", usually a range of nucleotides or amino acids.
alignment_range.hpp
Provides seqan3::detail::alignment_range.
type_traits.hpp
Provides helper type traits for the configuration and execution of the alignment algorithm.
functional
std::vector
seqan3::views::move
const auto move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
execution_handler_parallel.hpp
Provides seqan3::detail::execution_handler_parallel.
execution.hpp
Provides execution policies.
chunk.hpp
Provides seqan3::views::chunk.
same_as
The concept std::same_as<T, U> is satisfied if and only if T and U denote the same type.
seqan3::views::get
const auto get
A view calling std::get on each element in a range.
Definition: get.hpp:65
std::add_lvalue_reference_t
type_reduce.hpp
Provides seqan3::views::type_reduce.
range.hpp
Provides various transformation traits used by the range module.
std::invalid_argument
seqan3::pack_traits::size
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:116
ranges
Adaptations of concepts from the Ranges TS.
copy_constructible
The concept std::copy_constructible is satisfied if T is an lvalue reference type,...
seqan3::is_eof
constexpr auto is_eof
Checks whether a given letter is equal to the EOF constant defined in <cstdio>.
Definition: predicate.hpp:95
std::ptrdiff_t
optional
std::end
T end(T... args)
std::conditional_t
std::numeric_limits::max
T max(T... args)
seqan3::pack_traits::count
constexpr ptrdiff_t count
Count the occurrences of a type in a pack.
Definition: traits.hpp:134
execution_handler_sequential.hpp
Provides seqan3::detail::execution_handler_sequential.