19 #include <range/v3/algorithm/for_each.hpp>
36 namespace seqan3::detail
40 template <
template <
typename ...>
typename container_type,
typename seq_alph_t,
typename ...rest_t>
44 constexpr
auto remove_gap_from_value_type(container_type<
gapped<seq_alph_t>, rest_t...>)
45 -> container_type<seq_alph_t, rest_t...>;
48 template <
template <
typename ...>
typename container_type,
49 template <
typename ...>
typename allocator_type,
50 typename seq_alph_t,
typename ...rest_t>
55 -> container_type<seq_alph_t, allocator_type<seq_alph_t>, rest_t...>;
66 requires { remove_gap_from_value_type(std::declval<t>()); }
68 struct unaligned_seq<t>
71 using type = decltype(remove_gap_from_value_type(std::declval<t>()));
80 struct unaligned_seq<t>
87 using unaligned_seq_t =
typename unaligned_seq<t>::type;
202 template <
typename t>
206 std::ranges::forward_range<t> &&
209 requires {
typename detail::unaligned_seq_t<t>; } &&
210 requires (t v, detail::unaligned_seq_t<t> unaligned)
212 {
insert_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t<t>;
213 {
insert_gap(v, std::ranges::begin(v), 2) } -> std::ranges::iterator_t<t>;
214 {
erase_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t<t>;
215 {
erase_gap(v, std::ranges::begin(v), std::ranges::end(v)) } -> std::ranges::iterator_t<t>;
244 template <sequence_container aligned_seq_t>
246 requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
248 inline typename aligned_seq_t::iterator
insert_gap(aligned_seq_t & aligned_seq,
249 typename aligned_seq_t::const_iterator pos_it)
270 template <sequence_container aligned_seq_t>
272 requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
274 inline typename aligned_seq_t::iterator
insert_gap(aligned_seq_t & aligned_seq,
275 typename aligned_seq_t::const_iterator pos_it,
276 typename aligned_seq_t::size_type
size)
300 template <sequence_container aligned_seq_t>
302 requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
304 inline typename aligned_seq_t::iterator
erase_gap(aligned_seq_t & aligned_seq,
305 typename aligned_seq_t::const_iterator pos_it)
307 if (*pos_it !=
gap{})
310 return aligned_seq.erase(pos_it);
333 template <sequence_container aligned_seq_t>
335 requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>>
337 inline typename aligned_seq_t::iterator
erase_gap(aligned_seq_t & aligned_seq,
338 typename aligned_seq_t::const_iterator first,
339 typename aligned_seq_t::const_iterator last)
341 for (
auto it = first; it != last; ++it)
343 throw gap_erase_failure(
"The range to be erased contains at least one non-gap character.");
345 return aligned_seq.erase(first, last);
370 template <sequence_container aligned_seq_t, std::ranges::forward_range unaligned_sequence_type>
372 requires detail::is_gapped_alphabet<value_type_t<aligned_seq_t>> &&
375 inline void assign_unaligned(aligned_seq_t & aligned_seq, unaligned_sequence_type && unaligned_seq)
379 tmp.resize(std::ranges::distance(unaligned_seq));
380 std::ranges::copy(unaligned_seq, std::ranges::begin(tmp));
381 swap(aligned_seq, tmp);
405 template <
typename range_type>
407 requires requires (range_type v)
409 v.insert_gap(std::ranges::iterator_t<range_type>{});
410 v.insert_gap(std::ranges::iterator_t<range_type>{},
typename range_type::size_type{});
413 std::ranges::iterator_t<range_type>
insert_gap(range_type & rng,
414 std::ranges::iterator_t<range_type>
const pos_it,
415 typename range_type::size_type
const size = 1)
417 return rng.insert_gap(pos_it,
size);
436 template <
typename range_type>
438 requires requires (range_type v) { v.erase_gap(std::ranges::iterator_t<range_type>{}); }
440 std::ranges::iterator_t<range_type>
erase_gap(range_type & rng,
441 std::ranges::iterator_t<range_type>
const pos_it)
443 return rng.erase_gap(pos_it);
464 template <
typename range_type>
466 requires requires (range_type v) { v.erase_gap(std::ranges::iterator_t<range_type>{}, std::ranges::iterator_t<range_type>{}); }
468 std::ranges::iterator_t<range_type>
erase_gap(range_type & rng,
469 std::ranges::iterator_t<range_type>
const first,
470 std::ranges::iterator_t<range_type>
const last)
472 return rng.erase_gap(first, last);
486 template <
typename char_t,
tuple_like alignment_t,
size_t ...idx>
490 size_t const alignment_size = get<0>(align).size();
493 for (
size_t begin_pos = 0; begin_pos < alignment_size; begin_pos += 50)
495 size_t const end_pos =
std::min(begin_pos + 50, alignment_size);
501 stream <<
std::setw(7) << begin_pos <<
' ';
502 for (
size_t pos = begin_pos + 1; pos <= end_pos; ++pos)
506 else if (pos % 5 == 0)
515 [&stream] (
char ch) { stream << ch; });
517 auto stream_f = [&] (
auto const & previous_seq,
auto const & aligned_seq)
521 std::ranges::for_each(views::zip(previous_seq, aligned_seq) |
views::slice(begin_pos, end_pos),
522 [&stream] (
auto && ch) { stream << (get<0>(ch) == get<1>(ch) ?
'|' :
' '); });
527 [&stream] (
char ch) { stream << ch; });
529 (stream_f(get<idx>(align), get<idx + 1>(align)), ...);
537 template <
typename ...elems>
538 inline bool constexpr all_satisfy_aligned_seq =
false;
543 template <
typename ...elems>
555 template <tuple_like tuple_t,
typename char_t>
557 requires detail::all_satisfy_aligned_seq<detail::tuple_type_list_t<tuple_t>>
561 static_assert(std::tuple_size_v<tuple_t> >= 2,
"An alignment requires at least two sequences.");