67 template <
typename stream_type,
68 typename seq_legal_alph_type,
69 typename ref_seqs_type,
70 typename ref_ids_type,
71 typename stream_pos_type,
74 typename ref_seq_type,
76 typename ref_offset_type,
82 typename tag_dict_type,
83 typename e_value_type,
84 typename bit_score_type>
87 ref_seqs_type & ref_seqs,
89 stream_pos_type & position_buffer,
93 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
96 cigar_type & cigar_vector,
100 tag_dict_type & tag_dict,
101 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
102 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score));
104 template <
typename stream_type,
105 typename header_type,
108 typename ref_seq_type,
109 typename ref_id_type,
113 typename tag_dict_type>
116 [[maybe_unused]] header_type && header,
117 [[maybe_unused]] seq_type &&
seq,
118 [[maybe_unused]] qual_type &&
qual,
119 [[maybe_unused]] id_type &&
id,
120 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
121 [[maybe_unused]] ref_id_type &&
ref_id,
123 [[maybe_unused]] cigar_type && cigar_vector,
125 [[maybe_unused]] uint8_t
const mapq,
126 [[maybe_unused]] mate_type &&
mate,
127 [[maybe_unused]] tag_dict_type && tag_dict,
128 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
129 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score));
132 template <
typename stream_t,
typename header_type>
137 bool header_was_read{
false};
143 struct alignment_record_core
148 uint32_t l_read_name : 8;
151 uint32_t n_cigar_op : 16;
159 static_assert(
sizeof(alignment_record_core) == 36);
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)
215 template <std::
integral number_type>
216 void read_integral_byte_field(
std::string_view const str, number_type & target)
226 template <
typename stream_view_type>
227 void read_float_byte_field(stream_view_type && stream_view,
float & target)
232 template <
typename value_type>
235 value_type
const & SEQAN3_DOXYGEN_ONLY(value));
237 void read_sam_dict(
std::string_view const tag_str, sam_tag_dictionary & target);
241 static std::string get_tag_dict_str(sam_tag_dictionary
const & tag_dict);
245template <
typename stream_type,
246 typename seq_legal_alph_type,
247 typename ref_seqs_type,
248 typename ref_ids_type,
249 typename stream_pos_type,
252 typename ref_seq_type,
253 typename ref_id_type,
254 typename ref_offset_type,
260 typename tag_dict_type,
261 typename e_value_type,
262 typename bit_score_type>
265 ref_seqs_type & ref_seqs,
267 stream_pos_type & position_buffer,
271 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
274 cigar_type & cigar_vector,
278 tag_dict_type & tag_dict,
279 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
280 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score))
282 static_assert(detail::decays_to_ignore_v<ref_offset_type>
283 || detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
284 "The ref_offset must be a specialisation of std::optional.");
286 static_assert(detail::decays_to_ignore_v<mapq_type> || std::same_as<mapq_type, uint8_t>,
287 "The type of field::mapq must be uint8_t.");
289 static_assert(detail::decays_to_ignore_v<flag_type> || std::same_as<flag_type, sam_flag>,
290 "The type of field::flag must be seqan3::sam_flag.");
292 auto stream_view = seqan3::detail::istreambuf(stream);
296 if (!header_was_read)
307 read_integral_byte_field(stream_view, l_text);
310 read_header(stream_view | detail::take_exactly_or_throw(l_text), header, ref_seqs, options);
312 read_integral_byte_field(stream_view, n_ref);
314 for (int32_t ref_idx = 0; ref_idx < n_ref; ++ref_idx)
316 read_integral_byte_field(stream_view, l_name);
318 string_buffer.
resize(l_name - 1);
321 string_buffer.
data());
324 read_integral_byte_field(stream_view, l_ref);
326 if constexpr (detail::decays_to_ignore_v<ref_seqs_type>)
331 auto & reference_ids = header.
ref_ids();
335 reference_ids.push_back(string_buffer);
337 header.
ref_dict.emplace(reference_ids.back(), reference_ids.size() - 1);
342 auto id_it = header.
ref_dict.find(string_buffer);
347 throw format_error{detail::to_string(
"Unknown reference name '" + string_buffer
348 +
"' found in BAM file header (header.ref_ids():",
352 else if (id_it->second != ref_idx)
358 " does not correspond to the position ",
360 " in the header (header.ref_ids():",
364 else if (std::get<0>(header.
ref_id_info[id_it->second]) != l_ref)
366 throw format_error{
"Provided reference has unequal length as specified in the header."};
370 header_was_read =
true;
378 position_buffer = stream.tellg();
380 auto stream_it = detail::fast_istreambuf_iterator{*stream.rdbuf()};
382 alignment_record_core 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)
401 mapq =
static_cast<uint8_t
>(core.mapq);
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 std::string_view record_str = stream_it.cache_bytes(core.block_size - (
sizeof(alignment_record_core) - 4));
420 size_t considered_bytes{0};
422 if constexpr (!detail::decays_to_ignore_v<id_type>)
423 read_forward_range_field(record_str.
substr(0, core.l_read_name - 1),
id);
425 considered_bytes += core.l_read_name;
429 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
430 cigar_vector = parse_binary_cigar(record_str.
substr(considered_bytes, core.n_cigar_op * 4));
432 considered_bytes += core.n_cigar_op * 4;
436 if constexpr (!detail::decays_to_ignore_v<seq_type>)
438 size_t const number_of_bytes = (core.l_seq + 1) / 2;
445 using alph_t = std::ranges::range_value_t<
decltype(
seq)>;
446 constexpr auto from_dna16 = detail::convert_through_char_representation<dna16sam, alph_t>;
449 for (
size_t i = 0, j = 0; i < number_of_bytes; ++i, j += 2)
456 seq.resize(core.l_seq);
459 considered_bytes += (core.l_seq + 1) / 2;
463 if constexpr (!detail::decays_to_ignore_v<qual_type>)
466 qual.resize(core.l_seq);
468 for (int32_t i = 0; i < core.l_seq; ++i)
469 qual[i] =
assign_char_to(
static_cast<char>(qual_str[i] + 33), std::ranges::range_value_t<qual_type>{});
472 considered_bytes += core.l_seq;
476 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
477 read_sam_dict(record_str.
substr(considered_bytes), tag_dict);
481 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
483 int32_t
const sc_front = soft_clipping_at_front(cigar_vector);
488 if (core.l_seq != 0 && sc_front == core.l_seq)
490 if constexpr (detail::decays_to_ignore_v<tag_dict_type> | detail::decays_to_ignore_v<seq_type>)
493 detail::to_string(
"The cigar string '",
494 detail::get_cigar_string(cigar_vector),
495 "' suggests that the cigar string exceeded 65535 elements and was therefore ",
496 "stored in the optional field CG. You need to read in the field::tags and "
497 "field::seq in order to access this information.")};
501 auto it = tag_dict.find(
"CG"_tag);
503 if (it == tag_dict.end())
505 detail::to_string(
"The cigar string '",
506 detail::get_cigar_string(cigar_vector),
507 "' suggests that the cigar string exceeded 65535 elements and was therefore ",
508 "stored in the optional field CG but this tag is not present in the given ",
511 cigar_vector = detail::parse_cigar(std::get<std::string>(it->second));
519template <
typename stream_type,
520 typename header_type,
523 typename ref_seq_type,
524 typename ref_id_type,
528 typename tag_dict_type>
531 [[maybe_unused]] header_type && header,
532 [[maybe_unused]] seq_type &&
seq,
533 [[maybe_unused]] qual_type &&
qual,
534 [[maybe_unused]] id_type &&
id,
535 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
536 [[maybe_unused]] ref_id_type &&
ref_id,
538 [[maybe_unused]] cigar_type && cigar_vector,
540 [[maybe_unused]] uint8_t
const mapq,
541 [[maybe_unused]] mate_type &&
mate,
542 [[maybe_unused]] tag_dict_type && tag_dict,
543 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
544 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score))
550 "The seq object must be a std::ranges::forward_range over "
551 "letters that model seqan3::alphabet.");
554 "The id object must be a std::ranges::forward_range over "
555 "letters that model seqan3::alphabet.");
558 "The ref_seq object must be a std::ranges::forward_range "
559 "over letters that model seqan3::alphabet.");
561 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
563 static_assert((std::ranges::forward_range<ref_id_type> || std::integral<std::remove_reference_t<ref_id_type>>
564 || detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>),
565 "The ref_id object must be a std::ranges::forward_range "
566 "over letters that model seqan3::alphabet or an integral or a std::optional<integral>.");
570 "The qual object must be a std::ranges::forward_range "
571 "over letters that model seqan3::alphabet.");
574 "The mate object must be a std::tuple of size 3 with "
575 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
576 "2) a std::integral or std::optional<std::integral>, and "
577 "3) a std::integral.");
580 ((std::ranges::forward_range<decltype(std::get<0>(
mate))>
582 || detail::is_type_specialisation_of_v<
584 std::optional>)&&(std::integral<std::remove_cvref_t<decltype(std::get<1>(
mate))>>
585 || detail::is_type_specialisation_of_v<
587 std::optional>)&&std::integral<std::remove_cvref_t<decltype(std::get<2>(
mate))>>),
588 "The mate object must be a std::tuple of size 3 with "
589 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
590 "2) a std::integral or std::optional<std::integral>, and "
591 "3) a std::integral.");
594 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
596 if constexpr (detail::decays_to_ignore_v<header_type>)
598 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
599 "You can either construct the output file with reference names and reference length "
600 "information and the header will be created for you, or you can access the `header` member "
612 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
617 if (!header_was_written)
619 write_header(stream, options, header);
620 header_was_written =
true;
626 int32_t ref_length{};
629 if (!std::ranges::empty(cigar_vector))
631 int32_t dummy_seq_length{};
632 for (
auto & [count, operation] : cigar_vector)
633 detail::update_alignment_lengths(ref_length, dummy_seq_length, operation.to_char(), count);
636 if (cigar_vector.size() >= (1 << 16))
638 tag_dict[
"CG"_tag] = detail::get_cigar_string(cigar_vector);
639 cigar_vector.resize(2);
640 cigar_vector[0] =
cigar{
static_cast<uint32_t
>(std::ranges::distance(
seq)),
'S'_cigar_operation};
641 cigar_vector[1] =
cigar{
static_cast<uint32_t
>(ref_length),
'N'_cigar_operation};
644 std::string tag_dict_binary_str = get_tag_dict_str(tag_dict);
651 uint8_t read_name_size = std::min<uint8_t>(std::ranges::distance(
id), 254) + 1;
652 read_name_size +=
static_cast<uint8_t
>(read_name_size == 1);
654 alignment_record_core core{ 0,
660 static_cast<uint16_t
>(cigar_vector.size()),
662 static_cast<int32_t
>(std::ranges::distance(
seq)),
664 get<1>(
mate).value_or(-1),
667 auto check_and_assign_id_to = [&header]([[maybe_unused]]
auto & id_source, [[maybe_unused]]
auto & id_target)
671 if constexpr (!detail::decays_to_ignore_v<id_t>)
673 if constexpr (std::integral<id_t>)
675 id_target = id_source;
677 else if constexpr (detail::is_type_specialisation_of_v<id_t, std::optional>)
679 id_target = id_source.value_or(-1);
683 if (!std::ranges::empty(id_source))
687 if constexpr (std::ranges::contiguous_range<
decltype(id_source)>
688 && std::ranges::sized_range<
decltype(id_source)>
689 && std::ranges::borrowed_range<
decltype(id_source)>)
692 std::span{std::ranges::data(id_source), std::ranges::size(id_source)});
700 "The ref_id type is not convertible to the reference id information stored in the "
701 "reference dictionary of the header object.");
703 id_it = header.
ref_dict.find(id_source);
708 throw format_error{detail::to_string(
"Unknown reference name '",
711 "not be found in BAM header ref_dict: ",
716 id_target = id_it->second;
723 check_and_assign_id_to(
ref_id, core.refID);
726 check_and_assign_id_to(get<0>(
mate), core.next_refID);
729 core.block_size =
sizeof(core) - 4 + core.l_read_name + core.n_cigar_op * 4
731 (core.l_seq + 1) / 2 +
733 tag_dict_binary_str.
size();
737 if (std::ranges::empty(
id))
744 for (
auto [cigar_count, op] : cigar_vector)
746 cigar_count = cigar_count << 4;
747 cigar_count |=
static_cast<int32_t
>(char_to_sam_rank[op.to_char()]);
752 using alph_t = std::ranges::range_value_t<seq_type>;
753 constexpr auto to_dna16 = detail::convert_through_char_representation<alph_t, dna16sam>;
756 for (int32_t sidx = 0; sidx < ((core.l_seq & 1) ? core.l_seq - 1 : core.l_seq); ++sidx, ++sit)
761 stream_it =
static_cast<char>(compressed_chr);
765 stream_it =
static_cast<char>(
to_rank(to_dna16[
to_rank(*sit)]) << 4);
768 if (std::ranges::empty(
qual))
775 if (std::ranges::distance(
qual) != core.l_seq)
776 throw format_error{detail::to_string(
"Expected quality of same length as sequence with size ",
778 ". Got quality with size ",
779 std::ranges::distance(
qual),
783 | std::views::transform(
786 return static_cast<char>(
to_rank(chr));
792 stream << tag_dict_binary_str;
797template <
typename stream_t,
typename header_type>
798inline void format_bam::write_header(stream_t & stream,
sam_file_output_options const & options, header_type & header)
800 if constexpr (detail::decays_to_ignore_v<header_type>)
802 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
803 "You can either construct the output file with reference names and reference length "
804 "information and the header will be created for you, or you can access the `header` member "
809 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
815 detail::format_sam_base::write_header(os, options, header);
816#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI
817 int32_t
const l_text{
static_cast<int32_t
>(os.
str().size())};
819 int32_t
const l_text{
static_cast<int32_t
>(os.view().size())};
823#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI
824 auto header_view = os.
str();
826 auto header_view = os.view();
830 assert(header.ref_ids().size() < (1ull << 32));
831 int32_t
const n_ref{
static_cast<int32_t
>(header.ref_ids().size())};
834 for (int32_t ridx = 0; ridx < n_ref; ++ridx)
836 assert(header.ref_ids()[ridx].size() + 1 < (1ull << 32));
837 int32_t
const l_name{
static_cast<int32_t
>(header.ref_ids()[ridx].size()) + 1};
843 std::ranges::copy_n(
reinterpret_cast<char *
>(&get<0>(header.ref_id_info[ridx])), 4, stream_it);
866template <
typename value_type>
869 value_type
const & SEQAN3_DOXYGEN_ONLY(value))
871 auto it = str.
begin();
874 int32_t
const vector_size = [&]()
882 int32_t bytes_left{vector_size};
885 tmp_vector.
reserve(vector_size);
889 while (bytes_left > 0)
891 if constexpr (std::integral<value_type>)
893 else if constexpr (std::same_as<value_type, float>)
896 static_assert(std::is_same_v<value_type, void>,
"format_bam::read_sam_dict_vector: unsupported value_type");
903 variant = std::move(tmp_vector);
923inline void format_bam::read_sam_dict(
std::string_view const tag_str, sam_tag_dictionary & target)
931 auto it = tag_str.
begin();
934 auto parse_integer_into_target = [&]<std::integral int_t>(uint16_t
const tag, int_t)
938 target[tag] =
static_cast<int32_t
>(tmp);
943 auto parse_array_into_target = [&]<
arithmetic array_value_t>(uint16_t
const tag, array_value_t)
946 it +=
sizeof(int32_t) +
sizeof(array_value_t) *
count;
950 auto parse_tag = [&]()
952 uint16_t tag =
static_cast<uint16_t
>(*it) << 8;
954 tag |=
static_cast<uint16_t
>(*it);
959 while (it != tag_str.
end())
961 uint16_t
const tag = parse_tag();
963 char const type_id{*it};
977 parse_integer_into_target(tag, int8_t{});
982 parse_integer_into_target(tag, uint8_t{});
987 parse_integer_into_target(tag, int16_t{});
992 parse_integer_into_target(tag, uint16_t{});
997 parse_integer_into_target(tag, int32_t{});
1002 parse_integer_into_target(tag, uint32_t{});
1010 it +=
sizeof(float);
1015 std::string const v{
static_cast<char const *
>(it)};
1017 target[tag] = std::move(v);
1026 uint8_t dummy_byte{};
1028 if (str.
size() % 2 != 0)
1029 throw format_error{
"[CORRUPTED BAM FILE] Hexadecimal tag must have even number of digits."};
1033 for (
auto hex_begin = str.
begin(), hex_end = str.
begin() + 2; hex_begin != str.
end();
1034 hex_begin += 2, hex_end += 2)
1038 if (res.ec == std::errc::invalid_argument)
1039 throw format_error{
std::string(
"[CORRUPTED BAM FILE] The string '")
1040 +
std::string(hex_begin, hex_end) +
"' could not be cast into type uint8_t."};
1042 if (res.ec == std::errc::result_out_of_range)
1044 +
"' into type uint8_t would cause an overflow."};
1049 target[tag] = std::move(tmp_vector);
1051 it += str.
size() + 1;
1057 char array_value_type_id = *it;
1060 switch (array_value_type_id)
1063 parse_array_into_target(tag, int8_t{});
1066 parse_array_into_target(tag, uint8_t{});
1069 parse_array_into_target(tag, int16_t{});
1072 parse_array_into_target(tag, uint16_t{});
1075 parse_array_into_target(tag, int32_t{});
1078 parse_array_into_target(tag, uint32_t{});
1081 parse_array_into_target(tag,
float{});
1084 throw format_error{detail::to_string(
"The first character in the numerical id of a SAM tag ",
1085 "must be one of [cCsSiIf] but '",
1086 array_value_type_id,
1092 throw format_error{detail::to_string(
"The second character in the numerical id of a "
1093 "SAM tag must be one of [A,i,Z,H,B,f] but '",
1109 cigar_operation_mapping{
'M',
'I',
'D',
'N',
'S',
'H',
'P',
'=',
'X',
'*',
'*',
'*',
'*',
'*',
'*',
'*'};
1111 constexpr uint32_t cigar_operation_mask = 0x0f;
1114 char operation{
'\0'};
1116 uint32_t operation_and_count{};
1118 assert(cigar_str.
size() % 4 == 0);
1120 for (
auto it = cigar_str.
begin(); it != cigar_str.
end(); it +=
sizeof(operation_and_count))
1122 std::memcpy(&operation_and_count, it,
sizeof(operation_and_count));
1123 operation = cigar_operation_mapping[operation_and_count & cigar_operation_mask];
1124 count = operation_and_count >> 4;
1129 return cigar_vector;
1135inline std::string format_bam::get_tag_dict_str(sam_tag_dictionary
const & tag_dict)
1139 auto stream_variant_fn = [&result](
auto && arg)
1144 if constexpr (std::same_as<T, int32_t>)
1147 size_t const absolute_arg = std::abs(arg);
1149 bool const negative = arg < 0;
1150 n = n * n + 2 * negative;
1156 result[result.size() - 1] =
'C';
1157 result.append(
reinterpret_cast<char const *
>(&arg), 1);
1162 result[result.size() - 1] =
'S';
1163 result.append(
reinterpret_cast<char const *
>(&arg), 2);
1168 result[result.size() - 1] =
'c';
1169 int8_t tmp =
static_cast<int8_t
>(arg);
1170 result.append(
reinterpret_cast<char const *
>(&tmp), 1);
1175 result[result.size() - 1] =
's';
1176 int16_t tmp =
static_cast<int16_t
>(arg);
1177 result.append(
reinterpret_cast<char const *
>(&tmp), 2);
1182 result.append(
reinterpret_cast<char const *
>(&arg), 4);
1187 else if constexpr (std::same_as<T, std::string>)
1189 result.append(
reinterpret_cast<char const *
>(arg.data()), arg.size() + 1 );
1191 else if constexpr (!std::ranges::range<T>)
1193 result.append(
reinterpret_cast<char const *
>(&arg),
sizeof(arg));
1197 int32_t sz{
static_cast<int32_t
>(arg.size())};
1198 result.append(
reinterpret_cast<char *
>(&sz), 4);
1199 result.append(
reinterpret_cast<char const *
>(arg.data()),
1200 arg.size() *
sizeof(std::ranges::range_value_t<T>));
1204 for (
auto & [tag, variant] : tag_dict)
1206 result.push_back(
static_cast<char>(tag / 256));
1207 result.push_back(
static_cast<char>(tag % 256));
1209 result.push_back(detail::sam_tag_type_char[variant.
index()]);
1211 if (!
is_char<
'\0'>(detail::sam_tag_type_char_extra[variant.
index()]))
1212 result.push_back(detail::sam_tag_type_char_extra[variant.
index()]);
constexpr derived_type & assign_rank(rank_type const c) noexcept
Assign from a numeric value.
Definition alphabet_base.hpp:184
The seqan3::cigar semialphabet pairs a counter with a seqan3::cigar::operation letter.
Definition alphabet/cigar/cigar.hpp:57
exposition_only::cigar_operation operation
The (extended) cigar operation alphabet of M,D,I,H,N,P,S,X,=.
Definition alphabet/cigar/cigar.hpp:93
A 16 letter DNA alphabet, containing all IUPAC symbols minus the gap and plus an equality sign ('=').
Definition dna16sam.hpp:45
The SAM tag dictionary class that stores all optional SAM fields.
Definition sam_tag_dictionary.hpp:327
Provides seqan3::dna16sam.
T emplace_back(T... args)
Provides seqan3::detail::fast_ostreambuf_iterator.
constexpr auto assign_char_to
Assign a character to an alphabet object.
Definition alphabet/concept.hpp:521
constexpr auto assign_char_strictly_to
Assign a character to an alphabet object, throw if the character is not valid.
Definition alphabet/concept.hpp:731
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition alphabet/concept.hpp:152
sam_flag
An enum flag that describes the properties of an aligned read (given as a SAM record).
Definition sam_flag.hpp:73
@ flag
The alignment flag (bit information), uint16_t value.
@ ref_offset
Sequence (seqan3::field::ref_seq) relative start position (0-based), unsigned value.
@ ref_seq
The (reference) "sequence" information, usually a range of nucleotides or amino acids.
@ mapq
The mapping quality of the seqan3::field::seq alignment, usually a Phred-scaled score.
@ bit_score
The bit score (statistical significance indicator), 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.
@ id
The identifier, usually a string.
@ seq
The "sequence", usually a range of nucleotides or amino acids.
@ qual
The qualities, usually in Phred score notation.
constexpr auto is_char
Checks whether a given letter is the same as the template non-type argument.
Definition predicate.hpp:60
constexpr ptrdiff_t count
Count the occurrences of a type in a pack.
Definition type_pack/traits.hpp:161
constexpr size_t size
The size of a type pack.
Definition type_pack/traits.hpp:143
constexpr auto repeat_n
A view factory that repeats a given value n times.
Definition repeat_n.hpp:88
The generic alphabet concept that covers most data types used in ranges.
A type that satisfies std::is_arithmetic_v<t>.
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:26
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:23
Provides seqan3::views::take_exactly and seqan3::views::take_exactly_or_throw.