31 namespace seqan3::detail
59 template <std::ranges::view urng_t, simd::simd_concept simd_t>
60 class view_to_simd :
public std::ranges::view_interface<view_to_simd<urng_t, simd_t>>
64 static_assert(std::ranges::forward_range<urng_t>,
65 "The underlying range must model forward_range.");
66 static_assert(std::ranges::input_range<std::ranges::range_value_t<urng_t>>,
67 "Expects the value type of the underlying range to be an input_range.");
68 static_assert(std::default_initializable<std::ranges::range_value_t<urng_t>>,
69 "Expects the inner range to be default constructible.");
70 static_assert(
semialphabet<std::ranges::range_value_t<std::ranges::range_value_t<urng_t>>>,
71 "Expects semi-alphabet as value type of the inner range.");
76 using inner_range_type = std::ranges::range_value_t<urng_t>;
78 using scalar_type =
typename simd_traits<simd_t>::scalar_type;
80 using max_simd_type = simd_type_t<uint8_t, simd_traits<simd_t>::max_length>;
87 static constexpr
bool fast_load = std::ranges::contiguous_range<inner_range_type> &&
88 std::sized_sentinel_for<std::ranges::iterator_t<inner_range_type>,
89 std::ranges::sentinel_t<inner_range_type>> &&
90 sizeof(alphabet_rank_t<std::ranges::range_value_t<inner_range_type>>) == 1;
93 static constexpr uint8_t chunk_size = simd_traits<simd_t>::length;
95 static constexpr uint8_t chunks_per_load = simd_traits<simd_t>::max_length / chunk_size;
97 static constexpr uint8_t total_chunks = fast_load ? (chunks_per_load * chunks_per_load) : 1;
99 static constexpr
auto alphabet_size = alphabet_size<std::ranges::range_value_t<inner_range_type>>;
103 struct iterator_type;
110 constexpr view_to_simd() =
default;
111 constexpr view_to_simd(view_to_simd
const &) =
default;
112 constexpr view_to_simd(view_to_simd &&) =
default;
113 constexpr view_to_simd & operator=(view_to_simd
const &) =
default;
114 constexpr view_to_simd & operator=(view_to_simd &&) =
default;
115 ~view_to_simd() =
default;
121 constexpr view_to_simd(urng_t urng, scalar_type
const padding_value =
alphabet_size) :
123 padding_simd_vector{simd::
fill<simd_t>(padding_value)},
124 padding_value{padding_value}
127 if (std::ranges::distance(urng) > chunk_size)
128 throw std::invalid_argument{
"The size of the underlying range must be less than or equal to the size of "
129 "the given simd type!"};
133 template <
typename other_urng_t>
136 (!std::same_as<other_urng_t, urng_t>) &&
137 std::ranges::viewable_range<other_urng_t>
139 constexpr view_to_simd(other_urng_t && urng, scalar_type
const padding_value =
alphabet_size) :
148 constexpr iterator_type
begin() noexcept
154 constexpr
void begin() const noexcept = delete;
157 constexpr
std::default_sentinel_t end() noexcept
159 return std::default_sentinel;
163 constexpr
void end() const noexcept = delete;
167 constexpr
bool empty() const noexcept
169 requires
std::ranges::forward_range<inner_range_type>
172 return std::ranges::all_of(urng, [] (
auto & rng)
174 return std::ranges::empty(rng);
184 constexpr
size_t size() const noexcept
186 requires
std::ranges::sized_range<inner_range_type>
189 auto it = std::ranges::max_element(urng, [] (
auto & lhs,
auto & rhs)
194 return (it != std::ranges::end(urng)) ? (
std::ranges::size(*it) + chunk_size - 1) / chunk_size : 0;
201 simd_t padding_simd_vector{};
202 scalar_type padding_value{};
212 template <std::ranges::view urng_t, simd::simd_concept simd_t>
213 class view_to_simd<urng_t, simd_t>::iterator_type
220 using value_type = reference;
221 using pointer = void;
222 using difference_type = ptrdiff_t;
224 using iterator_concept = iterator_category;
230 constexpr iterator_type() =
default;
231 constexpr iterator_type(iterator_type
const &) =
default;
232 constexpr iterator_type(iterator_type &&) =
default;
233 constexpr iterator_type & operator=(iterator_type
const &) =
default;
234 constexpr iterator_type & operator=(iterator_type &&) =
default;
235 ~iterator_type() =
default;
245 constexpr iterator_type(view_to_simd & this_view) : this_view{&this_view}, current_chunk_pos{0}
249 for (
auto it = std::ranges::begin(this_view.urng); it != std::ranges::end(this_view.urng); ++it, ++seq_id)
252 cached_sentinel[seq_id] = std::ranges::end(*it);
262 auto sentinel_it = std::ranges::next(cached_iter[0], cached_sentinel[0]);
263 for (; seq_id < chunk_size; ++seq_id)
265 cached_iter[seq_id] = sentinel_it;
266 cached_sentinel[seq_id] = cached_sentinel[0];
270 final_chunk = all_iterators_reached_sentinel();
281 constexpr reference operator*() const noexcept
283 assert(this_view !=
nullptr);
284 return std::span{this_view->cached_simd_chunks[current_chunk_pos].begin(),
285 (current_chunk_pos == final_chunk_pos) ? final_chunk_size : chunk_size};
293 constexpr iterator_type & operator++()
295 if constexpr (fast_load)
297 if (current_chunk_pos == final_chunk_pos)
300 current_chunk_pos = 0;
316 constexpr value_type operator++(
int )
318 value_type tmp = this->operator*();
328 constexpr
bool operator==(std::default_sentinel_t
const &)
const noexcept
334 friend constexpr
bool operator==(std::default_sentinel_t
const &, iterator_type
const & rhs) noexcept
340 constexpr
bool operator!=(std::default_sentinel_t
const &)
const noexcept
346 friend constexpr
bool operator!=(std::default_sentinel_t
const &, iterator_type
const & rhs) noexcept
363 auto unpack(max_simd_type
const & row)
const
365 if constexpr (chunk_size == simd_traits<max_simd_type>::length / 2)
367 return std::array{simd::upcast<simd_t>(extract_half<0>(row)),
368 simd::upcast<simd_t>(extract_half<1>(row))};
370 else if constexpr (chunk_size == simd_traits<max_simd_type>::length / 4)
372 return std::array{simd::upcast<simd_t>(extract_quarter<0>(row)),
373 simd::upcast<simd_t>(extract_quarter<1>(row)),
374 simd::upcast<simd_t>(extract_quarter<2>(row)),
375 simd::upcast<simd_t>(extract_quarter<3>(row))};
377 else if constexpr (chunk_size == simd_traits<max_simd_type>::length / 8)
379 return std::array{simd::upcast<simd_t>(extract_eighth<0>(row)),
380 simd::upcast<simd_t>(extract_eighth<1>(row)),
381 simd::upcast<simd_t>(extract_eighth<2>(row)),
382 simd::upcast<simd_t>(extract_eighth<3>(row)),
383 simd::upcast<simd_t>(extract_eighth<4>(row)),
384 simd::upcast<simd_t>(extract_eighth<5>(row)),
385 simd::upcast<simd_t>(extract_eighth<6>(row)),
386 simd::upcast<simd_t>(extract_eighth<7>(row))};
404 constexpr
void split_into_sub_matrices(
std::array<max_simd_type, simd_traits<max_simd_type>::length> matrix)
const
406 auto apply_padding = [
this] (simd_t
const vec)
408 return (vec == simd::fill<simd_t>(
static_cast<uint8_t
>(~0))) ? this_view->padding_simd_vector : vec;
412 for (uint8_t row = 0; row < static_cast<uint8_t>(matrix.size()); ++row)
415 auto chunked_row = unpack(matrix[row]);
417 if constexpr (chunked_row.size() == 1)
419 this_view->cached_simd_chunks[0][row] = apply_padding(
std::move(chunked_row[0]));
423 static_assert(chunked_row.size() == chunks_per_load,
"Expected chunks_per_load many simd vectors.");
427 size_t idx =
chunk * chunks_per_load + row / chunk_size;
428 this_view->cached_simd_chunks[idx][row % chunk_size] = apply_padding(
std::move(chunked_row[
chunk]));
437 constexpr
bool all_iterators_reached_sentinel() const noexcept
441 return std::ranges::all_of(
views::zip(cached_iter, cached_sentinel), [] (
auto && iterator_sentinel_pair)
443 return get<0>(iterator_sentinel_pair) == get<1>(iterator_sentinel_pair);
457 constexpr simd_t convert_single_column()
460 simd_t simd_column{};
461 for (
size_t idx = 0u; idx < chunk_size; ++idx)
463 if (cached_iter[idx] == cached_sentinel[idx])
465 simd_column[idx] = this_view->padding_value;
469 simd_column[idx] =
static_cast<scalar_type
>(
seqan3::to_rank(*cached_iter[idx]));
486 template <
typename array_t>
487 constexpr
void update_final_chunk_position(array_t
const & iterators_before_update) noexcept
489 size_t max_distance = 0;
490 for (
auto && [it, sent] :
views::zip(iterators_before_update, cached_sentinel))
491 max_distance = std::max<size_t>(std::ranges::distance(it, sent), max_distance);
493 assert(max_distance > 0);
494 assert(max_distance <= (total_chunks * chunk_size));
497 final_chunk_pos = max_distance / chunk_size;
499 final_chunk_size = (max_distance % chunk_size) + 1;
503 constexpr
void underflow()
508 at_end = final_chunk;
534 constexpr int8_t max_size = simd_traits<simd_t>::max_length;
536 decltype(cached_iter) iterators_before_update{cached_iter};
538 for (uint8_t sequence_pos = 0; sequence_pos < chunk_size; ++sequence_pos)
540 for (uint8_t chunk_pos = 0; chunk_pos < chunks_per_load; ++chunk_pos)
542 uint8_t pos = chunk_pos * chunk_size + sequence_pos;
543 if (cached_sentinel[sequence_pos] - cached_iter[sequence_pos] >= max_size)
545 matrix[pos] = simd::load<max_simd_type>(
std::addressof(*cached_iter[sequence_pos]));
550 matrix[pos] = simd::fill<max_simd_type>(~0);
551 auto & sequence_it = cached_iter[sequence_pos];
552 for (int8_t idx = 0; sequence_it != cached_sentinel[sequence_pos]; ++sequence_it, ++idx)
559 final_chunk = all_iterators_reached_sentinel();
562 update_final_chunk_position(iterators_before_update);
564 simd::transpose(matrix);
565 split_into_sub_matrices(
std::move(matrix));
569 constexpr
void underflow()
571 requires (!fast_load)
574 at_end = final_chunk;
578 decltype(cached_iter) iterators_before_update{cached_iter};
579 for (
size_t i = 0; i < chunk_size; ++i)
580 this_view->cached_simd_chunks[0][i] = convert_single_column();
582 final_chunk = all_iterators_reached_sentinel();
585 update_final_chunk_position(iterators_before_update);
593 view_to_simd * this_view{
nullptr};
595 uint8_t final_chunk_size{chunk_size};
597 uint8_t final_chunk_pos{total_chunks - 1};
599 uint8_t current_chunk_pos{0};
601 bool final_chunk{
true};
618 template <simd::simd_concept simd_t>
622 using padding_t =
typename simd_traits<simd_t>::scalar_type;
627 constexpr
auto operator()(padding_t
const padding_value)
const noexcept
629 return detail::adaptor_from_functor{*
this, padding_value};
633 constexpr
auto operator()() const noexcept
635 return detail::adaptor_from_functor{*
this};
643 template <std::ranges::range urng_t>
644 constexpr
auto operator()(urng_t && urange, padding_t
const padding_value)
const noexcept
646 static_assert(std::ranges::forward_range<urng_t>,
647 "The underlying range in views::to_simd must model std::ranges::forward_range.");
648 static_assert(std::ranges::viewable_range<urng_t>,
649 "The underlying range in views::to_simd must model std::ranges::viewable_range.");
650 static_assert(std::ranges::input_range<std::ranges::range_value_t<urng_t>>,
651 "The value type of the underlying range must model std::ranges::input_range.");
652 static_assert(
semialphabet<std::ranges::range_value_t<std::ranges::range_value_t<urng_t>>>,
653 "The value type of the inner ranges must model seqan3::semialphabet.");
655 return view_to_simd<type_reduce_t<urng_t>, simd_t>{std::forward<urng_t>(urange), padding_value};
662 template <std::ranges::range urng_t>
663 constexpr
auto operator()(urng_t && urange)
const noexcept
665 static_assert(std::ranges::forward_range<urng_t>,
666 "The underlying range in views::to_simd must model std::ranges::forward_range.");
667 static_assert(std::ranges::viewable_range<urng_t>,
668 "The underlying range in views::to_simd must model std::ranges::viewable_range.");
669 static_assert(std::ranges::input_range<std::ranges::range_value_t<urng_t>>,
670 "The value type of the underlying range must model std::ranges::input_range.");
671 static_assert(
semialphabet<std::ranges::range_value_t<std::ranges::range_value_t<urng_t>>>,
672 "The value type of the inner ranges must model seqan3::semialphabet.");
674 return view_to_simd<type_reduce_t<urng_t>, simd_t>{std::forward<urng_t>(urange)};
678 template <std::ranges::range urng_t>
679 constexpr
friend auto operator|(urng_t && urange, to_simd_fn
const & me)
681 return me(std::forward<urng_t>(urange));
791 template <simd::simd_concept simd_t>
792 inline constexpr
auto to_simd = detail::to_simd_fn<simd_t>{};
Provides seqan3::detail::adaptor_from_functor.
Provides algorithms to modify seqan3::simd::simd_type.
Adaptations of algorithms from the Ranges TS.
Core alphabet concept and free function/type trait wrappers.
Provides various transformation traits used by the range module.
Provides type traits for working with templates.
constexpr auto alphabet_size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:858
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:155
auto operator|(validator1_type &&vali1, validator2_type &&vali2)
Enables the chaining of validators.
Definition: validators.hpp:1103
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto get
A view calling get on each element in a range.
Definition: elements.hpp:114
constexpr auto chunk
A chunk view.
Definition: chunk.hpp:29
constexpr auto zip
A zip view.
Definition: zip.hpp:29
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:74
constexpr auto type_reduce
A view adaptor that behaves like std::views::all, but type erases certain ranges.
Definition: type_reduce.hpp:158
The basis for seqan3::alphabet, but requires only rank interface (not char).
Provides C++20 additions to the <iterator> header.
The SeqAn namespace for views.
Definition: char_to.hpp:22
constexpr auto to_simd
A view that transforms a range of ranges into chunks of seqan3::simd vectors.
Definition: to_simd.hpp:792
SeqAn specific customisations in the standard namespace.
Provides algorithms for meta programming, parameter packs and seqan3::type_list.
Adaptations of concepts from the Ranges TS.
Provides seqan3::simd::simd_concept.
Provides seqan3::simd::simd_type.
Provides seqan3::simd::simd_traits.
Provides seqan3::views::type_reduce.
Provides seqan3::views::zip.