69 template <
typename stream_type,
70 typename seq_legal_alph_type,
71 typename ref_seqs_type,
72 typename ref_ids_type,
73 typename stream_pos_type,
76 typename ref_seq_type,
78 typename ref_offset_type,
84 typename tag_dict_type,
85 typename e_value_type,
86 typename bit_score_type>
89 ref_seqs_type & ref_seqs,
91 stream_pos_type & position_buffer,
95 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
97 ref_offset_type & ref_offset,
98 cigar_type & cigar_vector,
102 tag_dict_type & tag_dict,
103 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
104 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score));
106 template <
typename stream_type,
107 typename header_type,
110 typename ref_seq_type,
111 typename ref_id_type,
115 typename tag_dict_type>
118 [[maybe_unused]] header_type && header,
119 [[maybe_unused]] seq_type && seq,
120 [[maybe_unused]] qual_type && qual,
121 [[maybe_unused]] id_type &&
id,
122 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
123 [[maybe_unused]] ref_id_type && ref_id,
125 [[maybe_unused]] cigar_type && cigar_vector,
126 [[maybe_unused]]
sam_flag const flag,
127 [[maybe_unused]] uint8_t
const mapq,
128 [[maybe_unused]] mate_type && mate,
129 [[maybe_unused]] tag_dict_type && tag_dict,
130 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
131 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(bit_score));
134 template <
typename stream_t,
typename header_type>
139 bool header_was_read{
false};
145 struct alignment_record_core
150 uint32_t l_read_name : 8;
153 uint32_t n_cigar_op : 16;
171 ret[
static_cast<index_t
>(
'I')] = 1;
172 ret[
static_cast<index_t
>(
'D')] = 2;
173 ret[
static_cast<index_t
>(
'N')] = 3;
174 ret[
static_cast<index_t
>(
'S')] = 4;
175 ret[
static_cast<index_t
>(
'H')] = 5;
176 ret[
static_cast<index_t
>(
'P')] = 6;
177 ret[
static_cast<index_t
>(
'=')] = 7;
178 ret[
static_cast<index_t
>(
'X')] = 8;
186 static uint16_t reg2bin(int32_t beg, int32_t end)
noexcept
189 if (beg >> 14 == end >> 14)
190 return ((1 << 15) - 1) / 7 + (beg >> 14);
191 if (beg >> 17 == end >> 17)
192 return ((1 << 12) - 1) / 7 + (beg >> 17);
193 if (beg >> 20 == end >> 20)
194 return ((1 << 9) - 1) / 7 + (beg >> 20);
195 if (beg >> 23 == end >> 23)
196 return ((1 << 6) - 1) / 7 + (beg >> 23);
197 if (beg >> 26 == end >> 26)
198 return ((1 << 3) - 1) / 7 + (beg >> 26);
208 template <
typename stream_view_type, std::
integral number_type>
209 void read_integral_byte_field(stream_view_type && stream_view, number_type & target)
219 template <
typename stream_view_type>
220 void read_float_byte_field(stream_view_type && stream_view,
float & target)
225 template <
typename stream_view_type,
typename value_type>
227 stream_view_type && stream_view,
228 value_type
const & SEQAN3_DOXYGEN_ONLY(value));
230 template <
typename stream_view_type>
231 void read_sam_dict_field(stream_view_type && stream_view, sam_tag_dictionary & target);
233 template <
typename cigar_input_type>
234 auto parse_binary_cigar(cigar_input_type && cigar_input, uint16_t n_cigar_op)
const;
236 static std::string get_tag_dict_str(sam_tag_dictionary
const & tag_dict);
240template <
typename stream_type,
241 typename seq_legal_alph_type,
242 typename ref_seqs_type,
243 typename ref_ids_type,
244 typename stream_pos_type,
247 typename ref_seq_type,
248 typename ref_id_type,
249 typename ref_offset_type,
255 typename tag_dict_type,
256 typename e_value_type,
257 typename bit_score_type>
261 ref_seqs_type & ref_seqs,
263 stream_pos_type & position_buffer,
267 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
268 ref_id_type & ref_id,
269 ref_offset_type & ref_offset,
270 cigar_type & cigar_vector,
274 tag_dict_type & tag_dict,
275 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
276 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score))
278 static_assert(detail::decays_to_ignore_v<ref_offset_type>
279 || detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
280 "The ref_offset must be a specialisation of std::optional.");
282 static_assert(detail::decays_to_ignore_v<mapq_type> || std::same_as<mapq_type, uint8_t>,
283 "The type of field::mapq must be uint8_t.");
285 static_assert(detail::decays_to_ignore_v<flag_type> || std::same_as<flag_type, sam_flag>,
286 "The type of field::flag must be seqan3::sam_flag.");
288 auto stream_view = seqan3::detail::istreambuf(stream);
290 [[maybe_unused]] int32_t ref_length{};
294 if (!header_was_read)
305 read_integral_byte_field(stream_view, l_text);
308 read_header(stream_view | detail::take_exactly_or_throw(l_text), header, ref_seqs);
310 read_integral_byte_field(stream_view, n_ref);
312 for (int32_t ref_idx = 0; ref_idx < n_ref; ++ref_idx)
314 read_integral_byte_field(stream_view, l_name);
316 string_buffer.
resize(l_name - 1);
319 string_buffer.
data());
322 read_integral_byte_field(stream_view, l_ref);
324 if constexpr (detail::decays_to_ignore_v<ref_seqs_type>)
329 auto & reference_ids = header.
ref_ids();
333 reference_ids.push_back(string_buffer);
335 header.
ref_dict.emplace(reference_ids.back(), reference_ids.size() - 1);
340 auto id_it = header.
ref_dict.find(string_buffer);
345 throw format_error{detail::to_string(
"Unknown reference name '" + string_buffer
346 +
"' found in BAM file header (header.ref_ids():",
350 else if (id_it->second != ref_idx)
356 " does not correspond to the position ",
358 " in the header (header.ref_ids():",
362 else if (std::get<0>(header.
ref_id_info[id_it->second]) != l_ref)
364 throw format_error{
"Provided reference has unequal length as specified in the header."};
368 header_was_read =
true;
376 position_buffer = stream.tellg();
377 alignment_record_core core;
378 std::ranges::copy(stream_view | detail::take_exactly_or_throw(
sizeof(core)),
reinterpret_cast<char *
>(&core));
380 if (core.refID >=
static_cast<int32_t
>(header.
ref_ids().size()) || core.refID < -1)
382 throw format_error{detail::to_string(
"Reference id index '",
384 "' is not in range of ",
385 "header.ref_ids(), which has size ",
389 else if (core.refID > -1)
400 if constexpr (!detail::decays_to_ignore_v<mate_type>)
402 if (core.next_refID > -1)
403 get<0>(
mate) = core.next_refID;
405 if (core.next_pos > -1)
406 get<1>(
mate) = core.next_pos;
408 get<2>(
mate) = core.tlen;
413 auto id_view = stream_view | detail::take_exactly_or_throw(core.l_read_name - 1);
414 if constexpr (!detail::decays_to_ignore_v<id_type>)
415 read_forward_range_field(id_view,
id);
417 detail::consume(id_view);
422 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
424 int32_t seq_length{};
425 std::tie(cigar_vector, ref_length, seq_length) = parse_binary_cigar(stream_view, core.n_cigar_op);
429 detail::consume(stream_view | detail::take_exactly_or_throw(core.n_cigar_op * 4));
436 auto seq_stream = stream_view | detail::take_exactly_or_throw(core.l_seq / 2)
444 if constexpr (detail::decays_to_ignore_v<seq_type>)
446 auto skip_sequence_bytes = [&]()
448 detail::consume(seq_stream);
453 skip_sequence_bytes();
457 using alph_t = std::ranges::range_value_t<
decltype(
seq)>;
458 constexpr auto from_dna16 = detail::convert_through_char_representation<dna16sam, alph_t>;
460 for (
auto [d1, d2] : seq_stream)
478 auto qual_view = stream_view | detail::take_exactly_or_throw(core.l_seq)
482 return static_cast<char>(chr + 33);
484 if constexpr (!detail::decays_to_ignore_v<qual_type>)
485 read_forward_range_field(qual_view,
qual);
487 detail::consume(qual_view);
491 int32_t remaining_bytes = core.block_size - (
sizeof(alignment_record_core) - 4 )
492 - core.l_read_name - core.n_cigar_op * 4 - (core.l_seq + 1) / 2 - core.l_seq;
493 assert(remaining_bytes >= 0);
494 auto tags_view = stream_view | detail::take_exactly_or_throw(remaining_bytes);
496 while (tags_view.size() > 0)
498 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
499 read_sam_dict_field(tags_view, tag_dict);
501 detail::consume(tags_view);
506 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
508 int32_t
const sc_front = soft_clipping_at_front(cigar_vector);
513 if (core.l_seq != 0 && sc_front == core.l_seq)
515 if constexpr (detail::decays_to_ignore_v<tag_dict_type> | detail::decays_to_ignore_v<seq_type>)
518 detail::to_string(
"The cigar string '",
522 "N' suggests that the cigar string exceeded 65535 elements and was therefore ",
523 "stored in the optional field CG. You need to read in the field::tags and "
524 "field::seq in order to access this information.")};
528 auto it = tag_dict.find(
"CG"_tag);
530 if (it == tag_dict.end())
532 "The cigar string '",
536 "N' suggests that the cigar string exceeded 65535 elements and was therefore ",
537 "stored in the optional field CG but this tag is not present in the given ",
540 auto cigar_view = std::views::all(std::get<std::string>(it->second));
541 int32_t seq_length{};
542 std::tie(cigar_vector, ref_length, seq_length) = detail::parse_cigar(cigar_view);
550template <
typename stream_type,
551 typename header_type,
554 typename ref_seq_type,
555 typename ref_id_type,
559 typename tag_dict_type>
562 [[maybe_unused]] header_type && header,
563 [[maybe_unused]] seq_type && seq,
564 [[maybe_unused]] qual_type && qual,
565 [[maybe_unused]] id_type &&
id,
566 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
567 [[maybe_unused]] ref_id_type && ref_id,
569 [[maybe_unused]] cigar_type && cigar_vector,
570 [[maybe_unused]]
sam_flag const flag,
571 [[maybe_unused]] uint8_t
const mapq,
572 [[maybe_unused]] mate_type && mate,
573 [[maybe_unused]] tag_dict_type && tag_dict,
574 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
575 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(bit_score))
581 "The seq object must be a std::ranges::forward_range over "
582 "letters that model seqan3::alphabet.");
585 "The id object must be a std::ranges::forward_range over "
586 "letters that model seqan3::alphabet.");
589 "The ref_seq object must be a std::ranges::forward_range "
590 "over letters that model seqan3::alphabet.");
592 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
594 static_assert((std::ranges::forward_range<ref_id_type> || std::integral<std::remove_reference_t<ref_id_type>>
595 || detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>),
596 "The ref_id object must be a std::ranges::forward_range "
597 "over letters that model seqan3::alphabet or an integral or a std::optional<integral>.");
601 "The qual object must be a std::ranges::forward_range "
602 "over letters that model seqan3::alphabet.");
605 "The mate object must be a std::tuple of size 3 with "
606 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
607 "2) a std::integral or std::optional<std::integral>, and "
608 "3) a std::integral.");
611 ((std::ranges::forward_range<decltype(std::get<0>(
mate))>
613 || detail::is_type_specialisation_of_v<
615 std::optional>)&&(std::integral<std::remove_cvref_t<decltype(std::get<1>(
mate))>>
616 || detail::is_type_specialisation_of_v<
618 std::optional>)&&std::integral<std::remove_cvref_t<decltype(std::get<2>(
mate))>>),
619 "The mate object must be a std::tuple of size 3 with "
620 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
621 "2) a std::integral or std::optional<std::integral>, and "
622 "3) a std::integral.");
625 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
627 if constexpr (detail::decays_to_ignore_v<header_type>)
629 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
630 "You can either construct the output file with reference names and reference length "
631 "information and the header will be created for you, or you can access the `header` member "
643 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
648 if (!header_was_written)
650 write_header(stream, options, header);
651 header_was_written =
true;
657 int32_t ref_length{};
660 if (!std::ranges::empty(cigar_vector))
662 int32_t dummy_seq_length{};
663 for (
auto & [
count, operation] : cigar_vector)
664 detail::update_alignment_lengths(ref_length, dummy_seq_length, operation.to_char(),
count);
667 if (cigar_vector.size() >= (1 << 16))
669 tag_dict[
"CG"_tag] = detail::get_cigar_string(cigar_vector);
670 cigar_vector.resize(2);
671 cigar_vector[0] =
cigar{
static_cast<uint32_t
>(std::ranges::distance(
seq)),
'S'_cigar_operation};
672 cigar_vector[1] =
cigar{
static_cast<uint32_t
>(ref_length),
'N'_cigar_operation};
675 std::string tag_dict_binary_str = get_tag_dict_str(tag_dict);
682 uint8_t read_name_size = std::min<uint8_t>(std::ranges::distance(
id), 254) + 1;
683 read_name_size +=
static_cast<uint8_t
>(read_name_size == 1);
685 alignment_record_core core{ 0,
691 static_cast<uint16_t
>(cigar_vector.size()),
693 static_cast<int32_t
>(std::ranges::distance(
seq)),
695 get<1>(
mate).value_or(-1),
698 auto check_and_assign_id_to = [&header]([[maybe_unused]]
auto & id_source, [[maybe_unused]]
auto & id_target)
702 if constexpr (!detail::decays_to_ignore_v<id_t>)
704 if constexpr (std::integral<id_t>)
706 id_target = id_source;
708 else if constexpr (detail::is_type_specialisation_of_v<id_t, std::optional>)
710 id_target = id_source.value_or(-1);
714 if (!std::ranges::empty(id_source))
718 if constexpr (std::ranges::contiguous_range<
decltype(id_source)>
719 && std::ranges::sized_range<
decltype(id_source)>
720 && std::ranges::borrowed_range<
decltype(id_source)>)
731 "The ref_id type is not convertible to the reference id information stored in the "
732 "reference dictionary of the header object.");
734 id_it = header.
ref_dict.find(id_source);
739 throw format_error{detail::to_string(
"Unknown reference name '",
742 "not be found in BAM header ref_dict: ",
747 id_target = id_it->second;
754 check_and_assign_id_to(
ref_id, core.refID);
757 check_and_assign_id_to(get<0>(
mate), core.next_refID);
760 core.block_size =
sizeof(core) - 4 + core.l_read_name + core.n_cigar_op * 4
762 (core.l_seq + 1) / 2 +
764 tag_dict_binary_str.
size();
768 if (std::ranges::empty(
id))
775 for (
auto [cigar_count, op] : cigar_vector)
777 cigar_count = cigar_count << 4;
778 cigar_count |=
static_cast<int32_t
>(char_to_sam_rank[op.to_char()]);
783 using alph_t = std::ranges::range_value_t<seq_type>;
784 constexpr auto to_dna16 = detail::convert_through_char_representation<alph_t, dna16sam>;
787 for (int32_t sidx = 0; sidx < ((core.l_seq & 1) ? core.l_seq - 1 : core.l_seq); ++sidx, ++sit)
792 stream_it =
static_cast<char>(compressed_chr);
796 stream_it =
static_cast<char>(
to_rank(to_dna16[
to_rank(*sit)]) << 4);
799 if (std::ranges::empty(
qual))
806 if (std::ranges::distance(
qual) != core.l_seq)
807 throw format_error{detail::to_string(
"Expected quality of same length as sequence with size ",
809 ". Got quality with size ",
810 std::ranges::distance(
qual),
817 return static_cast<char>(
to_rank(chr));
823 stream << tag_dict_binary_str;
828template <
typename stream_t,
typename header_type>
829inline void format_bam::write_header(stream_t & stream,
sam_file_output_options const & options, header_type & header)
831 if constexpr (detail::decays_to_ignore_v<header_type>)
833 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
834 "You can either construct the output file with reference names and reference length "
835 "information and the header will be created for you, or you can access the `header` member "
840 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
846 detail::format_sam_base::write_header(os, options, header);
847#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI || (SEQAN3_COMPILER_IS_GCC && (__GNUC__ == 10))
848 int32_t
const l_text{
static_cast<int32_t
>(os.
str().size())};
850 int32_t
const l_text{
static_cast<int32_t
>(os.view().size())};
854#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI || (SEQAN3_COMPILER_IS_GCC && (__GNUC__ == 10))
855 auto header_view = os.
str();
857 auto header_view = os.view();
861 assert(header.ref_ids().size() < (1ull << 32));
862 int32_t
const n_ref{
static_cast<int32_t
>(header.ref_ids().size())};
865 for (int32_t ridx = 0; ridx < n_ref; ++ridx)
867 assert(header.ref_ids()[ridx].size() + 1 < (1ull << 32));
868 int32_t
const l_name{
static_cast<int32_t
>(header.ref_ids()[ridx].size()) + 1};
874 std::ranges::copy_n(
reinterpret_cast<char *
>(&get<0>(header.ref_id_info[ridx])), 4, stream_it);
880template <
typename stream_view_type,
typename value_type>
882 stream_view_type && stream_view,
883 value_type
const & SEQAN3_DOXYGEN_ONLY(value))
886 read_integral_byte_field(stream_view,
count);
893 if constexpr (std::integral<value_type>)
895 read_integral_byte_field(stream_view, tmp);
897 else if constexpr (std::same_as<value_type, float>)
899 read_float_byte_field(stream_view, tmp);
903 constexpr bool always_false = std::is_same_v<value_type, void>;
904 static_assert(always_false,
"format_bam::read_sam_dict_vector: unsupported value_type");
909 variant = std::move(tmp_vector);
929template <
typename stream_view_type>
930inline void format_bam::read_sam_dict_field(stream_view_type && stream_view, sam_tag_dictionary & target)
939 uint16_t tag =
static_cast<uint16_t
>(*it) << 8;
942 tag +=
static_cast<uint16_t
>(*it);
960 read_integral_byte_field(stream_view, tmp);
961 target[tag] =
static_cast<int32_t
>(tmp);
967 read_integral_byte_field(stream_view, tmp);
968 target[tag] =
static_cast<int32_t
>(tmp);
974 read_integral_byte_field(stream_view, tmp);
975 target[tag] =
static_cast<int32_t
>(tmp);
981 read_integral_byte_field(stream_view, tmp);
982 target[tag] =
static_cast<int32_t
>(tmp);
988 read_integral_byte_field(stream_view, tmp);
989 target[tag] = std::move(tmp);
995 read_integral_byte_field(stream_view, tmp);
996 target[tag] =
static_cast<int32_t
>(tmp);
1002 read_float_byte_field(stream_view, tmp);
1008 string_buffer.
clear();
1009 while (!is_char<'\0'>(*it))
1015 target[tag] = string_buffer;
1022 while (!is_char<'\0'>(*it))
1024 string_buffer.
clear();
1029 throw format_error{
"Hexadecimal tag has an uneven number of digits!"};
1033 read_byte_field(string_buffer, value);
1037 target[tag] = byte_array;
1042 char array_value_type_id = *it;
1045 switch (array_value_type_id)
1048 read_sam_dict_vector(target[tag], stream_view, int8_t{});
1051 read_sam_dict_vector(target[tag], stream_view, uint8_t{});
1054 read_sam_dict_vector(target[tag], stream_view, int16_t{});
1057 read_sam_dict_vector(target[tag], stream_view, uint16_t{});
1060 read_sam_dict_vector(target[tag], stream_view, int32_t{});
1063 read_sam_dict_vector(target[tag], stream_view, uint32_t{});
1066 read_sam_dict_vector(target[tag], stream_view,
float{});
1069 throw format_error{detail::to_string(
"The first character in the numerical id of a SAM tag ",
1070 "must be one of [cCsSiIf] but '",
1071 array_value_type_id,
1077 throw format_error{detail::to_string(
"The second character in the numerical id of a "
1078 "SAM tag must be one of [A,i,Z,H,B,f] but '",
1098template <
typename cigar_input_type>
1099inline auto format_bam::parse_binary_cigar(cigar_input_type && cigar_input, uint16_t n_cigar_op)
const
1102 char operation{
'\0'};
1104 int32_t ref_length{}, seq_length{};
1105 uint32_t operation_and_count{};
1106 constexpr char const * cigar_mapping =
"MIDNSHP=X*******";
1107 constexpr uint32_t cigar_mask = 0x0f;
1109 if (n_cigar_op == 0)
1110 return std::tuple{operations, ref_length, seq_length};
1114 while (n_cigar_op > 0)
1117 sizeof(operation_and_count),
1118 reinterpret_cast<char *
>(&operation_and_count));
1119 operation = cigar_mapping[operation_and_count & cigar_mask];
1120 count = operation_and_count >> 4;
1122 detail::update_alignment_lengths(ref_length, seq_length, operation,
count);
1127 return std::tuple{operations, ref_length, seq_length};
1133inline std::string format_bam::get_tag_dict_str(sam_tag_dictionary
const & tag_dict)
1137 auto stream_variant_fn = [&result](
auto && arg)
1142 if constexpr (std::same_as<T, int32_t>)
1145 size_t const absolute_arg = std::abs(arg);
1147 bool const negative = arg < 0;
1148 n = n * n + 2 * negative;
1154 result[result.size() - 1] =
'C';
1155 result.append(
reinterpret_cast<char const *
>(&arg), 1);
1160 result[result.size() - 1] =
'S';
1161 result.append(
reinterpret_cast<char const *
>(&arg), 2);
1166 result[result.size() - 1] =
'c';
1167 int8_t tmp =
static_cast<int8_t
>(arg);
1168 result.append(
reinterpret_cast<char const *
>(&tmp), 1);
1173 result[result.size() - 1] =
's';
1174 int16_t tmp =
static_cast<int16_t
>(arg);
1175 result.append(
reinterpret_cast<char const *
>(&tmp), 2);
1180 result.append(
reinterpret_cast<char const *
>(&arg), 4);
1185 else if constexpr (std::same_as<T, std::string>)
1187 result.append(
reinterpret_cast<char const *
>(arg.data()), arg.size() + 1 );
1189 else if constexpr (!std::ranges::range<T>)
1191 result.append(
reinterpret_cast<char const *
>(&arg),
sizeof(arg));
1195 int32_t sz{
static_cast<int32_t
>(arg.size())};
1196 result.append(
reinterpret_cast<char *
>(&sz), 4);
1197 result.append(
reinterpret_cast<char const *
>(arg.data()),
1198 arg.size() *
sizeof(std::ranges::range_value_t<T>));
1202 for (
auto & [tag, variant] : tag_dict)
1204 result.push_back(
static_cast<char>(tag / 256));
1205 result.push_back(
static_cast<char>(tag % 256));
1207 result.push_back(detail::sam_tag_type_char[variant.
index()]);
1209 if (!is_char<'\0'>(detail::sam_tag_type_char_extra[variant.
index()]))
1210 result.push_back(detail::sam_tag_type_char_extra[variant.
index()]);
constexpr derived_type & assign_char(char_type const chr) noexcept
Assign from a character, implicitly converts invalid characters.
Definition: alphabet_base.hpp:163
constexpr derived_type & assign_rank(rank_type const c) noexcept
Assign from a numeric value.
Definition: alphabet_base.hpp:187
The seqan3::cigar semialphabet pairs a counter with a seqan3::cigar::operation letter.
Definition: alphabet/cigar/cigar.hpp:60
exposition_only::cigar_operation operation
The (extended) cigar operation alphabet of M,D,I,H,N,P,S,X,=.
Definition: alphabet/cigar/cigar.hpp:96
A 16 letter DNA alphabet, containing all IUPAC symbols minus the gap and plus an equality sign ('=')....
Definition: dna16sam.hpp:48
The SAM tag dictionary class that stores all optional SAM fields.
Definition: sam_tag_dictionary.hpp:343
Provides seqan3::dna16sam.
T emplace_back(T... args)
Provides seqan3::detail::fast_ostreambuf_iterator.
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: alphabet/concept.hpp:155
sam_flag
An enum flag that describes the properties of an aligned read (given as a SAM record).
Definition: sam_flag.hpp:76
@ 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.
@ 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.
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 ptrdiff_t count
Count the occurrences of a type in a pack.
Definition: type_pack/traits.hpp:164
constexpr size_t size
The size of a type pack.
Definition: type_pack/traits.hpp:146
constexpr auto repeat_n
A view factory that repeats a given value n times.
Definition: repeat_n.hpp:91
The generic alphabet concept that covers most data types used in ranges.
Checks whether from can be implicityly converted to to.
Whether a type behaves like a tuple.
Auxiliary functions for the SAM IO.
Provides seqan3::detail::istreambuf.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
Provides seqan3::debug_stream and related types.
Provides helper data structures for the seqan3::sam_file_output.
Provides the seqan3::sam_tag_dictionary class and auxiliaries.
Provides seqan3::views::slice.
The options type defines various option members that influence the behavior of all or some formats.
Definition: sam_file/output_options.hpp:26
Provides seqan3::views::take_exactly and seqan3::views::take_exactly_or_throw.