19 #include <seqan3/alphabet/detail/convert.hpp> 80 template <
typename stream_type,
81 typename seq_legal_alph_type,
82 typename ref_seqs_type,
83 typename ref_ids_type,
87 typename ref_seq_type,
89 typename ref_offset_type,
96 typename tag_dict_type,
97 typename e_value_type,
98 typename bit_score_type>
101 ref_seqs_type & ref_seqs,
107 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
111 cigar_type & cigar_vector,
115 tag_dict_type & tag_dict,
116 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
117 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score));
119 template <
typename stream_type,
120 typename header_type,
123 typename ref_seq_type,
124 typename ref_id_type,
129 typename tag_dict_type>
132 [[maybe_unused]] header_type && header,
133 [[maybe_unused]] seq_type && seq,
134 [[maybe_unused]] qual_type && qual,
135 [[maybe_unused]] id_type &&
id,
136 [[maybe_unused]] int32_t
const offset,
137 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
138 [[maybe_unused]] ref_id_type && ref_id,
140 [[maybe_unused]] align_type && align,
141 [[maybe_unused]] cigar_type && cigar_vector,
142 [[maybe_unused]]
sam_flag const flag,
143 [[maybe_unused]] uint8_t
const mapq,
144 [[maybe_unused]] mate_type && mate,
145 [[maybe_unused]] tag_dict_type && tag_dict,
146 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
147 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score));
151 bool header_was_read{
false};
157 struct alignment_record_core
162 uint32_t l_read_name:8;
165 uint32_t n_cigar_op:16;
183 ret[
static_cast<index_t
>(
'I')] = 1;
184 ret[
static_cast<index_t
>(
'D')] = 2;
185 ret[
static_cast<index_t
>(
'N')] = 3;
186 ret[
static_cast<index_t
>(
'S')] = 4;
187 ret[
static_cast<index_t
>(
'H')] = 5;
188 ret[
static_cast<index_t
>(
'P')] = 6;
189 ret[
static_cast<index_t
>(
'=')] = 7;
190 ret[
static_cast<index_t
>(
'X')] = 8;
197 static uint16_t reg2bin(int32_t beg, int32_t end) noexcept
200 if (beg >> 14 == end >> 14)
return ((1 << 15) - 1) / 7 + (beg >> 14);
201 if (beg >> 17 == end >> 17)
return ((1 << 12) - 1) / 7 + (beg >> 17);
202 if (beg >> 20 == end >> 20)
return ((1 << 9) - 1) / 7 + (beg >> 20);
203 if (beg >> 23 == end >> 23)
return ((1 << 6) - 1) / 7 + (beg >> 23);
204 if (beg >> 26 == end >> 26)
return ((1 << 3) - 1) / 7 + (beg >> 26);
208 using format_sam_base::read_field;
216 template <
typename stream_view_type, std::
integral number_type>
217 void read_field(stream_view_type && stream_view, number_type & target)
219 std::ranges::copy_n(std::ranges::begin(stream_view),
sizeof(target), reinterpret_cast<char *>(&target));
227 template <
typename stream_view_type>
228 void read_field(stream_view_type && stream_view,
float & target)
230 std::ranges::copy_n(std::ranges::begin(stream_view),
sizeof(int32_t), reinterpret_cast<char *>(&target));
243 template <
typename stream_view_type,
typename optional_value_type>
246 optional_value_type tmp;
247 read_field(std::forward<stream_view_type>(stream_view), tmp);
251 template <
typename stream_view_type,
typename value_type>
253 stream_view_type && stream_view,
254 value_type const & SEQAN3_DOXYGEN_ONLY(value));
256 template <
typename stream_view_type>
259 template <
typename cigar_input_type>
260 auto parse_binary_cigar(cigar_input_type && cigar_input, uint16_t n_cigar_op)
const;
266 template <
typename stream_type,
267 typename seq_legal_alph_type,
268 typename ref_seqs_type,
269 typename ref_ids_type,
272 typename offset_type,
273 typename ref_seq_type,
274 typename ref_id_type,
275 typename ref_offset_type,
282 typename tag_dict_type,
283 typename e_value_type,
284 typename bit_score_type>
287 ref_seqs_type & ref_seqs,
293 ref_seq_type & SEQAN3_DOXYGEN_ONLY(
ref_seq),
297 cigar_type & cigar_vector,
301 tag_dict_type & tag_dict,
302 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
303 bit_score_type & SEQAN3_DOXYGEN_ONLY(
bit_score))
305 static_assert(detail::decays_to_ignore_v<ref_offset_type> ||
306 detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
307 "The ref_offset must be a specialisation of std::optional.");
310 "The type of field::mapq must be uint8_t.");
313 "The type of field::flag must be seqan3::sam_flag.");
316 auto stream_view = std::ranges::subrange<decltype(stream_buf_t{stream}), decltype(stream_buf_t{})>
317 {stream_buf_t{stream}, stream_buf_t{}};
320 [[maybe_unused]] int32_t offset_tmp{};
321 [[maybe_unused]] int32_t soft_clipping_end{};
323 [[maybe_unused]] int32_t ref_length{0}, seq_length{0};
327 if (!header_was_read)
334 read_field(stream_view, tmp32);
340 read_field(stream_view, n_ref);
342 for (int32_t ref_idx = 0; ref_idx < n_ref; ++ref_idx)
344 read_field(stream_view, tmp32);
346 string_buffer.resize(tmp32 - 1);
347 std::ranges::copy_n(std::ranges::begin(stream_view), tmp32 - 1, string_buffer.data());
348 std::ranges::next(std::ranges::begin(stream_view));
350 read_field(stream_view, tmp32);
352 auto id_it = header.
ref_dict.find(string_buffer);
357 throw format_error{detail::to_string(
"Unknown reference name '" + string_buffer +
358 "' found in BAM file header (header.ref_ids():",
361 else if (id_it->second != ref_idx)
363 throw format_error{detail::to_string(
"Reference id '", string_buffer,
"' at position ", ref_idx,
364 " does not correspond to the position ", id_it->second,
365 " in the header (header.ref_ids():", header.
ref_ids(),
").")};
367 else if (std::get<0>(header.
ref_id_info[id_it->second]) != tmp32)
369 throw format_error{
"Provided reference has unequal length as specified in the header."};
373 header_was_read =
true;
375 if (stream_buf_t{stream} == stream_buf_t{})
381 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 '", core.refID,
"' is not in range of ",
387 "header.ref_ids(), which has size ", header.
ref_ids().size(),
".")};
389 else if (core.refID > -1)
398 ref_offset = core.pos;
400 if constexpr (!detail::decays_to_ignore_v<mate_type>)
402 if (core.next_refID > -1)
403 get<0>(
mate) = core.next_refID;
405 if (core.next_pos > -1)
406 get<1>(
mate) = core.next_pos;
408 get<2>(mate) = core.tlen;
414 std::ranges::next(std::ranges::begin(stream_view));
418 if constexpr (!detail::decays_to_ignore_v<align_type> || !detail::decays_to_ignore_v<cigar_type>)
420 std::tie(tmp_cigar_vector, ref_length, seq_length) = parse_binary_cigar(stream_view, core.n_cigar_op);
421 transfer_soft_clipping_to(tmp_cigar_vector, offset_tmp, soft_clipping_end);
435 auto seq_stream = stream_view
443 if constexpr (detail::decays_to_ignore_v<seq_type>)
445 if constexpr (!detail::decays_to_ignore_v<align_type>)
448 "If you want to read ALIGNMENT but not SEQ, the alignment" 449 " object must store a sequence container at the second (query) position.");
451 if (!tmp_cigar_vector.empty())
453 assert(core.l_seq == (seq_length + offset_tmp + soft_clipping_end));
455 constexpr
auto from_dna16 = detail::convert_through_char_representation<alph_t, sam_dna16>;
457 get<1>(align).reserve(seq_length);
459 auto tmp_iter = std::ranges::begin(seq_stream);
460 std::ranges::advance(tmp_iter, offset_tmp / 2);
464 get<1>(align).push_back(from_dna16[
to_rank(get<1>(*tmp_iter))]);
469 for (
size_t i = (seq_length / 2); i > 0; --i)
471 get<1>(align).push_back(from_dna16[
to_rank(get<0>(*tmp_iter))]);
472 get<1>(align).push_back(from_dna16[
to_rank(get<1>(*tmp_iter))]);
478 get<1>(align).push_back(from_dna16[
to_rank(get<0>(*tmp_iter))]);
483 std::ranges::advance(tmp_iter, (soft_clipping_end + !(seq_length & 1)) / 2);
492 detail::consume(seq_stream);
494 std::ranges::next(std::ranges::begin(stream_view));
500 constexpr
auto from_dna16 = detail::convert_through_char_representation<alph_t, sam_dna16>;
502 for (
auto [d1, d2] : seq_stream)
504 seq.push_back(from_dna16[
to_rank(d1)]);
505 seq.push_back(from_dna16[
to_rank(d2)]);
511 seq.push_back(from_dna16[
to_rank(d)]);
512 std::ranges::next(std::ranges::begin(stream_view));
515 if constexpr (!detail::decays_to_ignore_v<align_type>)
518 seq |
views::slice(
static_cast<decltype(std::ranges::distance(seq))
>(offset_tmp),
519 std::ranges::distance(seq) - soft_clipping_end));
531 int32_t remaining_bytes = core.block_size - (
sizeof(alignment_record_core) - 4) -
532 core.l_read_name - core.n_cigar_op * 4 - (core.l_seq + 1) / 2 - core.l_seq;
533 assert(remaining_bytes >= 0);
536 while (tags_view.size() > 0)
537 read_field(tags_view, tag_dict);
541 if constexpr (!detail::decays_to_ignore_v<align_type>)
546 if (core.l_seq != 0 && offset_tmp == core.l_seq)
548 if constexpr (detail::decays_to_ignore_v<tag_dict_type> | detail::decays_to_ignore_v<seq_type>)
550 throw format_error{detail::to_string(
"The cigar string '", offset_tmp,
"S", ref_length,
551 "N' suggests that the cigar string exceeded 65535 elements and was therefore ",
552 "stored in the optional field CG. You need to read in the field::tags and " 553 "field::seq in order to access this information.")};
557 auto it = tag_dict.find(
"CG"_tag);
559 if (it == tag_dict.end())
560 throw format_error{detail::to_string(
"The cigar string '", offset_tmp,
"S", ref_length,
561 "N' suggests that the cigar string exceeded 65535 elements and was therefore ",
562 "stored in the optional field CG but this tag is not present in the given ",
566 std::tie(tmp_cigar_vector, ref_length, seq_length) = parse_cigar(cigar_view);
567 offset_tmp = soft_clipping_end = 0;
568 transfer_soft_clipping_to(tmp_cigar_vector, offset_tmp, soft_clipping_end);
571 seq |
views::slice(
static_cast<decltype(std::ranges::distance(seq))
>(offset_tmp),
572 std::ranges::distance(seq) - soft_clipping_end));
578 construct_alignment(align, tmp_cigar_vector, core.refID, ref_seqs, core.pos, ref_length);
581 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
582 std::swap(cigar_vector, tmp_cigar_vector);
586 template <
typename stream_type,
587 typename header_type,
590 typename ref_seq_type,
591 typename ref_id_type,
596 typename tag_dict_type>
599 [[maybe_unused]] header_type && header,
600 [[maybe_unused]] seq_type && seq,
601 [[maybe_unused]] qual_type && qual,
602 [[maybe_unused]] id_type &&
id,
603 [[maybe_unused]] int32_t
const offset,
604 [[maybe_unused]] ref_seq_type && SEQAN3_DOXYGEN_ONLY(
ref_seq),
605 [[maybe_unused]] ref_id_type && ref_id,
607 [[maybe_unused]] align_type && align,
608 [[maybe_unused]] cigar_type && cigar_vector,
609 [[maybe_unused]]
sam_flag const flag,
610 [[maybe_unused]] uint8_t
const mapq,
611 [[maybe_unused]] mate_type && mate,
612 [[maybe_unused]] tag_dict_type && tag_dict,
613 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(e_value),
614 [[maybe_unused]]
double SEQAN3_DOXYGEN_ONLY(
bit_score))
619 static_assert((std::ranges::forward_range<seq_type> &&
621 "The seq object must be a std::ranges::forward_range over " 622 "letters that model seqan3::alphabet.");
624 static_assert((std::ranges::forward_range<id_type> &&
626 "The id object must be a std::ranges::forward_range over " 627 "letters that model seqan3::alphabet.");
629 static_assert((std::ranges::forward_range<ref_seq_type> &&
631 "The ref_seq object must be a std::ranges::forward_range " 632 "over letters that model seqan3::alphabet.");
634 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
636 static_assert((std::ranges::forward_range<ref_id_type> ||
639 "The ref_id object must be a std::ranges::forward_range " 640 "over letters that model seqan3::alphabet or an integral or a std::optional<integral>.");
644 "The align object must be a std::pair of two ranges whose " 645 "value_type is comparable to seqan3::gap");
650 "The align object must be a std::pair of two ranges whose " 651 "value_type is comparable to seqan3::gap");
653 static_assert((std::ranges::forward_range<qual_type> &&
655 "The qual object must be a std::ranges::forward_range " 656 "over letters that model seqan3::alphabet.");
659 "The mate object must be a std::tuple of size 3 with " 660 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, " 661 "2) a std::integral or std::optional<std::integral>, and " 662 "3) a std::integral.");
664 static_assert(((std::ranges::forward_range<decltype(std::get<0>(mate))> ||
670 "The mate object must be a std::tuple of size 3 with " 671 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, " 672 "2) a std::integral or std::optional<std::integral>, and " 673 "3) a std::integral.");
676 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
678 if constexpr (detail::decays_to_ignore_v<header_type>)
680 throw format_error{
"BAM can only be written with a header but you did not provide enough information! " 681 "You can either construct the output file with ref_ids and ref_seqs information and " 682 "the header will be created for you, or you can access the `header` member directly."};
690 if (ref_offset.has_value() && (ref_offset.value() + 1) < 0)
691 throw format_error{detail::to_string(
"The ref_offset object must be >= -1 but is: ", ref_offset)};
698 if (!header_was_written)
702 write_header(os, options, header);
703 int32_t l_text{
static_cast<int32_t
>(os.
str().size())};
704 std::ranges::copy_n(reinterpret_cast<char *>(&l_text), 4, stream_it);
708 int32_t n_ref{
static_cast<int32_t
>(header.
ref_ids().size())};
709 std::ranges::copy_n(reinterpret_cast<char *>(&n_ref), 4, stream_it);
711 for (int32_t ridx = 0; ridx < n_ref; ++ridx)
713 int32_t l_name{
static_cast<int32_t
>(header.
ref_ids()[ridx].size()) + 1};
714 std::ranges::copy_n(reinterpret_cast<char *>(&l_name), 4, stream_it);
716 std::ranges::copy(header.
ref_ids()[ridx].begin(), header.
ref_ids()[ridx].end(), stream_it);
719 std::ranges::copy_n(reinterpret_cast<char *>(&get<0>(header.
ref_id_info[ridx])), 4, stream_it);
722 header_was_written =
true;
728 int32_t ref_length{};
732 if (!std::ranges::empty(get<0>(align)) && !std::ranges::empty(get<1>(align)))
734 ref_length = std::ranges::distance(get<1>(align));
740 int32_t off_end{
static_cast<int32_t
>(std::ranges::distance(seq)) - offset};
742 for (
auto chr : get<1>(align))
746 off_end -= ref_length;
747 cigar_vector = detail::get_cigar_vector(align, offset, off_end);
751 int32_t dummy_seq_length{};
752 for (
auto & [
count, operation] : cigar_vector)
753 update_alignment_lengths(ref_length, dummy_seq_length, operation.to_char(),
count);
756 if (cigar_vector.size() >= (1 << 16))
758 tag_dict[
"CG"_tag] = detail::get_cigar_string(cigar_vector);
759 cigar_vector.resize(2);
760 cigar_vector[0] =
cigar{
static_cast<uint32_t
>(std::ranges::distance(seq)),
'S'_cigar_op};
761 cigar_vector[1] =
cigar{
static_cast<uint32_t
>(std::ranges::distance(get<1>(align))),
'N'_cigar_op};
764 std::string tag_dict_binary_str = get_tag_dict_str(tag_dict);
771 uint8_t read_name_size = std::min<uint8_t>(std::ranges::distance(
id), 254) + 1;
772 read_name_size +=
static_cast<uint8_t
>(read_name_size == 1);
774 alignment_record_core core
778 ref_offset.value_or(-1),
781 reg2bin(ref_offset.value_or(-1), ref_length),
782 static_cast<uint16_t>(cigar_vector.size()),
784 static_cast<int32_t>(std::ranges::distance(seq)),
786 get<1>(mate).value_or(-1),
790 auto check_and_assign_id_to = [&header] ([[maybe_unused]]
auto & id_source,
791 [[maybe_unused]]
auto & id_target)
795 if constexpr (!detail::decays_to_ignore_v<id_t>)
799 id_target = id_source;
801 else if constexpr (detail::is_type_specialisation_of_v<id_t, std::optional>)
803 id_target = id_source.value_or(-1);
807 if (!std::ranges::empty(id_source))
811 if constexpr (std::ranges::contiguous_range<decltype(id_source)> &&
812 std::ranges::sized_range<decltype(id_source)> &&
815 id_it = header.
ref_dict.find(std::span{std::ranges::data(id_source),
823 "The ref_id type is not convertible to the reference id information stored in the " 824 "reference dictionary of the header object.");
826 id_it = header.
ref_dict.find(id_source);
831 throw format_error{detail::to_string(
"Unknown reference name '", id_source,
"' could " 832 "not be found in BAM header ref_dict: ",
836 id_target = id_it->second;
843 check_and_assign_id_to(ref_id, core.refID);
846 check_and_assign_id_to(get<0>(mate), core.next_refID);
849 core.block_size =
sizeof(core) - 4 +
851 core.n_cigar_op * 4 +
852 (core.l_seq + 1) / 2 +
854 tag_dict_binary_str.
size();
856 std::ranges::copy_n(reinterpret_cast<char *>(&core),
sizeof(core), stream_it);
858 if (std::ranges::empty(
id))
861 std::ranges::copy_n(std::ranges::begin(
id), core.l_read_name - 1, stream_it);
865 for (
auto [cigar_count, op] : cigar_vector)
867 cigar_count = cigar_count << 4;
868 cigar_count |=
static_cast<int32_t
>(char_to_sam_rank[op.to_char()]);
869 std::ranges::copy_n(reinterpret_cast<char *>(&cigar_count), 4, stream_it);
874 constexpr
auto to_dna16 = detail::convert_through_char_representation<sam_dna16, alph_t>;
876 auto sit = std::ranges::begin(seq);
877 for (int32_t sidx = 0; sidx < ((core.l_seq & 1) ? core.l_seq - 1 : core.l_seq); ++sidx, ++sit)
882 stream_it =
static_cast<char>(compressed_chr);
886 stream_it =
static_cast<char>(
to_rank(to_dna16[
to_rank(*sit)]) << 4);
889 if (std::ranges::empty(qual))
892 std::ranges::copy_n(v.begin(), core.l_seq, stream_it);
896 if (std::ranges::distance(qual) != core.l_seq)
897 throw format_error{detail::to_string(
"Expected quality of same length as sequence with size ",
898 core.l_seq,
". Got quality with size ",
899 std::ranges::distance(qual),
" instead.")};
902 std::ranges::copy_n(v.begin(), core.l_seq, stream_it);
906 stream << tag_dict_binary_str;
911 template <
typename stream_view_type,
typename value_type>
913 stream_view_type && stream_view,
914 value_type const & SEQAN3_DOXYGEN_ONLY(value))
917 read_field(stream_view, count);
924 read_field(stream_view, tmp);
948 template <
typename stream_view_type>
949 inline void format_bam::read_field(stream_view_type && stream_view,
sam_tag_dictionary & target)
957 uint16_t tag =
static_cast<uint16_t
>(*std::ranges::begin(stream_view)) << 8;
958 std::ranges::next(std::ranges::begin(stream_view));
959 tag +=
static_cast<uint16_t
>(*std::ranges::begin(stream_view));
960 std::ranges::next(std::ranges::begin(stream_view));
961 char type_id =
static_cast<char>(*std::ranges::begin(stream_view));
962 std::ranges::next(std::ranges::begin(stream_view));
968 target[tag] =
static_cast<char>(*std::ranges::begin(stream_view));
969 std::ranges::next(std::ranges::begin(stream_view));
976 read_field(stream_view, tmp);
977 target[tag] =
static_cast<int32_t
>(tmp);
983 read_field(stream_view, tmp);
984 target[tag] =
static_cast<int32_t
>(tmp);
990 read_field(stream_view, tmp);
991 target[tag] =
static_cast<int32_t
>(tmp);
997 read_field(stream_view, tmp);
998 target[tag] =
static_cast<int32_t
>(tmp);
1004 read_field(stream_view, tmp);
1011 read_field(stream_view, tmp);
1012 target[tag] =
static_cast<int32_t
>(tmp);
1018 read_field(stream_view, tmp);
1024 string_buffer.clear();
1025 while (!is_char<'\0'>(*std::ranges::begin(stream_view)))
1027 string_buffer.push_back(*std::ranges::begin(stream_view));
1028 std::ranges::next(std::ranges::begin(stream_view));
1030 std::ranges::next(std::ranges::begin(stream_view));
1031 target[tag] = string_buffer;
1041 char array_value_type_id = *std::ranges::begin(stream_view);
1042 std::ranges::next(std::ranges::begin(stream_view));
1044 switch (array_value_type_id)
1047 read_sam_dict_vector(target[tag], stream_view, int8_t{});
1050 read_sam_dict_vector(target[tag], stream_view, uint8_t{});
1053 read_sam_dict_vector(target[tag], stream_view, int16_t{});
1056 read_sam_dict_vector(target[tag], stream_view, uint16_t{});
1059 read_sam_dict_vector(target[tag], stream_view, int32_t{});
1062 read_sam_dict_vector(target[tag], stream_view, uint32_t{});
1065 read_sam_dict_vector(target[tag], stream_view,
float{});
1068 throw format_error{detail::to_string(
"The first character in the numerical id of a SAM tag ",
1069 "must be one of [cCsSiIf] but '", array_value_type_id,
"' was given.")};
1074 throw format_error{detail::to_string(
"The second character in the numerical id of a " 1075 "SAM tag must be one of [A,i,Z,H,B,f] but '", type_id,
"' was given.")};
1093 template <
typename cigar_input_type>
1094 inline auto format_bam::parse_binary_cigar(cigar_input_type && cigar_input, uint16_t n_cigar_op)
const 1097 char operation{
'\0'};
1099 int32_t ref_length{}, seq_length{};
1100 uint32_t operation_and_count{};
1101 constexpr
char const * cigar_mapping =
"MIDNSHP=X*******";
1102 constexpr uint32_t cigar_mask = 0x0f;
1104 if (n_cigar_op == 0)
1105 return std::tuple{operations, ref_length, seq_length};
1109 while (n_cigar_op > 0)
1111 std::ranges::copy_n(std::ranges::begin(cigar_input),
1112 sizeof(operation_and_count),
1113 reinterpret_cast<char*>(&operation_and_count));
1114 operation = cigar_mapping[operation_and_count & cigar_mask];
1115 count = operation_and_count >> 4;
1117 update_alignment_lengths(ref_length, seq_length, operation,
count);
1122 return std::tuple{operations, ref_length, seq_length};
1132 auto stream_variant_fn = [&result] (
auto && arg)
1140 bool negative = arg < 0;
1141 auto n = __builtin_ctz(detail::next_power_of_two(((negative) ? arg * -1 : arg) + 1) >> 1) / 8;
1142 n = n * n + 2 * negative;
1148 result[result.size() - 1] =
'C';
1149 result.append(reinterpret_cast<char const *>(&arg), 1);
1154 result[result.size() - 1] =
'S';
1155 result.append(reinterpret_cast<char const *>(&arg), 2);
1160 result[result.size() - 1] =
'c';
1161 int8_t tmp =
static_cast<int8_t
>(arg);
1162 result.append(reinterpret_cast<char const *>(&tmp), 1);
1167 result[result.size() - 1] =
's';
1168 int16_t tmp =
static_cast<int16_t
>(arg);
1169 result.append(reinterpret_cast<char const *>(&tmp), 2);
1174 result.append(reinterpret_cast<char const *>(&arg), 4);
1181 result.append(reinterpret_cast<char const *>(arg.data()), arg.size() + 1);
1183 else if constexpr (!std::ranges::range<T>)
1185 result.append(reinterpret_cast<char const *>(&arg),
sizeof(arg));
1189 int32_t sz{
static_cast<int32_t
>(arg.size())};
1190 result.append(reinterpret_cast<char *>(&sz), 4);
1191 result.append(reinterpret_cast<char const *>(arg.data()), arg.size() *
sizeof(
value_type_t<T>));
1195 for (
auto & [tag, variant] : tag_dict)
1197 result.push_back(static_cast<char>(tag / 256));
1198 result.push_back(static_cast<char>(tag % 256));
1200 result.push_back(detail::sam_tag_type_char[variant.
index()]);
1202 if (!is_char<'\0'>(detail::sam_tag_type_char_extra[variant.
index()]))
1203 result.push_back(detail::sam_tag_type_char_extra[variant.
index()]);
Provides concepts for core language types and relations that don't have concepts in C++20 (yet)...
auto constexpr take_exactly_or_throw
A view adaptor that returns the first size elements from the underlying range and also exposes size i...
Definition: take_exactly.hpp:91
Resolves to std::ranges::implicitly_convertible_to<type1, type2>().
void assign_unaligned(aligned_seq_t &aligned_seq, unaligned_sequence_type &&unaligned_seq)
An implementation of seqan3::aligned_sequence::assign_unaligned_sequence for sequence containers...
Definition: aligned_sequence_concept.hpp:375
typename value_type< t >::type value_type_t
Shortcut for seqan3::value_type (transformation_trait shortcut).
Definition: pre.hpp:48
Specifies a range whose iterators may outlive the range and remain valid.
Sequence (REF_SEQ) relative start position (0-based), unsigned value.
The alphabet of a gap character '-'.
Definition: gap.hpp:36
Provides the seqan3::sam_tag_dictionary class and auxiliaries.
The mate pair information given as a std::tuple of reference name, offset and template length...
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:142
::ranges::ostreambuf_iterator ostreambuf_iterator
Alias for ranges::ostreambuf_iterator. Writes successive characters onto the output stream from which...
Definition: iterator.hpp:204
Provides seqan3::detail::ignore_output_iterator for writing to null stream.
Provides seqan3::type_list and auxiliary type traits.
seqan3::type_list< trait_t< pack_t >... > transform
Apply a transformation trait to every type in the pack and return a seqan3::type_list of the results...
Definition: traits.hpp:307
The main SeqAn3 namespace.
Auxiliary for pretty printing of exception messages.
The "sequence", usually a range of nucleotides or amino acids.
Auxiliary functions for the alignment IO.
The alignment flag (bit information), uint16_t value.
Provides seqan3::alignment_file_output_options.
The qualities, usually in phred-score notation.
detail::search_mode_all constexpr all
Configuration element to receive all hits within the error bounds.
Definition: mode.hpp:43
Whether a type behaves like a tuple.
constexpr derived_type & assign_rank(rank_type const c) noexcept
Assign from a numeric value.
Definition: alphabet_base.hpp:165
The concept integral is satisfied if and only if T is an integral type.
Provides seqan3::sam_dna16.
Provides seqan3::views::take_until and seqan3::views::take_until_or_throw.
Provides seqan3::tuple_like.
Provides various utility functions.
Provides various utility functions.
Adaptations of concepts from the Ranges TS.
Requires seqan3::detail::weakly_equality_comparable_witht<t1,t2>, but also that t1 and t2...
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:116
A 16 letter DNA alphabet, containing all IUPAC symbols minus the gap and plus an equality sign ('=')...
Definition: sam_dna16.hpp:45
The options type defines various option members that influence the behavior of all or some formats...
Definition: output_options.hpp:22
The cigar semialphabet pairs a counter with a seqan3::cigar_op letter.
Definition: cigar.hpp:54
Sequence (SEQ) relative start position (0-based), unsigned value.
Provides character predicates for tokenisation.
The (extended) cigar operation alphabet of M,D,I,H,N,P,S,X,=.
Definition: cigar_op.hpp:52
The generic alphabet concept that covers most data types used in ranges.
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
Provides helper data structures for the seqan3::alignment_file_output.
The bit score (statistical significance indicator), unsigned value.
The (reference) "sequence" information, usually a range of nucleotides or amino acids.
Provides seqan3::views::slice.
Provides utility functions for bit twiddling.
Provides various transformation traits used by the range module.
typename reference< t >::type reference_t
Shortcut for seqan3::reference (transformation_trait shortcut).
Definition: pre.hpp:77
sam_flag
An enum flag that describes the properties of an aligned read (given as a SAM record).The SAM flag are bitwise flags, which means that each value corresponds to a specific bit that is set and that they can be combined and tested using binary operations. See this tutorial for an introduction on bitwise operations on enum flags.
Definition: misc.hpp:70
Exposes the value_type of another type.
Definition: pre.hpp:41
constexpr derived_type & assign_char(char_type const c) noexcept
Assign from a character, implicitly converts invalid characters.
Definition: alphabet_base.hpp:140
The concept std::same_as<T, U> is satisfied if and only if T and U denote the same type...
A more refined container concept than seqan3::container.
constexpr ptrdiff_t count
Count the occurrences of a type in a pack.
Definition: traits.hpp:134
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:141
The mapping quality of the SEQ alignment, usually a ohred-scaled score.
The identifier of the (reference) sequence that SEQ was aligned to.
Provides seqan3::views::take_exactly and seqan3::views::take_exactly_or_throw.
The SAM tag dictionary class that stores all optional SAM fields.
Definition: sam_tag_dictionary.hpp:324
constexpr auto repeat_n
A view factory that repeats a given value n times.
Definition: repeat_n.hpp:94