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,
77 typename ref_seq_type,
79 typename ref_offset_type,
85 typename tag_dict_type,
86 typename e_value_type,
87 typename bit_score_type>
90 ref_seqs_type & ref_seqs,
92 stream_pos_type & position_buffer,
97 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
99 ref_offset_type & ref_offset,
100 cigar_type & cigar_vector,
104 tag_dict_type & tag_dict,
105 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
106 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score));
108 template <
typename stream_type,
109 typename header_type,
112 typename ref_seq_type,
113 typename ref_id_type,
117 typename tag_dict_type>
120 [[maybe_unused]] header_type && header,
121 [[maybe_unused]] seq_type && seq,
122 [[maybe_unused]] qual_type && qual,
123 [[maybe_unused]] id_type &&
id,
124 [[maybe_unused]] int32_t
const offset,
125 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
126 [[maybe_unused]] ref_id_type && ref_id,
128 [[maybe_unused]] cigar_type && cigar_vector,
129 [[maybe_unused]]
sam_flag const flag,
130 [[maybe_unused]] uint8_t
const mapq,
131 [[maybe_unused]] mate_type && mate,
132 [[maybe_unused]] tag_dict_type && tag_dict,
133 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
134 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(bit_score));
137 template <
typename stream_t,
typename header_type>
142 bool header_was_read{
false};
148 struct alignment_record_core
153 uint32_t l_read_name : 8;
156 uint32_t n_cigar_op : 16;
174 ret[
static_cast<index_t
>(
'I')] = 1;
175 ret[
static_cast<index_t
>(
'D')] = 2;
176 ret[
static_cast<index_t
>(
'N')] = 3;
177 ret[
static_cast<index_t
>(
'S')] = 4;
178 ret[
static_cast<index_t
>(
'H')] = 5;
179 ret[
static_cast<index_t
>(
'P')] = 6;
180 ret[
static_cast<index_t
>(
'=')] = 7;
181 ret[
static_cast<index_t
>(
'X')] = 8;
189 static uint16_t reg2bin(int32_t beg, int32_t end)
noexcept
192 if (beg >> 14 == end >> 14)
193 return ((1 << 15) - 1) / 7 + (beg >> 14);
194 if (beg >> 17 == end >> 17)
195 return ((1 << 12) - 1) / 7 + (beg >> 17);
196 if (beg >> 20 == end >> 20)
197 return ((1 << 9) - 1) / 7 + (beg >> 20);
198 if (beg >> 23 == end >> 23)
199 return ((1 << 6) - 1) / 7 + (beg >> 23);
200 if (beg >> 26 == end >> 26)
201 return ((1 << 3) - 1) / 7 + (beg >> 26);
211 template <
typename stream_view_type, std::
integral number_type>
212 void read_integral_byte_field(stream_view_type && stream_view, number_type & target)
222 template <
typename stream_view_type>
223 void read_float_byte_field(stream_view_type && stream_view,
float & target)
228 template <
typename stream_view_type,
typename value_type>
230 stream_view_type && stream_view,
231 value_type
const & SEQAN3_DOXYGEN_ONLY(value));
233 template <
typename stream_view_type>
234 void read_sam_dict_field(stream_view_type && stream_view, sam_tag_dictionary & target);
236 template <
typename cigar_input_type>
237 auto parse_binary_cigar(cigar_input_type && cigar_input, uint16_t n_cigar_op)
const;
239 static std::string get_tag_dict_str(sam_tag_dictionary
const & tag_dict);
243template <
typename stream_type,
244 typename seq_legal_alph_type,
245 typename ref_seqs_type,
246 typename ref_ids_type,
247 typename stream_pos_type,
250 typename offset_type,
251 typename ref_seq_type,
252 typename ref_id_type,
253 typename ref_offset_type,
259 typename tag_dict_type,
260 typename e_value_type,
261 typename bit_score_type>
265 ref_seqs_type & ref_seqs,
267 stream_pos_type & position_buffer,
271 offset_type & offset,
272 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
273 ref_id_type & ref_id,
274 ref_offset_type & ref_offset,
275 cigar_type & cigar_vector,
279 tag_dict_type & tag_dict,
280 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
281 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score))
283 static_assert(detail::decays_to_ignore_v<ref_offset_type>
284 || detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
285 "The ref_offset must be a specialisation of std::optional.");
287 static_assert(detail::decays_to_ignore_v<mapq_type> || std::same_as<mapq_type, uint8_t>,
288 "The type of field::mapq must be uint8_t.");
290 static_assert(detail::decays_to_ignore_v<flag_type> || std::same_as<flag_type, sam_flag>,
291 "The type of field::flag must be seqan3::sam_flag.");
293 auto stream_view = seqan3::detail::istreambuf(stream);
295 [[maybe_unused]] int32_t offset_tmp{};
296 [[maybe_unused]] int32_t ref_length{};
300 if (!header_was_read)
311 read_integral_byte_field(stream_view, l_text);
314 read_header(stream_view | detail::take_exactly_or_throw(l_text), header, ref_seqs);
316 read_integral_byte_field(stream_view, n_ref);
318 for (int32_t ref_idx = 0; ref_idx < n_ref; ++ref_idx)
320 read_integral_byte_field(stream_view, l_name);
322 string_buffer.
resize(l_name - 1);
325 string_buffer.
data());
328 read_integral_byte_field(stream_view, l_ref);
330 if constexpr (detail::decays_to_ignore_v<ref_seqs_type>)
335 auto & reference_ids = header.
ref_ids();
339 reference_ids.push_back(string_buffer);
341 header.
ref_dict.emplace(reference_ids.back(), reference_ids.size() - 1);
346 auto id_it = header.
ref_dict.find(string_buffer);
351 throw format_error{detail::to_string(
"Unknown reference name '" + string_buffer
352 +
"' found in BAM file header (header.ref_ids():",
356 else if (id_it->second != ref_idx)
362 " does not correspond to the position ",
364 " in the header (header.ref_ids():",
368 else if (std::get<0>(header.
ref_id_info[id_it->second]) != l_ref)
370 throw format_error{
"Provided reference has unequal length as specified in the header."};
374 header_was_read =
true;
382 position_buffer = stream.tellg();
383 alignment_record_core core;
384 std::ranges::copy(stream_view | detail::take_exactly_or_throw(
sizeof(core)),
reinterpret_cast<char *
>(&core));
386 if (core.refID >=
static_cast<int32_t
>(header.
ref_ids().size()) || core.refID < -1)
388 throw format_error{detail::to_string(
"Reference id index '",
390 "' is not in range of ",
391 "header.ref_ids(), which has size ",
395 else if (core.refID > -1)
406 if constexpr (!detail::decays_to_ignore_v<mate_type>)
408 if (core.next_refID > -1)
409 get<0>(
mate) = core.next_refID;
411 if (core.next_pos > -1)
412 get<1>(
mate) = core.next_pos;
414 get<2>(
mate) = core.tlen;
419 auto id_view = stream_view | detail::take_exactly_or_throw(core.l_read_name - 1);
420 if constexpr (!detail::decays_to_ignore_v<id_type>)
421 read_forward_range_field(id_view,
id);
423 detail::consume(id_view);
428 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
430 int32_t seq_length{};
431 std::tie(cigar_vector, ref_length, seq_length) = parse_binary_cigar(stream_view, core.n_cigar_op);
432 int32_t soft_clipping_end{};
433 transfer_soft_clipping_to(cigar_vector, offset_tmp, soft_clipping_end);
437 detail::consume(stream_view | detail::take_exactly_or_throw(core.n_cigar_op * 4));
446 auto seq_stream = stream_view | detail::take_exactly_or_throw(core.l_seq / 2)
454 if constexpr (detail::decays_to_ignore_v<seq_type>)
456 auto skip_sequence_bytes = [&]()
458 detail::consume(seq_stream);
463 skip_sequence_bytes();
467 using alph_t = std::ranges::range_value_t<
decltype(
seq)>;
468 constexpr auto from_dna16 = detail::convert_through_char_representation<dna16sam, alph_t>;
470 for (
auto [d1, d2] : seq_stream)
488 auto qual_view = stream_view | detail::take_exactly_or_throw(core.l_seq)
492 return static_cast<char>(chr + 33);
494 if constexpr (!detail::decays_to_ignore_v<qual_type>)
495 read_forward_range_field(qual_view,
qual);
497 detail::consume(qual_view);
501 int32_t remaining_bytes = core.block_size - (
sizeof(alignment_record_core) - 4 )
502 - core.l_read_name - core.n_cigar_op * 4 - (core.l_seq + 1) / 2 - core.l_seq;
503 assert(remaining_bytes >= 0);
504 auto tags_view = stream_view | detail::take_exactly_or_throw(remaining_bytes);
506 while (tags_view.size() > 0)
508 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
509 read_sam_dict_field(tags_view, tag_dict);
511 detail::consume(tags_view);
516 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
521 if (core.l_seq != 0 && offset_tmp == core.l_seq)
523 if constexpr (detail::decays_to_ignore_v<tag_dict_type> | detail::decays_to_ignore_v<seq_type>)
526 detail::to_string(
"The cigar string '",
530 "N' suggests that the cigar string exceeded 65535 elements and was therefore ",
531 "stored in the optional field CG. You need to read in the field::tags and "
532 "field::seq in order to access this information.")};
536 auto it = tag_dict.find(
"CG"_tag);
538 if (it == tag_dict.end())
540 "The cigar string '",
544 "N' suggests that the cigar string exceeded 65535 elements and was therefore ",
545 "stored in the optional field CG but this tag is not present in the given ",
548 auto cigar_view = std::views::all(std::get<std::string>(it->second));
549 int32_t seq_length{};
550 std::tie(cigar_vector, ref_length, seq_length) = detail::parse_cigar(cigar_view);
552 int32_t soft_clipping_end{};
553 transfer_soft_clipping_to(cigar_vector, offset_tmp, soft_clipping_end);
561template <
typename stream_type,
562 typename header_type,
565 typename ref_seq_type,
566 typename ref_id_type,
570 typename tag_dict_type>
573 [[maybe_unused]] header_type && header,
574 [[maybe_unused]] seq_type && seq,
575 [[maybe_unused]] qual_type && qual,
576 [[maybe_unused]] id_type &&
id,
577 [[maybe_unused]] int32_t
const offset,
578 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
579 [[maybe_unused]] ref_id_type && ref_id,
581 [[maybe_unused]] cigar_type && cigar_vector,
582 [[maybe_unused]]
sam_flag const flag,
583 [[maybe_unused]] uint8_t
const mapq,
584 [[maybe_unused]] mate_type && mate,
585 [[maybe_unused]] tag_dict_type && tag_dict,
586 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
587 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(bit_score))
593 "The seq object must be a std::ranges::forward_range over "
594 "letters that model seqan3::alphabet.");
597 "The id object must be a std::ranges::forward_range over "
598 "letters that model seqan3::alphabet.");
601 "The ref_seq object must be a std::ranges::forward_range "
602 "over letters that model seqan3::alphabet.");
604 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
606 static_assert((std::ranges::forward_range<ref_id_type> || std::integral<std::remove_reference_t<ref_id_type>>
607 || detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>),
608 "The ref_id object must be a std::ranges::forward_range "
609 "over letters that model seqan3::alphabet or an integral or a std::optional<integral>.");
613 "The qual object must be a std::ranges::forward_range "
614 "over letters that model seqan3::alphabet.");
617 "The mate object must be a std::tuple of size 3 with "
618 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
619 "2) a std::integral or std::optional<std::integral>, and "
620 "3) a std::integral.");
623 ((std::ranges::forward_range<decltype(std::get<0>(
mate))>
625 || detail::is_type_specialisation_of_v<
627 std::optional>)&&(std::integral<std::remove_cvref_t<decltype(std::get<1>(
mate))>>
628 || detail::is_type_specialisation_of_v<
630 std::optional>)&&std::integral<std::remove_cvref_t<decltype(std::get<2>(
mate))>>),
631 "The mate object must be a std::tuple of size 3 with "
632 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
633 "2) a std::integral or std::optional<std::integral>, and "
634 "3) a std::integral.");
637 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
639 if constexpr (detail::decays_to_ignore_v<header_type>)
641 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
642 "You can either construct the output file with reference names and reference length "
643 "information and the header will be created for you, or you can access the `header` member "
655 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
660 if (!header_was_written)
662 write_header(stream, options, header);
663 header_was_written =
true;
669 int32_t ref_length{};
672 if (!std::ranges::empty(cigar_vector))
674 int32_t dummy_seq_length{};
675 for (
auto & [
count, operation] : cigar_vector)
676 detail::update_alignment_lengths(ref_length, dummy_seq_length, operation.to_char(),
count);
679 if (cigar_vector.size() >= (1 << 16))
681 tag_dict[
"CG"_tag] = detail::get_cigar_string(cigar_vector);
682 cigar_vector.resize(2);
683 cigar_vector[0] =
cigar{
static_cast<uint32_t
>(std::ranges::distance(
seq)),
'S'_cigar_operation};
684 cigar_vector[1] =
cigar{
static_cast<uint32_t
>(ref_length),
'N'_cigar_operation};
687 std::string tag_dict_binary_str = get_tag_dict_str(tag_dict);
694 uint8_t read_name_size = std::min<uint8_t>(std::ranges::distance(
id), 254) + 1;
695 read_name_size +=
static_cast<uint8_t
>(read_name_size == 1);
697 alignment_record_core core{ 0,
703 static_cast<uint16_t
>(cigar_vector.size()),
705 static_cast<int32_t
>(std::ranges::distance(
seq)),
707 get<1>(
mate).value_or(-1),
710 auto check_and_assign_id_to = [&header]([[maybe_unused]]
auto & id_source, [[maybe_unused]]
auto & id_target)
714 if constexpr (!detail::decays_to_ignore_v<id_t>)
716 if constexpr (std::integral<id_t>)
718 id_target = id_source;
720 else if constexpr (detail::is_type_specialisation_of_v<id_t, std::optional>)
722 id_target = id_source.value_or(-1);
726 if (!std::ranges::empty(id_source))
730 if constexpr (std::ranges::contiguous_range<
decltype(id_source)>
731 && std::ranges::sized_range<
decltype(id_source)>
732 && std::ranges::borrowed_range<
decltype(id_source)>)
743 "The ref_id type is not convertible to the reference id information stored in the "
744 "reference dictionary of the header object.");
746 id_it = header.
ref_dict.find(id_source);
751 throw format_error{detail::to_string(
"Unknown reference name '",
754 "not be found in BAM header ref_dict: ",
759 id_target = id_it->second;
766 check_and_assign_id_to(
ref_id, core.refID);
769 check_and_assign_id_to(get<0>(
mate), core.next_refID);
772 core.block_size =
sizeof(core) - 4 + core.l_read_name + core.n_cigar_op * 4
774 (core.l_seq + 1) / 2 +
776 tag_dict_binary_str.
size();
780 if (std::ranges::empty(
id))
787 for (
auto [cigar_count, op] : cigar_vector)
789 cigar_count = cigar_count << 4;
790 cigar_count |=
static_cast<int32_t
>(char_to_sam_rank[op.to_char()]);
795 using alph_t = std::ranges::range_value_t<seq_type>;
796 constexpr auto to_dna16 = detail::convert_through_char_representation<alph_t, dna16sam>;
799 for (int32_t sidx = 0; sidx < ((core.l_seq & 1) ? core.l_seq - 1 : core.l_seq); ++sidx, ++sit)
804 stream_it =
static_cast<char>(compressed_chr);
808 stream_it =
static_cast<char>(
to_rank(to_dna16[
to_rank(*sit)]) << 4);
811 if (std::ranges::empty(
qual))
818 if (std::ranges::distance(
qual) != core.l_seq)
819 throw format_error{detail::to_string(
"Expected quality of same length as sequence with size ",
821 ". Got quality with size ",
822 std::ranges::distance(
qual),
829 return static_cast<char>(
to_rank(chr));
835 stream << tag_dict_binary_str;
840template <
typename stream_t,
typename header_type>
841inline void format_bam::write_header(stream_t & stream,
sam_file_output_options const & options, header_type & header)
843 if constexpr (detail::decays_to_ignore_v<header_type>)
845 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
846 "You can either construct the output file with reference names and reference length "
847 "information and the header will be created for you, or you can access the `header` member "
852 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
858 detail::format_sam_base::write_header(os, options, header);
859#if SEQAN3_COMPILER_IS_GCC && (__GNUC__ == 10)
860 int32_t
const l_text{
static_cast<int32_t
>(os.
str().size())};
862 int32_t
const l_text{
static_cast<int32_t
>(os.view().size())};
866#if SEQAN3_COMPILER_IS_GCC && (__GNUC__ == 10)
867 auto header_view = os.
str();
869 auto header_view = os.view();
873 assert(header.ref_ids().size() < (1ull << 32));
874 int32_t
const n_ref{
static_cast<int32_t
>(header.ref_ids().size())};
877 for (int32_t ridx = 0; ridx < n_ref; ++ridx)
879 assert(header.ref_ids()[ridx].size() + 1 < (1ull << 32));
880 int32_t
const l_name{
static_cast<int32_t
>(header.ref_ids()[ridx].size()) + 1};
886 std::ranges::copy_n(
reinterpret_cast<char *
>(&get<0>(header.ref_id_info[ridx])), 4, stream_it);
892template <
typename stream_view_type,
typename value_type>
894 stream_view_type && stream_view,
895 value_type
const & SEQAN3_DOXYGEN_ONLY(value))
898 read_integral_byte_field(stream_view,
count);
905 if constexpr (std::integral<value_type>)
907 read_integral_byte_field(stream_view, tmp);
909 else if constexpr (std::same_as<value_type, float>)
911 read_float_byte_field(stream_view, tmp);
915 constexpr bool always_false = std::is_same_v<value_type, void>;
916 static_assert(always_false,
"format_bam::read_sam_dict_vector: unsupported value_type");
921 variant = std::move(tmp_vector);
941template <
typename stream_view_type>
942inline void format_bam::read_sam_dict_field(stream_view_type && stream_view, sam_tag_dictionary & target)
951 uint16_t tag =
static_cast<uint16_t
>(*it) << 8;
954 tag +=
static_cast<uint16_t
>(*it);
972 read_integral_byte_field(stream_view, tmp);
973 target[tag] =
static_cast<int32_t
>(tmp);
979 read_integral_byte_field(stream_view, tmp);
980 target[tag] =
static_cast<int32_t
>(tmp);
986 read_integral_byte_field(stream_view, tmp);
987 target[tag] =
static_cast<int32_t
>(tmp);
993 read_integral_byte_field(stream_view, tmp);
994 target[tag] =
static_cast<int32_t
>(tmp);
1000 read_integral_byte_field(stream_view, tmp);
1001 target[tag] = std::move(tmp);
1007 read_integral_byte_field(stream_view, tmp);
1008 target[tag] =
static_cast<int32_t
>(tmp);
1014 read_float_byte_field(stream_view, tmp);
1020 string_buffer.
clear();
1021 while (!is_char<'\0'>(*it))
1027 target[tag] = string_buffer;
1034 while (!is_char<'\0'>(*it))
1036 string_buffer.
clear();
1041 throw format_error{
"Hexadecimal tag has an uneven number of digits!"};
1045 read_byte_field(string_buffer, value);
1049 target[tag] = byte_array;
1054 char array_value_type_id = *it;
1057 switch (array_value_type_id)
1060 read_sam_dict_vector(target[tag], stream_view, int8_t{});
1063 read_sam_dict_vector(target[tag], stream_view, uint8_t{});
1066 read_sam_dict_vector(target[tag], stream_view, int16_t{});
1069 read_sam_dict_vector(target[tag], stream_view, uint16_t{});
1072 read_sam_dict_vector(target[tag], stream_view, int32_t{});
1075 read_sam_dict_vector(target[tag], stream_view, uint32_t{});
1078 read_sam_dict_vector(target[tag], stream_view,
float{});
1081 throw format_error{detail::to_string(
"The first character in the numerical id of a SAM tag ",
1082 "must be one of [cCsSiIf] but '",
1083 array_value_type_id,
1089 throw format_error{detail::to_string(
"The second character in the numerical id of a "
1090 "SAM tag must be one of [A,i,Z,H,B,f] but '",
1110template <
typename cigar_input_type>
1111inline auto format_bam::parse_binary_cigar(cigar_input_type && cigar_input, uint16_t n_cigar_op)
const
1114 char operation{
'\0'};
1116 int32_t ref_length{}, seq_length{};
1117 uint32_t operation_and_count{};
1118 constexpr char const * cigar_mapping =
"MIDNSHP=X*******";
1119 constexpr uint32_t cigar_mask = 0x0f;
1121 if (n_cigar_op == 0)
1122 return std::tuple{operations, ref_length, seq_length};
1126 while (n_cigar_op > 0)
1129 sizeof(operation_and_count),
1130 reinterpret_cast<char *
>(&operation_and_count));
1131 operation = cigar_mapping[operation_and_count & cigar_mask];
1132 count = operation_and_count >> 4;
1134 detail::update_alignment_lengths(ref_length, seq_length, operation,
count);
1139 return std::tuple{operations, ref_length, seq_length};
1145inline std::string format_bam::get_tag_dict_str(sam_tag_dictionary
const & tag_dict)
1149 auto stream_variant_fn = [&result](
auto && arg)
1154 if constexpr (std::same_as<T, int32_t>)
1157 size_t const absolute_arg = std::abs(arg);
1159 bool const negative = arg < 0;
1160 n = n * n + 2 * negative;
1166 result[result.size() - 1] =
'C';
1167 result.append(
reinterpret_cast<char const *
>(&arg), 1);
1172 result[result.size() - 1] =
'S';
1173 result.append(
reinterpret_cast<char const *
>(&arg), 2);
1178 result[result.size() - 1] =
'c';
1179 int8_t tmp =
static_cast<int8_t
>(arg);
1180 result.append(
reinterpret_cast<char const *
>(&tmp), 1);
1185 result[result.size() - 1] =
's';
1186 int16_t tmp =
static_cast<int16_t
>(arg);
1187 result.append(
reinterpret_cast<char const *
>(&tmp), 2);
1192 result.append(
reinterpret_cast<char const *
>(&arg), 4);
1197 else if constexpr (std::same_as<T, std::string>)
1199 result.append(
reinterpret_cast<char const *
>(arg.data()), arg.size() + 1 );
1201 else if constexpr (!std::ranges::range<T>)
1203 result.append(
reinterpret_cast<char const *
>(&arg),
sizeof(arg));
1207 int32_t sz{
static_cast<int32_t
>(arg.size())};
1208 result.append(
reinterpret_cast<char *
>(&sz), 4);
1209 result.append(
reinterpret_cast<char const *
>(arg.data()),
1210 arg.size() *
sizeof(std::ranges::range_value_t<T>));
1214 for (
auto & [tag, variant] : tag_dict)
1216 result.push_back(
static_cast<char>(tag / 256));
1217 result.push_back(
static_cast<char>(tag % 256));
1219 result.push_back(detail::sam_tag_type_char[variant.
index()]);
1221 if (!is_char<'\0'>(detail::sam_tag_type_char_extra[variant.
index()]))
1222 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.
@ 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.
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.