68 template <
typename stream_type,
69 typename seq_legal_alph_type,
70 typename ref_seqs_type,
71 typename ref_ids_type,
72 typename stream_pos_type,
75 typename ref_seq_type,
77 typename ref_offset_type,
83 typename tag_dict_type,
84 typename e_value_type,
85 typename bit_score_type>
88 ref_seqs_type & ref_seqs,
90 stream_pos_type & position_buffer,
94 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
97 cigar_type & cigar_vector,
101 tag_dict_type & tag_dict,
102 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
103 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score));
105 template <
typename stream_type,
106 typename header_type,
109 typename ref_seq_type,
110 typename ref_id_type,
114 typename tag_dict_type>
117 [[maybe_unused]] header_type && header,
118 [[maybe_unused]] seq_type &&
seq,
119 [[maybe_unused]] qual_type &&
qual,
120 [[maybe_unused]] id_type &&
id,
121 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
122 [[maybe_unused]] ref_id_type &&
ref_id,
124 [[maybe_unused]] cigar_type && cigar_vector,
126 [[maybe_unused]] uint8_t
const mapq,
127 [[maybe_unused]] mate_type &&
mate,
128 [[maybe_unused]] tag_dict_type && tag_dict,
129 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
130 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score));
133 template <
typename stream_t,
typename header_type>
138 bool header_was_read{
false};
144 struct alignment_record_core
149 uint32_t l_read_name : 8;
152 uint32_t n_cigar_op : 16;
160 static_assert(
sizeof(alignment_record_core) == 36);
170 ret[
static_cast<index_t
>(
'I')] = 1;
171 ret[
static_cast<index_t
>(
'D')] = 2;
172 ret[
static_cast<index_t
>(
'N')] = 3;
173 ret[
static_cast<index_t
>(
'S')] = 4;
174 ret[
static_cast<index_t
>(
'H')] = 5;
175 ret[
static_cast<index_t
>(
'P')] = 6;
176 ret[
static_cast<index_t
>(
'=')] = 7;
177 ret[
static_cast<index_t
>(
'X')] = 8;
183 static uint16_t reg2bin(int32_t beg, int32_t end)
noexcept
186 if (beg >> 14 == end >> 14)
187 return ((1 << 15) - 1) / 7 + (beg >> 14);
188 if (beg >> 17 == end >> 17)
189 return ((1 << 12) - 1) / 7 + (beg >> 17);
190 if (beg >> 20 == end >> 20)
191 return ((1 << 9) - 1) / 7 + (beg >> 20);
192 if (beg >> 23 == end >> 23)
193 return ((1 << 6) - 1) / 7 + (beg >> 23);
194 if (beg >> 26 == end >> 26)
195 return ((1 << 3) - 1) / 7 + (beg >> 26);
205 template <
typename stream_view_type, std::
integral number_type>
206 void read_integral_byte_field(stream_view_type && stream_view, number_type & target)
212 template <std::
integral number_type>
213 void read_integral_byte_field(
std::string_view const str, number_type & target)
223 template <
typename stream_view_type>
224 void read_float_byte_field(stream_view_type && stream_view,
float & target)
229 template <
typename value_type>
232 value_type
const & SEQAN3_DOXYGEN_ONLY(value));
234 void read_sam_dict(
std::string_view const tag_str, sam_tag_dictionary & target);
238 static std::string get_tag_dict_str(sam_tag_dictionary
const & tag_dict);
242template <
typename stream_type,
243 typename seq_legal_alph_type,
244 typename ref_seqs_type,
245 typename ref_ids_type,
246 typename stream_pos_type,
249 typename ref_seq_type,
250 typename ref_id_type,
251 typename ref_offset_type,
257 typename tag_dict_type,
258 typename e_value_type,
259 typename bit_score_type>
263 ref_seqs_type & ref_seqs,
265 stream_pos_type & position_buffer,
269 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
272 cigar_type & cigar_vector,
276 tag_dict_type & tag_dict,
277 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
278 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score))
280 static_assert(detail::decays_to_ignore_v<ref_offset_type>
281 || detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
282 "The ref_offset must be a specialisation of std::optional.");
284 static_assert(detail::decays_to_ignore_v<mapq_type> || std::same_as<mapq_type, uint8_t>,
285 "The type of field::mapq must be uint8_t.");
287 static_assert(detail::decays_to_ignore_v<flag_type> || std::same_as<flag_type, sam_flag>,
288 "The type of field::flag must be seqan3::sam_flag.");
290 auto stream_view = seqan3::detail::istreambuf(stream);
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();
378 auto stream_it = detail::fast_istreambuf_iterator{*stream.rdbuf()};
380 alignment_record_core core;
384 if (core.refID >=
static_cast<int32_t
>(header.
ref_ids().size()) || core.refID < -1)
386 throw format_error{detail::to_string(
"Reference id index '",
388 "' is not in range of ",
389 "header.ref_ids(), which has size ",
393 else if (core.refID > -1)
399 mapq =
static_cast<uint8_t
>(core.mapq);
404 if constexpr (!detail::decays_to_ignore_v<mate_type>)
406 if (core.next_refID > -1)
407 get<0>(
mate) = core.next_refID;
409 if (core.next_pos > -1)
410 get<1>(
mate) = core.next_pos;
412 get<2>(
mate) = core.tlen;
417 std::string_view record_str = stream_it.cache_bytes(core.block_size - (
sizeof(alignment_record_core) - 4));
418 size_t considered_bytes{0};
420 if constexpr (!detail::decays_to_ignore_v<id_type>)
421 read_forward_range_field(record_str.
substr(0, core.l_read_name - 1),
id);
423 considered_bytes += core.l_read_name;
427 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
428 cigar_vector = parse_binary_cigar(record_str.
substr(considered_bytes, core.n_cigar_op * 4));
430 considered_bytes += core.n_cigar_op * 4;
434 if constexpr (!detail::decays_to_ignore_v<seq_type>)
436 size_t const number_of_bytes = (core.l_seq + 1) / 2;
443 using alph_t = std::ranges::range_value_t<
decltype(
seq)>;
444 constexpr auto from_dna16 = detail::convert_through_char_representation<dna16sam, alph_t>;
447 for (
size_t i = 0, j = 0; i < number_of_bytes; ++i, j += 2)
454 seq.resize(core.l_seq);
457 considered_bytes += (core.l_seq + 1) / 2;
461 if constexpr (!detail::decays_to_ignore_v<qual_type>)
464 qual.resize(core.l_seq);
466 for (int32_t i = 0; i < core.l_seq; ++i)
467 qual[i] =
assign_char_to(
static_cast<char>(qual_str[i] + 33), std::ranges::range_value_t<qual_type>{});
470 considered_bytes += core.l_seq;
474 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
475 read_sam_dict(record_str.
substr(considered_bytes), tag_dict);
479 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
481 int32_t
const sc_front = soft_clipping_at_front(cigar_vector);
486 if (core.l_seq != 0 && sc_front == core.l_seq)
488 if constexpr (detail::decays_to_ignore_v<tag_dict_type> | detail::decays_to_ignore_v<seq_type>)
491 detail::to_string(
"The cigar string '",
492 detail::get_cigar_string(cigar_vector),
493 "' suggests that the cigar string exceeded 65535 elements and was therefore ",
494 "stored in the optional field CG. You need to read in the field::tags and "
495 "field::seq in order to access this information.")};
499 auto it = tag_dict.find(
"CG"_tag);
501 if (it == tag_dict.end())
503 detail::to_string(
"The cigar string '",
504 detail::get_cigar_string(cigar_vector),
505 "' suggests that the cigar string exceeded 65535 elements and was therefore ",
506 "stored in the optional field CG but this tag is not present in the given ",
509 cigar_vector = detail::parse_cigar(std::get<std::string>(it->second));
517template <
typename stream_type,
518 typename header_type,
521 typename ref_seq_type,
522 typename ref_id_type,
526 typename tag_dict_type>
529 [[maybe_unused]] header_type && header,
530 [[maybe_unused]] seq_type &&
seq,
531 [[maybe_unused]] qual_type &&
qual,
532 [[maybe_unused]] id_type &&
id,
533 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
534 [[maybe_unused]] ref_id_type &&
ref_id,
536 [[maybe_unused]] cigar_type && cigar_vector,
538 [[maybe_unused]] uint8_t
const mapq,
539 [[maybe_unused]] mate_type &&
mate,
540 [[maybe_unused]] tag_dict_type && tag_dict,
541 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
542 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score))
548 "The seq object must be a std::ranges::forward_range over "
549 "letters that model seqan3::alphabet.");
552 "The id object must be a std::ranges::forward_range over "
553 "letters that model seqan3::alphabet.");
556 "The ref_seq object must be a std::ranges::forward_range "
557 "over letters that model seqan3::alphabet.");
559 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
561 static_assert((std::ranges::forward_range<ref_id_type> || std::integral<std::remove_reference_t<ref_id_type>>
562 || detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>),
563 "The ref_id object must be a std::ranges::forward_range "
564 "over letters that model seqan3::alphabet or an integral or a std::optional<integral>.");
568 "The qual object must be a std::ranges::forward_range "
569 "over letters that model seqan3::alphabet.");
572 "The mate object must be a std::tuple of size 3 with "
573 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
574 "2) a std::integral or std::optional<std::integral>, and "
575 "3) a std::integral.");
578 ((std::ranges::forward_range<decltype(std::get<0>(
mate))>
581 && (std::integral<std::remove_cvref_t<decltype(std::get<1>(
mate))>>
583 && std::integral<std::remove_cvref_t<decltype(std::get<2>(
mate))>>),
584 "The mate object must be a std::tuple of size 3 with "
585 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
586 "2) a std::integral or std::optional<std::integral>, and "
587 "3) a std::integral.");
590 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
592 if constexpr (detail::decays_to_ignore_v<header_type>)
594 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
595 "You can either construct the output file with reference names and reference length "
596 "information and the header will be created for you, or you can access the `header` member "
608 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
613 if (!header_was_written)
615 write_header(stream, options, header);
616 header_was_written =
true;
622 int32_t ref_length{};
625 if (!std::ranges::empty(cigar_vector))
627 int32_t dummy_seq_length{};
628 for (
auto & [count, operation] : cigar_vector)
629 detail::update_alignment_lengths(ref_length, dummy_seq_length, operation.to_char(), count);
632 if (cigar_vector.size() >= (1 << 16))
634 tag_dict[
"CG"_tag] = detail::get_cigar_string(cigar_vector);
635 cigar_vector.resize(2);
636 cigar_vector[0] =
cigar{
static_cast<uint32_t
>(std::ranges::distance(
seq)),
'S'_cigar_operation};
637 cigar_vector[1] =
cigar{
static_cast<uint32_t
>(ref_length),
'N'_cigar_operation};
640 std::string tag_dict_binary_str = get_tag_dict_str(tag_dict);
647 uint8_t read_name_size = std::min<uint8_t>(std::ranges::distance(
id), 254) + 1;
648 read_name_size +=
static_cast<uint8_t
>(read_name_size == 1);
650 alignment_record_core core{ 0,
656 static_cast<uint16_t
>(cigar_vector.size()),
658 static_cast<int32_t
>(std::ranges::distance(
seq)),
660 get<1>(
mate).value_or(-1),
663 auto check_and_assign_id_to = [&header]([[maybe_unused]]
auto & id_source, [[maybe_unused]]
auto & id_target)
667 if constexpr (!detail::decays_to_ignore_v<id_t>)
669 if constexpr (std::integral<id_t>)
671 id_target = id_source;
673 else if constexpr (detail::is_type_specialisation_of_v<id_t, std::optional>)
675 id_target = id_source.value_or(-1);
679 if (!std::ranges::empty(id_source))
683 if constexpr (std::ranges::contiguous_range<
decltype(id_source)>
684 && std::ranges::sized_range<
decltype(id_source)>
685 && std::ranges::borrowed_range<
decltype(id_source)>)
688 std::span{std::ranges::data(id_source), std::ranges::size(id_source)});
696 "The ref_id type is not convertible to the reference id information stored in the "
697 "reference dictionary of the header object.");
699 id_it = header.
ref_dict.find(id_source);
704 throw format_error{detail::to_string(
"Unknown reference name '",
707 "not be found in BAM header ref_dict: ",
712 id_target = id_it->second;
719 check_and_assign_id_to(
ref_id, core.refID);
722 check_and_assign_id_to(get<0>(
mate), core.next_refID);
725 core.block_size =
sizeof(core) - 4 + core.l_read_name + core.n_cigar_op * 4
727 (core.l_seq + 1) / 2 +
729 tag_dict_binary_str.
size();
733 if (std::ranges::empty(
id))
740 for (
auto [cigar_count, op] : cigar_vector)
742 cigar_count = cigar_count << 4;
743 cigar_count |=
static_cast<int32_t
>(char_to_sam_rank[op.to_char()]);
748 using alph_t = std::ranges::range_value_t<seq_type>;
749 constexpr auto to_dna16 = detail::convert_through_char_representation<alph_t, dna16sam>;
752 for (int32_t sidx = 0; sidx < ((core.l_seq & 1) ? core.l_seq - 1 : core.l_seq); ++sidx, ++sit)
757 stream_it =
static_cast<char>(compressed_chr);
761 stream_it =
static_cast<char>(
to_rank(to_dna16[
to_rank(*sit)]) << 4);
764 if (std::ranges::empty(
qual))
771 if (std::ranges::distance(
qual) != core.l_seq)
772 throw format_error{detail::to_string(
"Expected quality of same length as sequence with size ",
774 ". Got quality with size ",
775 std::ranges::distance(
qual),
779 | std::views::transform(
782 return static_cast<char>(
to_rank(chr));
788 stream << tag_dict_binary_str;
793template <
typename stream_t,
typename header_type>
794inline void format_bam::write_header(stream_t & stream,
sam_file_output_options const & options, header_type & header)
796 if constexpr (detail::decays_to_ignore_v<header_type>)
798 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
799 "You can either construct the output file with reference names and reference length "
800 "information and the header will be created for you, or you can access the `header` member "
805 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
811 detail::format_sam_base::write_header(os, options, header);
812#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI
813 int32_t
const l_text{
static_cast<int32_t
>(os.
str().size())};
815 int32_t
const l_text{
static_cast<int32_t
>(os.view().size())};
819#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI
820 auto header_view = os.
str();
822 auto header_view = os.view();
826 assert(header.ref_ids().size() < (1ull << 32));
827 int32_t
const n_ref{
static_cast<int32_t
>(header.ref_ids().size())};
830 for (int32_t ridx = 0; ridx < n_ref; ++ridx)
832 assert(header.ref_ids()[ridx].size() + 1 < (1ull << 32));
833 int32_t
const l_name{
static_cast<int32_t
>(header.ref_ids()[ridx].size()) + 1};
839 std::ranges::copy_n(
reinterpret_cast<char *
>(&get<0>(header.ref_id_info[ridx])), 4, stream_it);
862template <
typename value_type>
865 value_type
const & SEQAN3_DOXYGEN_ONLY(value))
867 auto it = str.
begin();
870 int32_t
const vector_size = [&]()
878 int32_t bytes_left{vector_size};
881 tmp_vector.
reserve(vector_size);
885 while (bytes_left > 0)
887 if constexpr (std::integral<value_type>)
889 else if constexpr (std::same_as<value_type, float>)
892 static_assert(std::is_same_v<value_type, void>,
"format_bam::read_sam_dict_vector: unsupported value_type");
899 variant = std::move(tmp_vector);
919inline void format_bam::read_sam_dict(
std::string_view const tag_str, sam_tag_dictionary & target)
927 auto it = tag_str.
begin();
930 auto parse_integer_into_target = [&]<std::integral int_t>(uint16_t
const tag, int_t)
934 target[tag] =
static_cast<int32_t
>(tmp);
939 auto parse_array_into_target = [&]<
arithmetic array_value_t>(uint16_t
const tag, array_value_t)
942 it +=
sizeof(int32_t) +
sizeof(array_value_t) *
count;
946 auto parse_tag = [&]()
948 uint16_t tag =
static_cast<uint16_t
>(*it) << 8;
950 tag |=
static_cast<uint16_t
>(*it);
955 while (it != tag_str.
end())
957 uint16_t
const tag = parse_tag();
959 char const type_id{*it};
973 parse_integer_into_target(tag, int8_t{});
978 parse_integer_into_target(tag, uint8_t{});
983 parse_integer_into_target(tag, int16_t{});
988 parse_integer_into_target(tag, uint16_t{});
993 parse_integer_into_target(tag, int32_t{});
998 parse_integer_into_target(tag, uint32_t{});
1006 it +=
sizeof(float);
1011 std::string const v{
static_cast<char const *
>(it)};
1013 target[tag] = std::move(v);
1022 uint8_t dummy_byte{};
1024 if (str.
size() % 2 != 0)
1025 throw format_error{
"[CORRUPTED BAM FILE] Hexadecimal tag must have even number of digits."};
1029 for (
auto hex_begin = str.
begin(), hex_end = str.
begin() + 2; hex_begin != str.
end();
1030 hex_begin += 2, hex_end += 2)
1034 if (res.ec == std::errc::invalid_argument)
1035 throw format_error{
std::string(
"[CORRUPTED BAM FILE] The string '")
1036 +
std::string(hex_begin, hex_end) +
"' could not be cast into type uint8_t."};
1038 if (res.ec == std::errc::result_out_of_range)
1040 +
"' into type uint8_t would cause an overflow."};
1045 target[tag] = std::move(tmp_vector);
1047 it += str.
size() + 1;
1053 char array_value_type_id = *it;
1056 switch (array_value_type_id)
1059 parse_array_into_target(tag, int8_t{});
1062 parse_array_into_target(tag, uint8_t{});
1065 parse_array_into_target(tag, int16_t{});
1068 parse_array_into_target(tag, uint16_t{});
1071 parse_array_into_target(tag, int32_t{});
1074 parse_array_into_target(tag, uint32_t{});
1077 parse_array_into_target(tag,
float{});
1080 throw format_error{detail::to_string(
"The first character in the numerical id of a SAM tag ",
1081 "must be one of [cCsSiIf] but '",
1082 array_value_type_id,
1088 throw format_error{detail::to_string(
"The second character in the numerical id of a "
1089 "SAM tag must be one of [A,i,Z,H,B,f] but '",
1105 cigar_operation_mapping{
'M',
'I',
'D',
'N',
'S',
'H',
'P',
'=',
'X',
'*',
'*',
'*',
'*',
'*',
'*',
'*'};
1107 constexpr uint32_t cigar_operation_mask = 0x0f;
1110 char operation{
'\0'};
1112 uint32_t operation_and_count{};
1114 assert(cigar_str.
size() % 4 == 0);
1116 for (
auto it = cigar_str.
begin(); it != cigar_str.
end(); it +=
sizeof(operation_and_count))
1118 std::memcpy(&operation_and_count, it,
sizeof(operation_and_count));
1119 operation = cigar_operation_mapping[operation_and_count & cigar_operation_mask];
1120 count = operation_and_count >> 4;
1125 return cigar_vector;
1131inline std::string format_bam::get_tag_dict_str(sam_tag_dictionary
const & tag_dict)
1135 auto stream_variant_fn = [&result](
auto && arg)
1140 if constexpr (std::same_as<T, int32_t>)
1143 size_t const absolute_arg = std::abs(arg);
1145 bool const negative = arg < 0;
1146 n = n * n + 2 * negative;
1152 result[result.size() - 1] =
'C';
1153 result.append(
reinterpret_cast<char const *
>(&arg), 1);
1158 result[result.size() - 1] =
'S';
1159 result.append(
reinterpret_cast<char const *
>(&arg), 2);
1164 result[result.size() - 1] =
'c';
1165 int8_t tmp =
static_cast<int8_t
>(arg);
1166 result.append(
reinterpret_cast<char const *
>(&tmp), 1);
1171 result[result.size() - 1] =
's';
1172 int16_t tmp =
static_cast<int16_t
>(arg);
1173 result.append(
reinterpret_cast<char const *
>(&tmp), 2);
1178 result.append(
reinterpret_cast<char const *
>(&arg), 4);
1183 else if constexpr (std::same_as<T, std::string>)
1185 result.append(
reinterpret_cast<char const *
>(arg.data()), arg.size() + 1 );
1187 else if constexpr (!std::ranges::range<T>)
1189 result.append(
reinterpret_cast<char const *
>(&arg),
sizeof(arg));
1193 int32_t sz{
static_cast<int32_t
>(arg.size())};
1194 result.append(
reinterpret_cast<char *
>(&sz), 4);
1195 result.append(
reinterpret_cast<char const *
>(arg.data()),
1196 arg.size() *
sizeof(std::ranges::range_value_t<T>));
1200 for (
auto & [tag, variant] : tag_dict)
1202 result.push_back(
static_cast<char>(tag / 256));
1203 result.push_back(
static_cast<char>(tag % 256));
1205 result.push_back(detail::sam_tag_type_char[variant.
index()]);
1207 if (!
is_char<
'\0'>(detail::sam_tag_type_char_extra[variant.
index()]))
1208 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:517
constexpr auto assign_char_strictly_to
Assign a character to an alphabet object, throw if the character is not valid.
Definition alphabet/concept.hpp:721
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.
Provides seqan3::debug_stream and related types.