70 template <
typename stream_type,
71 typename seq_legal_alph_type,
72 typename ref_seqs_type,
73 typename ref_ids_type,
74 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,
96 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
99 cigar_type & cigar_vector,
103 tag_dict_type & tag_dict,
104 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
105 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score));
107 template <
typename stream_type,
108 typename header_type,
111 typename ref_seq_type,
112 typename ref_id_type,
116 typename tag_dict_type>
119 [[maybe_unused]] header_type && header,
120 [[maybe_unused]] seq_type &&
seq,
121 [[maybe_unused]] qual_type &&
qual,
122 [[maybe_unused]] id_type &&
id,
123 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
124 [[maybe_unused]] ref_id_type &&
ref_id,
126 [[maybe_unused]] cigar_type && cigar_vector,
128 [[maybe_unused]] uint8_t
const mapq,
129 [[maybe_unused]] mate_type &&
mate,
130 [[maybe_unused]] tag_dict_type && tag_dict,
131 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
132 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score));
135 template <
typename stream_t,
typename header_type>
140 bool header_was_read{
false};
146 struct alignment_record_core
151 uint32_t l_read_name : 8;
154 uint32_t n_cigar_op : 16;
162 static_assert(
sizeof(alignment_record_core) == 36);
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)
218 template <std::
integral number_type>
219 void read_integral_byte_field(
std::string_view const str, number_type & target)
229 template <
typename stream_view_type>
230 void read_float_byte_field(stream_view_type && stream_view,
float & target)
235 template <
typename value_type>
238 value_type
const & SEQAN3_DOXYGEN_ONLY(value));
240 void read_sam_dict(
std::string_view const tag_str, sam_tag_dictionary & target);
244 static std::string get_tag_dict_str(sam_tag_dictionary
const & tag_dict);
248template <
typename stream_type,
249 typename seq_legal_alph_type,
250 typename ref_seqs_type,
251 typename ref_ids_type,
252 typename stream_pos_type,
255 typename ref_seq_type,
256 typename ref_id_type,
257 typename ref_offset_type,
263 typename tag_dict_type,
264 typename e_value_type,
265 typename bit_score_type>
269 ref_seqs_type & ref_seqs,
271 stream_pos_type & position_buffer,
275 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
278 cigar_type & cigar_vector,
282 tag_dict_type & tag_dict,
283 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
284 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score))
286 static_assert(detail::decays_to_ignore_v<ref_offset_type>
287 || detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
288 "The ref_offset must be a specialisation of std::optional.");
290 static_assert(detail::decays_to_ignore_v<mapq_type> || std::same_as<mapq_type, uint8_t>,
291 "The type of field::mapq must be uint8_t.");
293 static_assert(detail::decays_to_ignore_v<flag_type> || std::same_as<flag_type, sam_flag>,
294 "The type of field::flag must be seqan3::sam_flag.");
296 auto stream_view = seqan3::detail::istreambuf(stream);
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();
384 auto stream_it = detail::fast_istreambuf_iterator{*stream.rdbuf()};
386 alignment_record_core core;
390 if (core.refID >=
static_cast<int32_t
>(header.
ref_ids().size()) || core.refID < -1)
392 throw format_error{detail::to_string(
"Reference id index '",
394 "' is not in range of ",
395 "header.ref_ids(), which has size ",
399 else if (core.refID > -1)
410 if constexpr (!detail::decays_to_ignore_v<mate_type>)
412 if (core.next_refID > -1)
413 get<0>(
mate) = core.next_refID;
415 if (core.next_pos > -1)
416 get<1>(
mate) = core.next_pos;
418 get<2>(
mate) = core.tlen;
423 std::string_view record_str = stream_it.cache_bytes(core.block_size - (
sizeof(alignment_record_core) - 4));
424 size_t considered_bytes{0};
426 if constexpr (!detail::decays_to_ignore_v<id_type>)
427 read_forward_range_field(record_str.
substr(0, core.l_read_name - 1),
id);
429 considered_bytes += core.l_read_name;
433 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
434 cigar_vector = parse_binary_cigar(record_str.
substr(considered_bytes, core.n_cigar_op * 4));
436 considered_bytes += core.n_cigar_op * 4;
440 if constexpr (!detail::decays_to_ignore_v<seq_type>)
442 size_t const number_of_bytes = (core.l_seq + 1) / 2;
449 using alph_t = std::ranges::range_value_t<
decltype(
seq)>;
450 constexpr auto from_dna16 = detail::convert_through_char_representation<dna16sam, alph_t>;
453 for (
size_t i = 0, j = 0; i < number_of_bytes; ++i, j += 2)
460 seq.resize(core.l_seq);
463 considered_bytes += (core.l_seq + 1) / 2;
467 if constexpr (!detail::decays_to_ignore_v<qual_type>)
470 qual.resize(core.l_seq);
472 for (int32_t i = 0; i < core.l_seq; ++i)
473 qual[i] =
assign_char_to(
static_cast<char>(qual_str[i] + 33), std::ranges::range_value_t<qual_type>{});
476 considered_bytes += core.l_seq;
480 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
481 read_sam_dict(record_str.
substr(considered_bytes), tag_dict);
485 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
487 int32_t
const sc_front = soft_clipping_at_front(cigar_vector);
492 if (core.l_seq != 0 && sc_front == core.l_seq)
494 if constexpr (detail::decays_to_ignore_v<tag_dict_type> | detail::decays_to_ignore_v<seq_type>)
497 detail::to_string(
"The cigar string '",
498 detail::get_cigar_string(cigar_vector),
499 "' suggests that the cigar string exceeded 65535 elements and was therefore ",
500 "stored in the optional field CG. You need to read in the field::tags and "
501 "field::seq in order to access this information.")};
505 auto it = tag_dict.find(
"CG"_tag);
507 if (it == tag_dict.end())
509 detail::to_string(
"The cigar string '",
510 detail::get_cigar_string(cigar_vector),
511 "' suggests that the cigar string exceeded 65535 elements and was therefore ",
512 "stored in the optional field CG but this tag is not present in the given ",
515 cigar_vector = detail::parse_cigar(std::get<std::string>(it->second));
523template <
typename stream_type,
524 typename header_type,
527 typename ref_seq_type,
528 typename ref_id_type,
532 typename tag_dict_type>
535 [[maybe_unused]] header_type && header,
536 [[maybe_unused]] seq_type &&
seq,
537 [[maybe_unused]] qual_type &&
qual,
538 [[maybe_unused]] id_type &&
id,
539 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
540 [[maybe_unused]] ref_id_type &&
ref_id,
542 [[maybe_unused]] cigar_type && cigar_vector,
544 [[maybe_unused]] uint8_t
const mapq,
545 [[maybe_unused]] mate_type &&
mate,
546 [[maybe_unused]] tag_dict_type && tag_dict,
547 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
548 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score))
554 "The seq object must be a std::ranges::forward_range over "
555 "letters that model seqan3::alphabet.");
558 "The id object must be a std::ranges::forward_range over "
559 "letters that model seqan3::alphabet.");
562 "The ref_seq object must be a std::ranges::forward_range "
563 "over letters that model seqan3::alphabet.");
565 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
567 static_assert((std::ranges::forward_range<ref_id_type> || std::integral<std::remove_reference_t<ref_id_type>>
568 || detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>),
569 "The ref_id object must be a std::ranges::forward_range "
570 "over letters that model seqan3::alphabet or an integral or a std::optional<integral>.");
574 "The qual object must be a std::ranges::forward_range "
575 "over letters that model seqan3::alphabet.");
578 "The mate object must be a std::tuple of size 3 with "
579 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
580 "2) a std::integral or std::optional<std::integral>, and "
581 "3) a std::integral.");
584 ((std::ranges::forward_range<decltype(std::get<0>(
mate))>
586 || detail::is_type_specialisation_of_v<
588 std::optional>)&&(std::integral<std::remove_cvref_t<decltype(std::get<1>(
mate))>>
589 || detail::is_type_specialisation_of_v<
591 std::optional>)&&std::integral<std::remove_cvref_t<decltype(std::get<2>(
mate))>>),
592 "The mate object must be a std::tuple of size 3 with "
593 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
594 "2) a std::integral or std::optional<std::integral>, and "
595 "3) a std::integral.");
598 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
600 if constexpr (detail::decays_to_ignore_v<header_type>)
602 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
603 "You can either construct the output file with reference names and reference length "
604 "information and the header will be created for you, or you can access the `header` member "
616 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
621 if (!header_was_written)
623 write_header(stream, options, header);
624 header_was_written =
true;
630 int32_t ref_length{};
633 if (!std::ranges::empty(cigar_vector))
635 int32_t dummy_seq_length{};
636 for (
auto & [count, operation] : cigar_vector)
637 detail::update_alignment_lengths(ref_length, dummy_seq_length, operation.to_char(), count);
640 if (cigar_vector.size() >= (1 << 16))
642 tag_dict[
"CG"_tag] = detail::get_cigar_string(cigar_vector);
643 cigar_vector.resize(2);
644 cigar_vector[0] =
cigar{
static_cast<uint32_t
>(std::ranges::distance(
seq)),
'S'_cigar_operation};
645 cigar_vector[1] =
cigar{
static_cast<uint32_t
>(ref_length),
'N'_cigar_operation};
648 std::string tag_dict_binary_str = get_tag_dict_str(tag_dict);
655 uint8_t read_name_size = std::min<uint8_t>(std::ranges::distance(
id), 254) + 1;
656 read_name_size +=
static_cast<uint8_t
>(read_name_size == 1);
658 alignment_record_core core{ 0,
664 static_cast<uint16_t
>(cigar_vector.size()),
666 static_cast<int32_t
>(std::ranges::distance(
seq)),
668 get<1>(
mate).value_or(-1),
671 auto check_and_assign_id_to = [&header]([[maybe_unused]]
auto & id_source, [[maybe_unused]]
auto & id_target)
675 if constexpr (!detail::decays_to_ignore_v<id_t>)
677 if constexpr (std::integral<id_t>)
679 id_target = id_source;
681 else if constexpr (detail::is_type_specialisation_of_v<id_t, std::optional>)
683 id_target = id_source.value_or(-1);
687 if (!std::ranges::empty(id_source))
691 if constexpr (std::ranges::contiguous_range<
decltype(id_source)>
692 && std::ranges::sized_range<
decltype(id_source)>
693 && std::ranges::borrowed_range<
decltype(id_source)>)
696 std::span{std::ranges::data(id_source), std::ranges::size(id_source)});
704 "The ref_id type is not convertible to the reference id information stored in the "
705 "reference dictionary of the header object.");
707 id_it = header.
ref_dict.find(id_source);
712 throw format_error{detail::to_string(
"Unknown reference name '",
715 "not be found in BAM header ref_dict: ",
720 id_target = id_it->second;
727 check_and_assign_id_to(
ref_id, core.refID);
730 check_and_assign_id_to(get<0>(
mate), core.next_refID);
733 core.block_size =
sizeof(core) - 4 + core.l_read_name + core.n_cigar_op * 4
735 (core.l_seq + 1) / 2 +
737 tag_dict_binary_str.
size();
741 if (std::ranges::empty(
id))
748 for (
auto [cigar_count, op] : cigar_vector)
750 cigar_count = cigar_count << 4;
751 cigar_count |=
static_cast<int32_t
>(char_to_sam_rank[op.to_char()]);
756 using alph_t = std::ranges::range_value_t<seq_type>;
757 constexpr auto to_dna16 = detail::convert_through_char_representation<alph_t, dna16sam>;
760 for (int32_t sidx = 0; sidx < ((core.l_seq & 1) ? core.l_seq - 1 : core.l_seq); ++sidx, ++sit)
765 stream_it =
static_cast<char>(compressed_chr);
769 stream_it =
static_cast<char>(
to_rank(to_dna16[
to_rank(*sit)]) << 4);
772 if (std::ranges::empty(
qual))
779 if (std::ranges::distance(
qual) != core.l_seq)
780 throw format_error{detail::to_string(
"Expected quality of same length as sequence with size ",
782 ". Got quality with size ",
783 std::ranges::distance(
qual),
787 | std::views::transform(
790 return static_cast<char>(
to_rank(chr));
796 stream << tag_dict_binary_str;
801template <
typename stream_t,
typename header_type>
802inline void format_bam::write_header(stream_t & stream,
sam_file_output_options const & options, header_type & header)
804 if constexpr (detail::decays_to_ignore_v<header_type>)
806 throw format_error{
"BAM can only be written with a header but you did not provide enough information! "
807 "You can either construct the output file with reference names and reference length "
808 "information and the header will be created for you, or you can access the `header` member "
813 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
819 detail::format_sam_base::write_header(os, options, header);
820#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI
821 int32_t
const l_text{
static_cast<int32_t
>(os.
str().size())};
823 int32_t
const l_text{
static_cast<int32_t
>(os.view().size())};
827#if SEQAN3_WORKAROUND_GCC_NO_CXX11_ABI
828 auto header_view = os.
str();
830 auto header_view = os.view();
834 assert(header.ref_ids().size() < (1ull << 32));
835 int32_t
const n_ref{
static_cast<int32_t
>(header.ref_ids().size())};
838 for (int32_t ridx = 0; ridx < n_ref; ++ridx)
840 assert(header.ref_ids()[ridx].size() + 1 < (1ull << 32));
841 int32_t
const l_name{
static_cast<int32_t
>(header.ref_ids()[ridx].size()) + 1};
847 std::ranges::copy_n(
reinterpret_cast<char *
>(&get<0>(header.ref_id_info[ridx])), 4, stream_it);
870template <
typename value_type>
873 value_type
const & SEQAN3_DOXYGEN_ONLY(value))
875 auto it = str.
begin();
878 int32_t
const vector_size = [&]()
886 int32_t bytes_left{vector_size};
889 tmp_vector.
reserve(vector_size);
893 while (bytes_left > 0)
895 if constexpr (std::integral<value_type>)
897 else if constexpr (std::same_as<value_type, float>)
900 static_assert(std::is_same_v<value_type, void>,
"format_bam::read_sam_dict_vector: unsupported value_type");
907 variant = std::move(tmp_vector);
927inline void format_bam::read_sam_dict(
std::string_view const tag_str, sam_tag_dictionary & target)
935 auto it = tag_str.
begin();
938 auto parse_integer_into_target = [&]<std::integral int_t>(uint16_t
const tag, int_t)
942 target[tag] =
static_cast<int32_t
>(tmp);
947 auto parse_array_into_target = [&]<
arithmetic array_value_t>(uint16_t
const tag, array_value_t)
950 it +=
sizeof(int32_t) +
sizeof(array_value_t) *
count;
954 auto parse_tag = [&]()
956 uint16_t tag =
static_cast<uint16_t
>(*it) << 8;
958 tag |=
static_cast<uint16_t
>(*it);
963 while (it != tag_str.
end())
965 uint16_t
const tag = parse_tag();
967 char const type_id{*it};
981 parse_integer_into_target(tag, int8_t{});
986 parse_integer_into_target(tag, uint8_t{});
991 parse_integer_into_target(tag, int16_t{});
996 parse_integer_into_target(tag, uint16_t{});
1001 parse_integer_into_target(tag, int32_t{});
1006 parse_integer_into_target(tag, uint32_t{});
1014 it +=
sizeof(float);
1019 std::string const v{
static_cast<char const *
>(it)};
1021 target[tag] = std::move(v);
1030 uint8_t dummy_byte{};
1032 if (str.
size() % 2 != 0)
1033 throw format_error{
"[CORRUPTED BAM FILE] Hexadecimal tag must have even number of digits."};
1037 for (
auto hex_begin = str.
begin(), hex_end = str.
begin() + 2; hex_begin != str.
end();
1038 hex_begin += 2, hex_end += 2)
1042 if (res.ec == std::errc::invalid_argument)
1043 throw format_error{
std::string(
"[CORRUPTED BAM FILE] The string '")
1044 +
std::string(hex_begin, hex_end) +
"' could not be cast into type uint8_t."};
1046 if (res.ec == std::errc::result_out_of_range)
1048 +
"' into type uint8_t would cause an overflow."};
1053 target[tag] = std::move(tmp_vector);
1055 it += str.
size() + 1;
1061 char array_value_type_id = *it;
1064 switch (array_value_type_id)
1067 parse_array_into_target(tag, int8_t{});
1070 parse_array_into_target(tag, uint8_t{});
1073 parse_array_into_target(tag, int16_t{});
1076 parse_array_into_target(tag, uint16_t{});
1079 parse_array_into_target(tag, int32_t{});
1082 parse_array_into_target(tag, uint32_t{});
1085 parse_array_into_target(tag,
float{});
1088 throw format_error{detail::to_string(
"The first character in the numerical id of a SAM tag ",
1089 "must be one of [cCsSiIf] but '",
1090 array_value_type_id,
1096 throw format_error{detail::to_string(
"The second character in the numerical id of a "
1097 "SAM tag must be one of [A,i,Z,H,B,f] but '",
1113 cigar_operation_mapping{
'M',
'I',
'D',
'N',
'S',
'H',
'P',
'=',
'X',
'*',
'*',
'*',
'*',
'*',
'*',
'*'};
1115 constexpr uint32_t cigar_operation_mask = 0x0f;
1118 char operation{
'\0'};
1120 uint32_t operation_and_count{};
1122 assert(cigar_str.
size() % 4 == 0);
1124 for (
auto it = cigar_str.
begin(); it != cigar_str.
end(); it +=
sizeof(operation_and_count))
1126 std::memcpy(&operation_and_count, it,
sizeof(operation_and_count));
1127 operation = cigar_operation_mapping[operation_and_count & cigar_operation_mask];
1128 count = operation_and_count >> 4;
1133 return cigar_vector;
1139inline std::string format_bam::get_tag_dict_str(sam_tag_dictionary
const & tag_dict)
1143 auto stream_variant_fn = [&result](
auto && arg)
1148 if constexpr (std::same_as<T, int32_t>)
1151 size_t const absolute_arg = std::abs(arg);
1153 bool const negative = arg < 0;
1154 n = n * n + 2 * negative;
1160 result[result.size() - 1] =
'C';
1161 result.append(
reinterpret_cast<char const *
>(&arg), 1);
1166 result[result.size() - 1] =
'S';
1167 result.append(
reinterpret_cast<char const *
>(&arg), 2);
1172 result[result.size() - 1] =
'c';
1173 int8_t tmp =
static_cast<int8_t
>(arg);
1174 result.append(
reinterpret_cast<char const *
>(&tmp), 1);
1179 result[result.size() - 1] =
's';
1180 int16_t tmp =
static_cast<int16_t
>(arg);
1181 result.append(
reinterpret_cast<char const *
>(&tmp), 2);
1186 result.append(
reinterpret_cast<char const *
>(&arg), 4);
1191 else if constexpr (std::same_as<T, std::string>)
1193 result.append(
reinterpret_cast<char const *
>(arg.data()), arg.size() + 1 );
1195 else if constexpr (!std::ranges::range<T>)
1197 result.append(
reinterpret_cast<char const *
>(&arg),
sizeof(arg));
1201 int32_t sz{
static_cast<int32_t
>(arg.size())};
1202 result.append(
reinterpret_cast<char *
>(&sz), 4);
1203 result.append(
reinterpret_cast<char const *
>(arg.data()),
1204 arg.size() *
sizeof(std::ranges::range_value_t<T>));
1208 for (
auto & [tag, variant] : tag_dict)
1210 result.push_back(
static_cast<char>(tag / 256));
1211 result.push_back(
static_cast<char>(tag % 256));
1213 result.push_back(detail::sam_tag_type_char[variant.
index()]);
1215 if (!
is_char<
'\0'>(detail::sam_tag_type_char_extra[variant.
index()]))
1216 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: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 assign_char_to
Assign a character to an alphabet object.
Definition: alphabet/concept.hpp:524
constexpr auto assign_char_strictly_to
Assign a character to an alphabet object, throw if the character is not valid.
Definition: alphabet/concept.hpp:734
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.
@ 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:63
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.
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: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.