77 typename ref_offset_type,
106 typename header_type,
110 typename ref_id_type,
133 template <
typename stream_t,
typename header_type>
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;
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>
212 template <std::
integral number_type>
223 template <
typename stream_view_type>
229 template <
typename value_type>
250 typename ref_id_type,
251 typename ref_offset_type,
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.");
324 if constexpr (detail::decays_to_ignore_v<ref_seqs_type>)
329 auto & reference_ids = header.
ref_ids();
335 header.
ref_dict.emplace(reference_ids.back(), reference_ids.size() - 1);
346 +
"' found in BAM file header (header.ref_ids():",
356 " does not correspond to the position ",
358 " in the header (header.ref_ids():",
364 throw format_error{
"Provided reference has unequal length as specified in the header."};
376 position_buffer = stream.tellg();
384 if (core.
refID >=
static_cast<int32_t
>(header.
ref_ids().size()) || core.
refID < -1)
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>)
420 if constexpr (!detail::decays_to_ignore_v<id_type>)
427 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
434 if constexpr (!detail::decays_to_ignore_v<seq_type>)
443 using alph_t = std::ranges::range_value_t<
decltype(
seq)>;
444 constexpr auto from_dna16 = detail::convert_through_char_representation<dna16sam, alph_t>;
461 if constexpr (!detail::decays_to_ignore_v<qual_type>)
466 for (int32_t
i = 0;
i < core.
l_seq; ++
i)
474 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
479 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
488 if constexpr (detail::decays_to_ignore_v<tag_dict_type> | detail::decays_to_ignore_v<seq_type>)
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.")};
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 ",
518 typename header_type,
522 typename ref_id_type,
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 "
647 uint8_t
read_name_size = std::min<uint8_t>(std::ranges::distance(
id), 254) + 1;
658 static_cast<int32_t
>(std::ranges::distance(
seq)),
667 if constexpr (!detail::decays_to_ignore_v<id_t>)
669 if constexpr (std::integral<id_t>)
673 else if constexpr (detail::is_type_specialisation_of_v<id_t, std::optional>)
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)>)
696 "The ref_id type is not convertible to the reference id information stored in the "
697 "reference dictionary of the header object.");
707 "not be found in BAM header ref_dict: ",
725 core.block_size =
sizeof(core) - 4 + core.l_read_name + core.n_cigar_op * 4
727 (core.l_seq + 1) / 2 +
733 if (std::ranges::empty(
id))
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)
764 if (std::ranges::empty(
qual))
771 if (std::ranges::distance(
qual) != core.l_seq)
774 ". Got quality with size ",
775 std::ranges::distance(
qual),
779 | std::views::transform(
793template <
typename stream_t,
typename header_type>
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 "
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
826 assert(header.ref_ids().size() < (1ull << 32));
827 int32_t
const n_ref{
static_cast<int32_t
>(header.ref_ids().size())};
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};
862template <
typename value_type>
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");
934 target[
tag] =
static_cast<int32_t
>(
tmp);
948 uint16_t
tag =
static_cast<uint16_t
>(*it) << 8;
950 tag |=
static_cast<uint16_t
>(*it);
1013 target[
tag] = std::move(
v);
1024 if (str.
size() % 2 != 0)
1025 throw format_error{
"[CORRUPTED BAM FILE] Hexadecimal tag must have even number of digits."};
1034 if (
res.ec == std::errc::invalid_argument)
1038 if (
res.ec == std::errc::result_out_of_range)
1040 +
"' into type uint8_t would cause an overflow."};
1081 "must be one of [cCsSiIf] but '",
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',
'*',
'*',
'*',
'*',
'*',
'*',
'*'};
1110 char operation{
'\0'};
1140 if constexpr (std::same_as<T, int32_t>)
1153 result.append(
reinterpret_cast<char const *
>(&
arg), 1);
1159 result.append(
reinterpret_cast<char const *
>(&
arg), 2);
1165 int8_t
tmp =
static_cast<int8_t
>(
arg);
1166 result.append(
reinterpret_cast<char const *
>(&
tmp), 1);
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>));
1202 result.push_back(
static_cast<char>(
tag / 256));
1203 result.push_back(
static_cast<char>(
tag % 256));
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
Functionally the same as std::istreambuf_iterator, but faster.
Definition fast_istreambuf_iterator.hpp:37
Functionally the same as std::ostreambuf_iterator, but offers writing a range more efficiently.
Definition fast_ostreambuf_iterator.hpp:38
A 16 letter DNA alphabet, containing all IUPAC symbols minus the gap and plus an equality sign ('=').
Definition dna16sam.hpp:45
The actual implementation of seqan3::cigar::operation for documentation purposes only.
Definition cigar_operation.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
std::string get_cigar_string(std::vector< cigar > const &cigar_vector)
Transforms a vector of cigar elements into a string representation.
Definition io/sam_file/detail/cigar.hpp:118
constexpr char sam_tag_type_char_extra[12]
Each types SAM tag type extra char id. Index corresponds to the seqan3::detail::sam_tag_variant types...
Definition sam_tag_dictionary.hpp:42
void update_alignment_lengths(int32_t &ref_length, int32_t &seq_length, char const cigar_operation, uint32_t const cigar_count)
Updates the sequence lengths by cigar_count depending on the cigar operation op.
Definition io/sam_file/detail/cigar.hpp:48
constexpr char sam_tag_type_char[12]
Each SAM tag type char identifier. Index corresponds to the seqan3::detail::sam_tag_variant types.
Definition sam_tag_dictionary.hpp:39
constexpr std::vector< cigar > parse_cigar(std::string_view const cigar_str)
Parses a cigar string into a vector of operation-count pairs (e.g. (M, 3)).
Definition io/sam_file/detail/cigar.hpp:87
constexpr auto 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_view.hpp:588
constexpr auto istreambuf
A view factory that returns a view over the stream buffer of an input stream.
Definition istreambuf_view.hpp:104
@ 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 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.
std::string to_string(value_type &&... values)
Streams all parameters via the seqan3::debug_stream and returns a concatenated string.
Definition to_string.hpp:26
The main SeqAn3 namespace.
Definition aligned_sequence_concept.hpp:26
constexpr auto const & get(configuration< configs_t... > const &config) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition configuration.hpp:412
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.