137 template <
typename stream_type,
138 typename seq_legal_alph_type,
146 qual_type & qualities);
148 template <
typename stream_type,
156 qual_type && qualities);
158 template <
typename stream_type,
159 typename seq_legal_alph_type,
160 typename ref_seqs_type,
161 typename ref_ids_type,
164 typename offset_type,
165 typename ref_seq_type,
166 typename ref_id_type,
167 typename ref_offset_type,
174 typename tag_dict_type,
175 typename e_value_type,
176 typename bit_score_type>
179 ref_seqs_type & ref_seqs,
184 offset_type & offset,
185 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
186 ref_id_type & ref_id,
187 ref_offset_type & ref_offset,
189 cigar_type & cigar_vector,
193 tag_dict_type & tag_dict,
194 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
195 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score));
197 template <
typename stream_type,
198 typename header_type,
201 typename ref_seq_type,
202 typename ref_id_type,
206 typename tag_dict_type,
207 typename e_value_type,
208 typename bit_score_type>
211 header_type && header,
215 int32_t
const offset,
216 ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
217 ref_id_type && ref_id,
224 tag_dict_type && tag_dict,
225 e_value_type && SEQAN3_DOXYGEN_ONLY(e_value),
226 bit_score_type && SEQAN3_DOXYGEN_ONLY(bit_score));
248 template <
typename t>
251 return std::forward<t>(v);
254 using format_sam_base::read_field;
256 template <
typename stream_view_type,
typename value_type>
258 stream_view_type && stream_view,
261 template <
typename stream_view_type>
263 stream_view_type && stream_view);
265 template <
typename stream_view_type>
268 template <
typename stream_it_t, std::ranges::forward_range field_type>
271 template <
typename stream_it_t>
274 template <
typename stream_it_t>
279 template <
typename stream_type,
280 typename seq_legal_alph_type,
288 qual_type & qualities)
294 std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore,
295 std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore);
298 if constexpr (!detail::decays_to_ignore_v<seq_type>)
299 if (std::ranges::distance(
sequence) == 0)
300 throw parse_error{
"The sequence information must not be empty."};
301 if constexpr (!detail::decays_to_ignore_v<id_type>)
302 if (std::ranges::distance(
id) == 0)
303 throw parse_error{
"The id information must not be empty."};
310 template <
typename stream_type,
318 qual_type && qualities)
346 template <
typename stream_type,
347 typename seq_legal_alph_type,
348 typename ref_seqs_type,
349 typename ref_ids_type,
352 typename offset_type,
353 typename ref_seq_type,
354 typename ref_id_type,
355 typename ref_offset_type,
362 typename tag_dict_type,
363 typename e_value_type,
364 typename bit_score_type>
367 ref_seqs_type & ref_seqs,
372 offset_type & offset,
373 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
374 ref_id_type & ref_id,
375 ref_offset_type & ref_offset,
377 cigar_type & cigar_vector,
381 tag_dict_type & tag_dict,
382 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
383 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score))
385 static_assert(detail::decays_to_ignore_v<ref_offset_type> ||
386 detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
387 "The ref_offset must be a specialisation of std::optional.");
393 int32_t ref_offset_tmp{};
394 std::ranges::range_value_t<decltype(header.
ref_ids())> ref_id_tmp{};
395 [[maybe_unused]] int32_t offset_tmp{};
396 [[maybe_unused]] int32_t soft_clipping_end{};
398 [[maybe_unused]] int32_t ref_length{0}, seq_length{0};
402 if (is_char<'@'>(*std::ranges::begin(stream_view)))
406 if (std::ranges::begin(stream_view) == std::ranges::end(stream_view))
414 uint16_t flag_integral{};
424 if (ref_offset_tmp == -1)
426 else if (ref_offset_tmp > -1)
428 else if (ref_offset_tmp < -1)
429 throw format_error{
"No negative values are allowed for field::ref_offset."};
435 if constexpr (!detail::decays_to_ignore_v<align_type> || !detail::decays_to_ignore_v<cigar_type>)
437 if (!is_char<'*'>(*std::ranges::begin(stream_view)))
445 std::ranges::next(std::ranges::begin(field_view));
457 if constexpr (!detail::decays_to_ignore_v<mate_type>)
459 std::ranges::range_value_t<decltype(header.
ref_ids())> tmp_mate_ref_id{};
462 if (tmp_mate_ref_id ==
"=")
464 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
478 get<1>(
mate) = --tmp_pnext;
479 else if (tmp_pnext < 0)
480 throw format_error{
"No negative values are allowed at the mate mapping position."};
487 for (
size_t i = 0; i < 3u; ++i)
495 if (!is_char<'*'>(*std::ranges::begin(stream_view)))
497 auto constexpr is_legal_alph = char_is_valid_for<seq_legal_alph_type>;
500 if (!is_legal_alph(c))
502 "char_is_valid_for<" +
503 detail::type_name_as_string<seq_legal_alph_type> +
504 "> evaluated to false on " +
509 if constexpr (detail::decays_to_ignore_v<seq_type>)
511 if constexpr (!detail::decays_to_ignore_v<align_type>)
514 "If you want to read ALIGNMENT but not SEQ, the alignment"
515 " object must store a sequence container at the second (query) position.");
517 if (!tmp_cigar_vector.empty())
520 auto tmp_iter = std::ranges::begin(seq_stream);
521 std::ranges::advance(tmp_iter, offset_tmp);
523 for (; seq_length > 0; --seq_length)
525 get<1>(align).push_back(std::ranges::range_value_t<decltype(get<1>(align))>{}.assign_char(*tmp_iter));
529 std::ranges::advance(tmp_iter, soft_clipping_end);
545 if constexpr (!detail::decays_to_ignore_v<align_type>)
547 if (!tmp_cigar_vector.empty())
549 assign_unaligned(get<1>(align),
558 std::ranges::next(std::ranges::begin(field_view));
563 auto const tab_or_end = is_char<'\t'> || is_char<'\r'> || is_char<'\n'>;
566 if constexpr (!detail::decays_to_ignore_v<seq_type> && !detail::decays_to_ignore_v<qual_type>)
568 if (std::ranges::distance(
seq) != 0 && std::ranges::distance(
qual) != 0 &&
569 std::ranges::distance(
seq) != std::ranges::distance(
qual))
572 ") and quality length (", std::ranges::distance(
qual),
573 ") must be the same.")};
579 while (is_char<'\t'>(*std::ranges::begin(stream_view)))
581 std::ranges::next(std::ranges::begin(stream_view));
591 if constexpr (!detail::decays_to_ignore_v<align_type>)
593 int32_t ref_idx{(ref_id_tmp.empty()) ? -1 : 0};
595 if constexpr (!detail::decays_to_ignore_v<ref_seqs_type>)
597 if (!ref_id_tmp.empty())
599 assert(header.
ref_dict.count(ref_id_tmp) != 0);
600 ref_idx = header.
ref_dict[ref_id_tmp];
604 construct_alignment(align, tmp_cigar_vector, ref_idx, ref_seqs, ref_offset_tmp, ref_length);
607 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
608 std::swap(cigar_vector, tmp_cigar_vector);
612 template <
typename stream_type,
613 typename header_type,
616 typename ref_seq_type,
617 typename ref_id_type,
621 typename tag_dict_type,
622 typename e_value_type,
623 typename bit_score_type>
626 header_type && header,
630 int32_t
const offset,
631 ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
632 ref_id_type && ref_id,
639 tag_dict_type && tag_dict,
640 e_value_type && SEQAN3_DOXYGEN_ONLY(e_value),
641 bit_score_type && SEQAN3_DOXYGEN_ONLY(bit_score))
659 static_assert((std::ranges::forward_range<seq_type> &&
660 alphabet<std::ranges::range_reference_t<seq_type>>),
661 "The seq object must be a std::ranges::forward_range over "
662 "letters that model seqan3::alphabet.");
664 static_assert((std::ranges::forward_range<id_type> &&
665 alphabet<std::ranges::range_reference_t<id_type>>),
666 "The id object must be a std::ranges::forward_range over "
667 "letters that model seqan3::alphabet.");
669 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
671 static_assert((std::ranges::forward_range<ref_id_type> ||
674 "The ref_id object must be a std::ranges::forward_range "
675 "over letters that model seqan3::alphabet.");
679 static_assert(!detail::decays_to_ignore_v<header_type>,
680 "If you give indices as reference id information the header must also be present.");
684 "The align object must be a std::pair of two ranges whose "
685 "value_type is comparable to seqan3::gap");
688 std::equality_comparable_with<
gap, std::ranges::range_reference_t<decltype(std::get<0>(align))>> &&
689 std::equality_comparable_with<
gap, std::ranges::range_reference_t<decltype(std::get<1>(align))>>),
690 "The align object must be a std::pair of two ranges whose "
691 "value_type is comparable to seqan3::gap");
693 static_assert((std::ranges::forward_range<qual_type> &&
694 alphabet<std::ranges::range_reference_t<qual_type>>),
695 "The qual object must be a std::ranges::forward_range "
696 "over letters that model seqan3::alphabet.");
699 "The mate object must be a std::tuple of size 3 with "
700 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
701 "2) a std::integral or std::optional<std::integral>, and "
702 "3) a std::integral.");
704 static_assert(((std::ranges::forward_range<decltype(std::get<0>(
mate))> ||
710 "The mate object must be a std::tuple of size 3 with "
711 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
712 "2) a std::integral or std::optional<std::integral>, and "
713 "3) a std::integral.");
717 static_assert(!detail::decays_to_ignore_v<header_type>,
718 "If you give indices as mate reference id information the header must also be present.");
721 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
726 if constexpr (!detail::decays_to_ignore_v<header_type> &&
727 !detail::decays_to_ignore_v<ref_id_type> &&
736 if constexpr (std::ranges::contiguous_range<decltype(
ref_id)> &&
737 std::ranges::sized_range<decltype(
ref_id)> &&
738 std::ranges::borrowed_range<decltype(
ref_id)>)
747 "The ref_id type is not convertible to the reference id information stored in the "
748 "reference dictionary of the header object.");
760 throw format_error{
"The ref_offset object must be an std::integral >= 0."};
765 if constexpr (!detail::decays_to_ignore_v<header_type>)
779 constexpr
char separator{
'\t'};
782 *stream_it = separator;
784 stream_it.write_number(
static_cast<uint16_t
>(
flag));
785 *stream_it = separator;
787 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
810 *stream_it = separator;
813 stream_it.write_number(
ref_offset.value_or(-1) + 1);
814 *stream_it = separator;
816 stream_it.write_number(
static_cast<unsigned>(
mapq));
817 *stream_it = separator;
819 if (!std::ranges::empty(cigar_vector))
821 for (
auto & c : cigar_vector)
822 stream_it.write_range(c.to_string());
824 else if (!std::ranges::empty(get<0>(align)) && !std::ranges::empty(get<1>(align)))
831 for (
auto chr : get<1>(align))
846 *stream_it = separator;
854 if (get<0>(
mate).has_value())
866 *stream_it = separator;
871 stream_it.write_number(get<1>(
mate).value_or(-1) + 1);
872 *stream_it = separator;
876 stream_it.write_number(get<1>(
mate));
877 *stream_it = separator;
880 stream_it.write_number(get<2>(
mate));
881 *stream_it = separator;
884 *stream_it = separator;
911 template <
typename stream_view_type,
typename value_type>
913 stream_view_type && stream_view,
917 while (std::ranges::begin(stream_view) != ranges::end(stream_view))
922 if (is_char<','>(*std::ranges::begin(stream_view)))
923 std::ranges::next(std::ranges::begin(stream_view));
925 variant = std::move(tmp_vector);
941 template <
typename stream_view_type>
943 stream_view_type && stream_view)
948 while (std::ranges::begin(stream_view) != ranges::end(stream_view))
956 throw format_error{
"Hexadecimal tag has an uneven number of digits!"};
962 variant = std::move(tmp_vector);
982 template <
typename stream_view_type>
990 uint16_t tag =
static_cast<uint16_t
>(*std::ranges::begin(stream_view)) << 8;
991 std::ranges::next(std::ranges::begin(stream_view));
992 tag +=
static_cast<uint16_t
>(*std::ranges::begin(stream_view));
993 std::ranges::next(std::ranges::begin(stream_view));
994 std::ranges::next(std::ranges::begin(stream_view));
995 char type_id = *std::ranges::begin(stream_view);
996 std::ranges::next(std::ranges::begin(stream_view));
997 std::ranges::next(std::ranges::begin(stream_view));
1003 target[tag] =
static_cast<char>(*std::ranges::begin(stream_view));
1004 std::ranges::next(std::ranges::begin(stream_view));
1023 target[tag] = stream_view | views::to<std::string>;
1033 char array_value_type_id = *std::ranges::begin(stream_view);
1034 std::ranges::next(std::ranges::begin(stream_view));
1035 std::ranges::next(std::ranges::begin(stream_view));
1037 switch (array_value_type_id)
1062 "id of a SAM tag must be one of [cCsSiIf] but '" + array_value_type_id +
1069 "SAM tag must be one of [A,i,Z,H,B,f] but '") + type_id +
"' was given."};
1080 template <
typename stream_it_t, std::ranges::forward_range field_type>
1083 if (std::ranges::empty(field_value))
1089 if constexpr (std::same_as<
std::remove_cvref_t<std::ranges::range_reference_t<field_type>>,
char>)
1090 stream_it.write_range(field_value);
1102 template <
typename stream_it_t>
1115 template <
typename stream_it_t>
1118 auto const stream_variant_fn = [&stream_it] (
auto && arg)
1122 if constexpr (std::ranges::input_range<T>)
1126 stream_it.write_range(arg);
1130 if (!std::ranges::empty(arg))
1132 stream_it.write_number(std::to_integer<uint8_t>(*std::ranges::begin(arg)));
1137 stream_it.write_number(std::to_integer<uint8_t>(elem));
1143 if (!std::ranges::empty(arg))
1145 stream_it.write_number(*std::ranges::begin(arg));
1150 stream_it.write_number(elem);
1161 stream_it.write_number(arg);
1165 for (
auto & [tag, variant] : tag_dict)
1167 *stream_it = separator;
1169 char const char0 = tag / 256;
1170 char const char1 = tag % 256;
Core alphabet concept and free function/type trait wrappers.
Functionally the same as std::ostreambuf_iterator, but offers writing a range more efficiently.
Definition: fast_ostreambuf_iterator.hpp:39
The alphabet of a gap character '-'.
Definition: gap.hpp:39
The SAM tag dictionary class that stores all optional SAM fields.
Definition: sam_tag_dictionary.hpp:334
Provides seqan3::detail::fast_ostreambuf_iterator.
auto const to_char
A view that calls seqan3::to_char() on each element in the input range.
Definition: to_char.hpp:63
constexpr void consume(rng_t &&rng)
Iterate over a range (consumes single-pass input ranges).
Definition: misc.hpp:28
std::tuple< std::vector< cigar >, int32_t, int32_t > parse_cigar(cigar_input_type &&cigar_input)
Parses a cigar string into a vector of operation-count pairs (e.g. (M, 3)).
Definition: cigar.hpp:137
sam_flag
An enum flag that describes the properties of an aligned read (given as a SAM record).
Definition: sam_flag.hpp:74
std::string get_cigar_string(std::vector< cigar > const &cigar_vector)
Transforms a vector of cigar elements into a string representation.
Definition: cigar.hpp:266
constexpr char sam_tag_type_char_extra[12]
Each types SAM tag type extra char id. Index corresponds to the seqan3::detail::sam_tag_variant types...
Definition: sam_tag_dictionary.hpp:40
constexpr char sam_tag_type_char[12]
Each SAM tag type char identifier. Index corresponds to the seqan3::detail::sam_tag_variant types.
Definition: sam_tag_dictionary.hpp:37
@ none
None of the flags below are set.
constexpr auto take_until
A view adaptor that returns elements from the underlying range until the functor evaluates to true (o...
Definition: take_until_view.hpp:584
constexpr auto take_exactly_or_throw
A view adaptor that returns the first size elements from the underlying range and also exposes size i...
Definition: take_exactly_view.hpp:608
constexpr auto take_until_or_throw_and_consume
A view adaptor that returns elements from the underlying range until the functor evaluates to true (t...
Definition: take_until_view.hpp:626
constexpr auto take_until_and_consume
A view adaptor that returns elements from the underlying range until the functor evaluates to true (o...
Definition: take_until_view.hpp:612
constexpr auto take_until_or_throw
A view adaptor that returns elements from the underlying range until the functor evaluates to true (t...
Definition: take_until_view.hpp:598
constexpr auto istreambuf
A view factory that returns a view over the stream buffer of an input stream.
Definition: istreambuf_view.hpp:110
@ flag
The alignment flag (bit information), uint16_t value.
@ ref_offset
Sequence (seqan3::field::ref_seq) relative start position (0-based), unsigned value.
@ mapq
The mapping quality of the seqan3::field::seq alignment, usually a Phred-scaled score.
@ offset
Sequence (seqan3::field::seq) relative start position (0-based), unsigned value.
@ mate
The mate pair information given as a std::tuple of reference name, offset and template length.
@ ref_id
The identifier of the (reference) sequence that seqan3::field::seq was aligned to.
@ seq
The "sequence", usually a range of nucleotides or amino acids.
@ qual
The qualities, usually in Phred score notation.
std::string make_printable(char const c)
Returns a printable value for the given character c.
Definition: pretty_print.hpp:48
constexpr auto is_space
Checks whether c is a space character.
Definition: predicate.hpp:128
typename decltype(detail::split_after< i >(list_t{}))::second_type drop
Return a seqan3::type_list of the types in the input type list, except the first n.
Definition: traits.hpp:388
decltype(detail::transform< trait_t >(list_t{})) transform
Apply a transformation trait to every type in the list and return a seqan3::type_list of the results.
Definition: traits.hpp:471
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:183
The generic alphabet concept that covers most data types used in ranges.
Resolves to std::ranges::implicitly_convertible_to<type1, type2>(). <dl class="no-api">This entity i...
A more refined container concept than seqan3::container.
The generic concept for a (biological) sequence.
Whether a type behaves like a tuple.
Auxiliary functions for the alignment IO.
Provides seqan3::detail::istreambuf.
std::string to_string(value_type &&...values)
Streams all parameters via the seqan3::debug_stream and returns a concatenated string.
Definition: to_string.hpp:29
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
Adaptations of concepts from the Ranges TS.
Provides seqan3::sam_file_output_options.
Provides helper data structures for the seqan3::sam_file_output.
Provides the seqan3::sam_tag_dictionary class and auxiliaries.
Provides seqan3::sequence_file_output_options.
Provides seqan3::views::slice.
Thrown if there is a parse error, such as reading an unexpected character from an input stream.
Definition: exception.hpp:48
The options type defines various option members that influence the behavior of all or some formats.
Definition: output_options.hpp:23
bool add_carriage_return
The default plain text line-ending is "\n", but on Windows an additional carriage return is recommend...
Definition: output_options.hpp:27
bool sam_require_header
Whether to require a header for SAM files.
Definition: output_options.hpp:41
The options type defines various option members that influence the behaviour of all or some formats.
Definition: output_options.hpp:23
Provides seqan3::views::take_until and seqan3::views::take_until_or_throw.
Provides seqan3::views::to.
Provides seqan3::views::to_char.
Provides traits to inspect some information of a type, for example its name.
Provides seqan3::tuple_like.