30namespace seqan3::detail
58template <std::ranges::view urng_t, simd::simd_concept simd_t>
59class view_to_simd :
public std::ranges::view_interface<view_to_simd<urng_t, simd_t>>
63 static_assert(std::ranges::forward_range<urng_t>,
64 "The underlying range must model forward_range.");
65 static_assert(std::ranges::input_range<std::ranges::range_value_t<urng_t>>,
66 "Expects the value type of the underlying range to be an input_range.");
67 static_assert(std::default_initializable<std::ranges::range_value_t<urng_t>>,
68 "Expects the inner range to be default constructible.");
70 "Expects semi-alphabet as value type of the inner range.");
75 using inner_range_type = std::ranges::range_value_t<urng_t>;
77 using scalar_type =
typename simd_traits<simd_t>::scalar_type;
79 using max_simd_type = simd_type_t<uint8_t, simd_traits<simd_t>::max_length>;
86 static constexpr bool fast_load = std::ranges::contiguous_range<inner_range_type> &&
87 std::sized_sentinel_for<std::ranges::iterator_t<inner_range_type>,
88 std::ranges::sentinel_t<inner_range_type>> &&
89 sizeof(alphabet_rank_t<std::ranges::range_value_t<inner_range_type>>) == 1;
92 static constexpr uint8_t chunk_size = simd_traits<simd_t>::length;
94 static constexpr uint8_t chunks_per_load = simd_traits<simd_t>::max_length / chunk_size;
96 static constexpr uint8_t total_chunks = fast_load ? (chunks_per_load * chunks_per_load) : 1;
98 static constexpr auto alphabet_size = alphabet_size<std::ranges::range_value_t<inner_range_type>>;
102 struct iterator_type;
109 constexpr view_to_simd() =
default;
110 constexpr view_to_simd(view_to_simd
const &) =
default;
111 constexpr view_to_simd(view_to_simd &&) =
default;
112 constexpr view_to_simd & operator=(view_to_simd
const &) =
default;
113 constexpr view_to_simd & operator=(view_to_simd &&) =
default;
114 ~view_to_simd() =
default;
120 constexpr view_to_simd(urng_t urng, scalar_type
const padding_value =
alphabet_size) :
121 urng{
std::move(urng)},
122 padding_simd_vector{simd::
fill<simd_t>(padding_value)},
123 padding_value{padding_value}
126 if (std::ranges::distance(urng) > chunk_size)
127 throw std::invalid_argument{
"The size of the underlying range must be less than or equal to the size of "
128 "the given simd type!"};
132 template <
typename other_urng_t>
134 requires (!std::same_as<std::remove_cvref_t<other_urng_t>, view_to_simd>) &&
135 (!std::same_as<other_urng_t, urng_t>) &&
136 std::ranges::viewable_range<other_urng_t>
138 constexpr view_to_simd(other_urng_t && urng, scalar_type
const padding_value =
alphabet_size) :
147 constexpr iterator_type
begin() noexcept
153 constexpr void begin() const noexcept = delete;
156 constexpr
std::default_sentinel_t end() noexcept
158 return std::default_sentinel;
162 constexpr void end() const noexcept = delete;
166 constexpr
bool empty() const noexcept
168 requires
std::ranges::forward_range<inner_range_type>
171 return std::ranges::all_of(urng, [] (
auto & rng)
173 return std::ranges::empty(rng);
183 constexpr size_t size() const noexcept
185 requires
std::ranges::sized_range<inner_range_type>
188 auto it = std::ranges::max_element(urng, [] (
auto & lhs,
auto & rhs)
193 return (it != std::ranges::end(urng)) ? (
std::ranges::size(*it) + chunk_size - 1) / chunk_size : 0;
200 simd_t padding_simd_vector{};
201 scalar_type padding_value{};
211template <std::ranges::view urng_t, simd::simd_concept simd_t>
212class view_to_simd<urng_t, simd_t>::iterator_type
219 using value_type = reference;
220 using pointer = void;
221 using difference_type = ptrdiff_t;
223 using iterator_concept = iterator_category;
229 constexpr iterator_type() =
default;
230 constexpr iterator_type(iterator_type
const &) =
default;
231 constexpr iterator_type(iterator_type &&) =
default;
232 constexpr iterator_type & operator=(iterator_type
const &) =
default;
233 constexpr iterator_type & operator=(iterator_type &&) =
default;
234 ~iterator_type() =
default;
244 constexpr iterator_type(view_to_simd & this_view) : this_view{&this_view}, current_chunk_pos{0}
248 for (
auto it = std::ranges::begin(this_view.urng); it != std::ranges::end(this_view.urng); ++it, ++seq_id)
251 cached_sentinel[seq_id] = std::ranges::end(*it);
261 auto sentinel_it = std::ranges::next(cached_iter[0], cached_sentinel[0]);
262 for (; seq_id < chunk_size; ++seq_id)
264 cached_iter[seq_id] = sentinel_it;
265 cached_sentinel[seq_id] = cached_sentinel[0];
269 final_chunk = all_iterators_reached_sentinel();
280 constexpr reference operator*() const noexcept
282 assert(this_view !=
nullptr);
283 return std::span{this_view->cached_simd_chunks[current_chunk_pos].begin(),
284 (current_chunk_pos == final_chunk_pos) ? final_chunk_size : chunk_size};
292 constexpr iterator_type & operator++()
294 if constexpr (fast_load)
296 if (current_chunk_pos == final_chunk_pos)
299 current_chunk_pos = 0;
315 constexpr value_type operator++(
int )
317 value_type tmp = this->operator*();
327 constexpr bool operator==(std::default_sentinel_t
const &)
const noexcept
333 friend constexpr bool operator==(std::default_sentinel_t
const &, iterator_type
const & rhs)
noexcept
339 constexpr bool operator!=(std::default_sentinel_t
const &)
const noexcept
345 friend constexpr bool operator!=(std::default_sentinel_t
const &, iterator_type
const & rhs)
noexcept
362 auto unpack(max_simd_type
const & row)
const
364 if constexpr (chunk_size == simd_traits<max_simd_type>::length / 2)
366 return std::array{simd::upcast<simd_t>(extract_half<0>(row)),
367 simd::upcast<simd_t>(extract_half<1>(row))};
369 else if constexpr (chunk_size == simd_traits<max_simd_type>::length / 4)
371 return std::array{simd::upcast<simd_t>(extract_quarter<0>(row)),
372 simd::upcast<simd_t>(extract_quarter<1>(row)),
373 simd::upcast<simd_t>(extract_quarter<2>(row)),
374 simd::upcast<simd_t>(extract_quarter<3>(row))};
376 else if constexpr (chunk_size == simd_traits<max_simd_type>::length / 8)
378 return std::array{simd::upcast<simd_t>(extract_eighth<0>(row)),
379 simd::upcast<simd_t>(extract_eighth<1>(row)),
380 simd::upcast<simd_t>(extract_eighth<2>(row)),
381 simd::upcast<simd_t>(extract_eighth<3>(row)),
382 simd::upcast<simd_t>(extract_eighth<4>(row)),
383 simd::upcast<simd_t>(extract_eighth<5>(row)),
384 simd::upcast<simd_t>(extract_eighth<6>(row)),
385 simd::upcast<simd_t>(extract_eighth<7>(row))};
403 constexpr void split_into_sub_matrices(
std::array<max_simd_type, simd_traits<max_simd_type>::length> matrix)
const
405 auto apply_padding = [
this] (simd_t
const vec)
407 return (vec == simd::fill<simd_t>(
static_cast<uint8_t
>(~0))) ? this_view->padding_simd_vector : vec;
411 for (uint8_t row = 0; row < static_cast<uint8_t>(matrix.size()); ++row)
414 auto chunked_row = unpack(matrix[row]);
416 if constexpr (chunked_row.size() == 1)
418 this_view->cached_simd_chunks[0][row] = apply_padding(std::move(chunked_row[0]));
422 static_assert(chunked_row.size() == chunks_per_load,
"Expected chunks_per_load many simd vectors.");
426 size_t idx =
chunk * chunks_per_load + row / chunk_size;
427 this_view->cached_simd_chunks[idx][row % chunk_size] = apply_padding(std::move(chunked_row[
chunk]));
436 constexpr bool all_iterators_reached_sentinel() const noexcept
440 return std::ranges::all_of(
views::zip(cached_iter, cached_sentinel), [] (
auto && iterator_sentinel_pair)
442 return get<0>(iterator_sentinel_pair) == get<1>(iterator_sentinel_pair);
456 constexpr simd_t convert_single_column()
459 simd_t simd_column{};
460 for (
size_t idx = 0u; idx < chunk_size; ++idx)
462 if (cached_iter[idx] == cached_sentinel[idx])
464 simd_column[idx] = this_view->padding_value;
468 simd_column[idx] =
static_cast<scalar_type
>(
seqan3::to_rank(*cached_iter[idx]));
485 template <
typename array_t>
486 constexpr void update_final_chunk_position(array_t
const & iterators_before_update)
noexcept
488 size_t max_distance = 0;
489 for (
auto && [it, sent] :
views::zip(iterators_before_update, cached_sentinel))
490 max_distance = std::max<size_t>(std::ranges::distance(it, sent), max_distance);
492 assert(max_distance > 0);
493 assert(max_distance <= (total_chunks * chunk_size));
496 final_chunk_pos = max_distance / chunk_size;
498 final_chunk_size = (max_distance % chunk_size) + 1;
502 constexpr void underflow()
507 at_end = final_chunk;
533 constexpr int8_t max_size = simd_traits<simd_t>::max_length;
535 decltype(cached_iter) iterators_before_update{cached_iter};
537 for (uint8_t sequence_pos = 0; sequence_pos < chunk_size; ++sequence_pos)
539 for (uint8_t chunk_pos = 0; chunk_pos < chunks_per_load; ++chunk_pos)
541 uint8_t pos = chunk_pos * chunk_size + sequence_pos;
542 if (cached_sentinel[sequence_pos] - cached_iter[sequence_pos] >= max_size)
544 matrix[pos] = simd::load<max_simd_type>(
std::addressof(*cached_iter[sequence_pos]));
549 matrix[pos] = simd::fill<max_simd_type>(~0);
550 auto & sequence_it = cached_iter[sequence_pos];
551 for (int8_t idx = 0; sequence_it != cached_sentinel[sequence_pos]; ++sequence_it, ++idx)
558 final_chunk = all_iterators_reached_sentinel();
561 update_final_chunk_position(iterators_before_update);
563 simd::transpose(matrix);
564 split_into_sub_matrices(std::move(matrix));
568 constexpr void underflow()
570 requires (!fast_load)
573 at_end = final_chunk;
577 decltype(cached_iter) iterators_before_update{cached_iter};
578 for (
size_t i = 0; i < chunk_size; ++i)
579 this_view->cached_simd_chunks[0][i] = convert_single_column();
581 final_chunk = all_iterators_reached_sentinel();
584 update_final_chunk_position(iterators_before_update);
592 view_to_simd * this_view{
nullptr};
594 uint8_t final_chunk_size{chunk_size};
596 uint8_t final_chunk_pos{total_chunks - 1};
598 uint8_t current_chunk_pos{0};
600 bool final_chunk{
true};
617template <simd::simd_concept simd_t>
621 using padding_t =
typename simd_traits<simd_t>::scalar_type;
626 constexpr auto operator()(padding_t
const padding_value)
const noexcept
628 return detail::adaptor_from_functor{*
this, padding_value};
632 constexpr auto operator()() const noexcept
634 return detail::adaptor_from_functor{*
this};
642 template <std::ranges::range urng_t>
643 constexpr auto operator()(urng_t && urange, padding_t
const padding_value)
const noexcept
645 static_assert(std::ranges::forward_range<urng_t>,
646 "The underlying range in views::to_simd must model std::ranges::forward_range.");
647 static_assert(std::ranges::viewable_range<urng_t>,
648 "The underlying range in views::to_simd must model std::ranges::viewable_range.");
649 static_assert(std::ranges::input_range<std::ranges::range_value_t<urng_t>>,
650 "The value type of the underlying range must model std::ranges::input_range.");
652 "The value type of the inner ranges must model seqan3::semialphabet.");
654 return view_to_simd<type_reduce_t<urng_t>, simd_t>{std::forward<urng_t>(urange), padding_value};
661 template <std::ranges::range urng_t>
662 constexpr auto operator()(urng_t && urange)
const noexcept
664 static_assert(std::ranges::forward_range<urng_t>,
665 "The underlying range in views::to_simd must model std::ranges::forward_range.");
666 static_assert(std::ranges::viewable_range<urng_t>,
667 "The underlying range in views::to_simd must model std::ranges::viewable_range.");
668 static_assert(std::ranges::input_range<std::ranges::range_value_t<urng_t>>,
669 "The value type of the underlying range must model std::ranges::input_range.");
671 "The value type of the inner ranges must model seqan3::semialphabet.");
673 return view_to_simd<type_reduce_t<urng_t>, simd_t>{std::forward<urng_t>(urange)};
677 template <std::ranges::range urng_t>
678 constexpr friend auto operator|(urng_t && urange, to_simd_fn
const & me)
680 return me(std::forward<urng_t>(urange));
790template <simd::simd_concept simd_t>
791inline constexpr auto to_simd = detail::to_simd_fn<simd_t>{};
Provides seqan3::detail::adaptor_from_functor.
Provides algorithms to modify seqan3::simd::simd_type.
The <algorithm> header from C++20's standard library.
Core alphabet concept and free function/type trait wrappers.
Provides various transformation traits used by the range module.
constexpr auto alphabet_size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:861
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:1120
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto chunk
A chunk view.
Definition: chunk.hpp:29
constexpr auto zip
A zip view.
Definition: zip.hpp:29
constexpr auto type_reduce
A view adaptor that behaves like std::views::all, but type erases certain ranges.
Definition: type_reduce.hpp:153
The basis for seqan3::alphabet, but requires only rank interface (not char).
The <iterator> header from C++20's standard library.
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:791
constexpr auto const & get(configuration< configs_t... > const &config) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: configuration.hpp:429
SeqAn specific customisations in the standard namespace.
The <ranges> header from C++20's standard library.
Provides seqan3::simd::simd_type.
Provides seqan3::simd::simd_traits.
Provides type traits for working with templates.
Provides seqan3::views::type_reduce.
Provides seqan3::simd::simd_concept.
Provides seqan3::views::zip.