138 template <
typename stream_type,
139 typename seq_legal_alph_type,
140 typename stream_pos_type,
146 stream_pos_type & position_buffer,
149 qual_type & qualities);
151 template <
typename stream_type,
159 qual_type && qualities);
161 template <
typename stream_type,
162 typename seq_legal_alph_type,
163 typename ref_seqs_type,
164 typename ref_ids_type,
165 typename stream_pos_type,
168 typename offset_type,
169 typename ref_seq_type,
170 typename ref_id_type,
171 typename ref_offset_type,
178 typename tag_dict_type,
179 typename e_value_type,
180 typename bit_score_type>
183 ref_seqs_type & ref_seqs,
185 stream_pos_type & position_buffer,
189 offset_type & offset,
190 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
191 ref_id_type & ref_id,
192 ref_offset_type & ref_offset,
194 cigar_type & cigar_vector,
198 tag_dict_type & tag_dict,
199 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
200 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score));
202 template <
typename stream_type,
203 typename header_type,
206 typename ref_seq_type,
207 typename ref_id_type,
211 typename tag_dict_type,
212 typename e_value_type,
213 typename bit_score_type>
216 header_type && header,
220 int32_t
const offset,
221 ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
222 ref_id_type && ref_id,
229 tag_dict_type && tag_dict,
230 e_value_type && SEQAN3_DOXYGEN_ONLY(e_value),
231 bit_score_type && SEQAN3_DOXYGEN_ONLY(bit_score));
253 template <
typename t>
256 return std::forward<t>(v);
259 template <
typename stream_view_type, arithmetic value_type>
263 template <
typename stream_view_type>
266 template <
typename stream_view_type>
269 template <
typename stream_it_t, std::ranges::forward_range field_type>
272 template <
typename stream_it_t>
275 template <
typename stream_it_t>
280template <
typename stream_type,
281 typename seq_legal_alph_type,
282 typename stream_pos_type,
288 stream_pos_type & position_buffer,
291 qual_type & qualities)
318 if constexpr (!detail::decays_to_ignore_v<seq_type>)
319 if (std::ranges::distance(
sequence) == 0)
320 throw parse_error{
"The sequence information must not be empty."};
321 if constexpr (!detail::decays_to_ignore_v<id_type>)
322 if (std::ranges::distance(
id) == 0)
323 throw parse_error{
"The id information must not be empty."};
330template <
typename stream_type,
338 qual_type && qualities)
366template <
typename stream_type,
367 typename seq_legal_alph_type,
368 typename ref_seqs_type,
369 typename ref_ids_type,
370 typename stream_pos_type,
373 typename offset_type,
374 typename ref_seq_type,
375 typename ref_id_type,
376 typename ref_offset_type,
383 typename tag_dict_type,
384 typename e_value_type,
385 typename bit_score_type>
389 ref_seqs_type & ref_seqs,
391 stream_pos_type & position_buffer,
395 offset_type & offset,
396 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
397 ref_id_type & ref_id,
398 ref_offset_type & ref_offset,
400 cigar_type & cigar_vector,
404 tag_dict_type & tag_dict,
405 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
406 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score))
408 static_assert(detail::decays_to_ignore_v<ref_offset_type>
409 || detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
410 "The ref_offset must be a specialisation of std::optional.");
416 int32_t ref_offset_tmp{};
417 std::ranges::range_value_t<
decltype(header.
ref_ids())> ref_id_tmp{};
418 [[maybe_unused]] int32_t offset_tmp{};
419 [[maybe_unused]] int32_t soft_clipping_end{};
421 [[maybe_unused]] int32_t ref_length{0}, seq_length{0};
434 position_buffer = stream.tellg();
438 if constexpr (!detail::decays_to_ignore_v<id_type>)
443 uint16_t flag_integral{};
453 if (ref_offset_tmp == -1)
455 else if (ref_offset_tmp > -1)
457 else if (ref_offset_tmp < -1)
458 throw format_error{
"No negative values are allowed for field::ref_offset."};
460 if constexpr (!detail::decays_to_ignore_v<mapq_type>)
467 if constexpr (!detail::decays_to_ignore_v<align_type> || !detail::decays_to_ignore_v<cigar_type>)
489 if constexpr (!detail::decays_to_ignore_v<mate_type>)
491 std::ranges::range_value_t<
decltype(header.
ref_ids())> tmp_mate_ref_id{};
494 if (tmp_mate_ref_id ==
"=")
496 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
510 get<1>(
mate) = --tmp_pnext;
511 else if (tmp_pnext < 0)
512 throw format_error{
"No negative values are allowed at the mate mapping position."};
519 for (
size_t i = 0; i < 3u; ++i)
529 constexpr auto is_legal_alph = char_is_valid_for<seq_legal_alph_type>;
533 [is_legal_alph](
char const c)
535 if (!is_legal_alph(c))
537 + detail::type_name_as_string<seq_legal_alph_type>
542 if constexpr (detail::decays_to_ignore_v<seq_type>)
544 if constexpr (!detail::decays_to_ignore_v<align_type>)
547 "If you want to read ALIGNMENT but not SEQ, the alignment"
548 " object must store a sequence container at the second (query) position.");
550 if (!tmp_cigar_vector.empty())
554 std::ranges::advance(tmp_iter, offset_tmp);
556 for (; seq_length > 0; --seq_length)
558 get<1>(align).push_back(
559 std::ranges::range_value_t<
decltype(get<1>(align))>{}.assign_char(*tmp_iter));
563 std::ranges::advance(tmp_iter, soft_clipping_end);
579 if constexpr (!detail::decays_to_ignore_v<align_type>)
581 if (!tmp_cigar_vector
584 assign_unaligned(get<1>(align),
599 auto const tab_or_end = is_char<'\t'> || is_char<'\r'> || is_char<'\n'>;
601 if constexpr (!detail::decays_to_ignore_v<qual_type>)
606 if constexpr (!detail::decays_to_ignore_v<seq_type> && !detail::decays_to_ignore_v<qual_type>)
608 if (std::ranges::distance(
seq) != 0 && std::ranges::distance(
qual) != 0
609 && std::ranges::distance(
seq) != std::ranges::distance(
qual))
612 std::ranges::distance(
seq),
613 ") and quality length (",
614 std::ranges::distance(
qual),
615 ") must be the same.")};
625 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
637 if constexpr (!detail::decays_to_ignore_v<align_type>)
639 int32_t ref_idx{(ref_id_tmp.empty() ) ? -1 : 0};
641 if constexpr (!detail::decays_to_ignore_v<ref_seqs_type>)
643 if (!ref_id_tmp.empty())
645 assert(header.
ref_dict.count(ref_id_tmp) != 0);
646 ref_idx = header.
ref_dict[ref_id_tmp];
650 construct_alignment(align, tmp_cigar_vector, ref_idx, ref_seqs, ref_offset_tmp, ref_length);
653 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
654 std::swap(cigar_vector, tmp_cigar_vector);
658template <
typename stream_type,
659 typename header_type,
662 typename ref_seq_type,
663 typename ref_id_type,
667 typename tag_dict_type,
668 typename e_value_type,
669 typename bit_score_type>
672 header_type && header,
676 int32_t
const offset,
677 ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
678 ref_id_type && ref_id,
685 tag_dict_type && tag_dict,
686 e_value_type && SEQAN3_DOXYGEN_ONLY(e_value),
687 bit_score_type && SEQAN3_DOXYGEN_ONLY(bit_score))
706 "The seq object must be a std::ranges::forward_range over "
707 "letters that model seqan3::alphabet.");
710 "The id object must be a std::ranges::forward_range over "
711 "letters that model seqan3::alphabet.");
713 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
715 static_assert((std::ranges::forward_range<ref_id_type> || std::integral<std::remove_reference_t<ref_id_type>>
716 || detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>),
717 "The ref_id object must be a std::ranges::forward_range "
718 "over letters that model seqan3::alphabet.");
720 if constexpr (std::integral<std::remove_cvref_t<ref_id_type>>
721 || detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>)
722 static_assert(!detail::decays_to_ignore_v<header_type>,
723 "If you give indices as reference id information the header must also be present.");
727 "The align object must be a std::pair of two ranges whose "
728 "value_type is comparable to seqan3::gap");
730 static_assert((std::tuple_size_v<std::remove_cvref_t<align_type>> == 2
731 && std::equality_comparable_with<gap, std::ranges::range_reference_t<decltype(std::get<0>(align))>>
732 && std::equality_comparable_with<
gap, std::ranges::range_reference_t<
decltype(std::get<1>(align))>>),
733 "The align object must be a std::pair of two ranges whose "
734 "value_type is comparable to seqan3::gap");
737 "The qual object must be a std::ranges::forward_range "
738 "over letters that model seqan3::alphabet.");
741 "The mate object must be a std::tuple of size 3 with "
742 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
743 "2) a std::integral or std::optional<std::integral>, and "
744 "3) a std::integral.");
747 ((std::ranges::forward_range<decltype(std::get<0>(
mate))>
749 || detail::is_type_specialisation_of_v<
751 std::optional>)&&(std::integral<std::remove_cvref_t<decltype(std::get<1>(
mate))>>
752 || detail::is_type_specialisation_of_v<
754 std::optional>)&&std::integral<std::remove_cvref_t<decltype(std::get<2>(
mate))>>),
755 "The mate object must be a std::tuple of size 3 with "
756 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
757 "2) a std::integral or std::optional<std::integral>, and "
758 "3) a std::integral.");
760 if constexpr (std::integral<std::remove_cvref_t<decltype(std::get<0>(
mate))>>
763 static_assert(!detail::decays_to_ignore_v<header_type>,
764 "If you give indices as mate reference id information the header must also be present.");
767 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
772 if constexpr (!detail::decays_to_ignore_v<header_type> && !detail::decays_to_ignore_v<ref_id_type>
773 && !std::integral<std::remove_reference_t<ref_id_type>>
774 && !detail::is_type_specialisation_of_v<std::remove_reference_t<ref_id_type>,
std::optional>)
781 if constexpr (std::ranges::contiguous_range<
decltype(
ref_id)> && std::ranges::sized_range<
decltype(
ref_id)>
782 && std::ranges::borrowed_range<
decltype(
ref_id)>)
791 "The ref_id type is not convertible to the reference id information stored in the "
792 "reference dictionary of the header object.");
800 "' was not in the list of references:",
806 throw format_error{
"The ref_offset object must be a std::integral >= 0."};
811 if constexpr (!detail::decays_to_ignore_v<header_type>)
825 constexpr char separator{
'\t'};
828 *stream_it = separator;
830 stream_it.write_number(
static_cast<uint16_t
>(
flag));
831 *stream_it = separator;
833 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
835 if constexpr (std::integral<std::remove_reference_t<ref_id_type>>)
839 else if constexpr (detail::is_type_specialisation_of_v<std::remove_reference_t<ref_id_type>,
std::optional>)
856 *stream_it = separator;
859 stream_it.write_number(
ref_offset.value_or(-1) + 1);
860 *stream_it = separator;
862 stream_it.write_number(
static_cast<unsigned>(
mapq));
863 *stream_it = separator;
865 if (!std::ranges::empty(cigar_vector))
867 for (
auto & c : cigar_vector)
868 stream_it.write_range(c.to_string());
870 else if (!std::ranges::empty(get<0>(align)) && !std::ranges::empty(get<1>(align)))
877 for (
auto chr : get<1>(align))
892 *stream_it = separator;
894 if constexpr (std::integral<std::remove_reference_t<decltype(get<0>(
mate))>>)
898 else if constexpr (detail::is_type_specialisation_of_v<std::remove_reference_t<decltype(get<0>(
mate))>,
901 if (get<0>(
mate).has_value())
911 *stream_it = separator;
913 if constexpr (detail::is_type_specialisation_of_v<std::remove_cvref_t<decltype(get<1>(
mate))>,
std::optional>)
916 stream_it.write_number(get<1>(
mate).value_or(-1) + 1);
917 *stream_it = separator;
921 stream_it.write_number(get<1>(
mate));
922 *stream_it = separator;
925 stream_it.write_number(get<2>(
mate));
926 *stream_it = separator;
929 *stream_it = separator;
955template <
typename stream_view_type, arithmetic value_type>
957 stream_view_type && stream_view,
969 variant = std::move(tmp_vector);
985template <
typename stream_view_type>
999 throw format_error{
"Hexadecimal tag has an uneven number of digits!"};
1005 variant = std::move(tmp_vector);
1025template <
typename stream_view_type>
1066 target[tag] = stream_view | ranges::to<std::string>();
1080 switch (array_value_type_id)
1105 +
"id of a SAM tag must be one of [cCsSiIf] but '" + array_value_type_id
1112 "SAM tag must be one of [A,i,Z,H,B,f] but '")
1113 + type_id +
"' was given."};
1124template <
typename stream_it_t, std::ranges::forward_range field_type>
1127 if (std::ranges::empty(field_value))
1133 if constexpr (std::same_as<std::remove_cvref_t<std::ranges::range_reference_t<field_type>>,
char>)
1134 stream_it.write_range(field_value);
1146template <
typename stream_it_t>
1159template <
typename stream_it_t>
1163 auto const stream_variant_fn = [&stream_it](
auto && arg)
1167 if constexpr (std::ranges::input_range<T>)
1169 if constexpr (std::same_as<std::remove_cvref_t<std::ranges::range_reference_t<T>>,
char>)
1171 stream_it.write_range(arg);
1173 else if constexpr (std::same_as<std::remove_cvref_t<std::ranges::range_reference_t<T>>,
std::byte>)
1175 if (!std::ranges::empty(arg))
1182 stream_it.write_number(std::to_integer<uint8_t>(elem));
1188 if (!std::ranges::empty(arg))
1195 stream_it.write_number(elem);
1200 else if constexpr (std::same_as<std::remove_cvref_t<T>,
char>)
1206 stream_it.write_number(arg);
1210 for (
auto & [tag, variant] : tag_dict)
1212 *stream_it = separator;
1214 char const char0 = tag / 256;
1215 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:40
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:343
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: core/range/detail/misc.hpp:28
sam_flag
An enum flag that describes the properties of an aligned read (given as a SAM record).
Definition: sam_flag.hpp:76
constexpr 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: io/sam_file/detail/cigar.hpp:148
std::string get_cigar_string(std::vector< cigar > const &cigar_vector)
Transforms a vector of cigar elements into a string representation.
Definition: io/sam_file/detail/cigar.hpp:276
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:45
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:42
@ 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:560
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:590
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:602
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:588
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:574
constexpr auto istreambuf
A view factory that returns a view over the stream buffer of an input stream.
Definition: istreambuf_view.hpp:107
@ 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:125
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: type_list/traits.hpp:395
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: type_list/traits.hpp:470
constexpr size_t size
The size of a type pack.
Definition: type_pack/traits.hpp:146
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:178
The generic alphabet concept that covers most data types used in ranges.
Checks whether from can be implicityly converted to to.
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
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: io/exception.hpp:48
The options type defines various option members that influence the behavior of all or some formats.
Definition: sam_file/output_options.hpp:26
bool add_carriage_return
The default plain text line-ending is "\n", but on Windows an additional carriage return is recommend...
Definition: sam_file/output_options.hpp:30
bool sam_require_header
Whether to require a header for SAM files.
Definition: sam_file/output_options.hpp:44
The options type defines various option members that influence the behaviour of all or some formats.
Definition: sequence_file/output_options.hpp:26
Provides seqan3::views::take_until and seqan3::views::take_until_or_throw.
Provides seqan3::ranges::to.
Provides seqan3::views::to_char.
Provides traits to inspect some information of a type, for example its name.
Provides seqan3::tuple_like.