139 template <
typename stream_type,
140 typename seq_legal_alph_type,
141 typename stream_pos_type,
147 stream_pos_type & position_buffer,
150 qual_type & qualities);
152 template <
typename stream_type,
160 qual_type && qualities);
162 template <
typename stream_type,
163 typename seq_legal_alph_type,
164 typename ref_seqs_type,
165 typename ref_ids_type,
166 typename stream_pos_type,
169 typename offset_type,
170 typename ref_seq_type,
171 typename ref_id_type,
172 typename ref_offset_type,
179 typename tag_dict_type,
180 typename e_value_type,
181 typename bit_score_type>
184 ref_seqs_type & ref_seqs,
186 stream_pos_type & position_buffer,
190 offset_type & offset,
191 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
192 ref_id_type & ref_id,
193 ref_offset_type & ref_offset,
195 cigar_type & cigar_vector,
199 tag_dict_type & tag_dict,
200 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
201 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score));
203 template <
typename stream_type,
204 typename header_type,
207 typename ref_seq_type,
208 typename ref_id_type,
212 typename tag_dict_type,
213 typename e_value_type,
214 typename bit_score_type>
217 header_type && header,
221 int32_t
const offset,
222 ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
223 ref_id_type && ref_id,
230 tag_dict_type && tag_dict,
231 e_value_type && SEQAN3_DOXYGEN_ONLY(e_value),
232 bit_score_type && SEQAN3_DOXYGEN_ONLY(bit_score));
242 sam_file_header<> default_header{};
245 bool ref_info_present_in_header{
false};
254 template <
typename t>
255 decltype(
auto) default_or(t && v)
const noexcept
257 return std::forward<t>(v);
260 template <
typename stream_view_type, arithmetic value_type>
262 stream_view_type && stream_view,
265 template <
typename stream_view_type>
267 stream_view_type && stream_view);
269 template <
typename stream_view_type>
270 void read_sam_dict_field(stream_view_type && stream_view, sam_tag_dictionary & target);
272 template <
typename stream_it_t, std::ranges::forward_range field_type>
273 void write_range_or_asterisk(stream_it_t & stream_it, field_type && field_value);
275 template <
typename stream_it_t>
276 void write_range_or_asterisk(stream_it_t & stream_it,
char const *
const field_value);
278 template <
typename stream_it_t>
279 void write_tag_fields(stream_it_t & stream, sam_tag_dictionary
const & tag_dict,
char const separator);
283template <
typename stream_type,
284 typename seq_legal_alph_type,
285 typename stream_pos_type,
291 stream_pos_type & position_buffer,
294 qual_type & qualities)
300 id, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore,
301 std::ignore, std::ignore, std::ignore, std::ignore, std::ignore, std::ignore);
304 if constexpr (!detail::decays_to_ignore_v<seq_type>)
305 if (std::ranges::distance(
sequence) == 0)
306 throw parse_error{
"The sequence information must not be empty."};
307 if constexpr (!detail::decays_to_ignore_v<id_type>)
308 if (std::ranges::distance(
id) == 0)
309 throw parse_error{
"The id information must not be empty."};
312 id =
id | detail::take_until_and_consume(
is_space) | views::to<id_type>;
316template <
typename stream_type,
324 qual_type && qualities)
335 default_or(qualities),
352template <
typename stream_type,
353 typename seq_legal_alph_type,
354 typename ref_seqs_type,
355 typename ref_ids_type,
356 typename stream_pos_type,
359 typename offset_type,
360 typename ref_seq_type,
361 typename ref_id_type,
362 typename ref_offset_type,
369 typename tag_dict_type,
370 typename e_value_type,
371 typename bit_score_type>
374 ref_seqs_type & ref_seqs,
376 stream_pos_type & position_buffer,
380 offset_type & offset,
381 ref_seq_type & SEQAN3_DOXYGEN_ONLY(ref_seq),
382 ref_id_type & ref_id,
383 ref_offset_type & ref_offset,
385 cigar_type & cigar_vector,
389 tag_dict_type & tag_dict,
390 e_value_type & SEQAN3_DOXYGEN_ONLY(e_value),
391 bit_score_type & SEQAN3_DOXYGEN_ONLY(bit_score))
393 static_assert(detail::decays_to_ignore_v<ref_offset_type> ||
394 detail::is_type_specialisation_of_v<ref_offset_type, std::optional>,
395 "The ref_offset must be a specialisation of std::optional.");
397 auto stream_view = detail::istreambuf(stream);
398 auto field_view = stream_view | detail::take_until_or_throw_and_consume(is_char<'\t'>);
401 int32_t ref_offset_tmp{};
402 std::ranges::range_value_t<
decltype(header.
ref_ids())> ref_id_tmp{};
403 [[maybe_unused]] int32_t offset_tmp{};
404 [[maybe_unused]] int32_t soft_clipping_end{};
406 [[maybe_unused]] int32_t ref_length{0}, seq_length{0};
410 if (is_char<'@'>(*std::ranges::begin(stream_view)))
412 read_header(stream_view, header, ref_seqs);
414 if (std::ranges::begin(stream_view) == std::ranges::end(stream_view))
419 position_buffer = stream.tellg();
423 if constexpr (!detail::decays_to_ignore_v<id_type>)
424 read_forward_range_field(field_view,
id);
426 detail::consume(field_view);
428 uint16_t flag_integral{};
429 read_arithmetic_field(field_view, flag_integral);
432 read_forward_range_field(field_view, ref_id_tmp);
433 check_and_assign_ref_id(
ref_id, ref_id_tmp, header, ref_seqs);
435 read_arithmetic_field(field_view, ref_offset_tmp);
438 if (ref_offset_tmp == -1)
440 else if (ref_offset_tmp > -1)
442 else if (ref_offset_tmp < -1)
443 throw format_error{
"No negative values are allowed for field::ref_offset."};
445 if constexpr (!detail::decays_to_ignore_v<mapq_type>)
446 read_arithmetic_field(field_view,
mapq);
448 detail::consume(field_view);
452 if constexpr (!detail::decays_to_ignore_v<align_type> || !detail::decays_to_ignore_v<cigar_type>)
454 if (!is_char<'*'>(*std::ranges::begin(stream_view)))
456 std::tie(tmp_cigar_vector, ref_length, seq_length) = detail::parse_cigar(field_view);
457 transfer_soft_clipping_to(tmp_cigar_vector, offset_tmp, soft_clipping_end);
462 ++std::ranges::begin(field_view);
467 detail::consume(field_view);
474 if constexpr (!detail::decays_to_ignore_v<mate_type>)
476 std::ranges::range_value_t<
decltype(header.
ref_ids())> tmp_mate_ref_id{};
477 read_forward_range_field(field_view, tmp_mate_ref_id);
479 if (tmp_mate_ref_id ==
"=")
481 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
484 check_and_assign_ref_id(get<0>(
mate), ref_id_tmp, header, ref_seqs);
488 check_and_assign_ref_id(get<0>(
mate), tmp_mate_ref_id, header, ref_seqs);
492 read_arithmetic_field(field_view, tmp_pnext);
495 get<1>(
mate) = --tmp_pnext;
496 else if (tmp_pnext < 0)
497 throw format_error{
"No negative values are allowed at the mate mapping position."};
500 read_arithmetic_field(field_view, get<2>(
mate));
504 for (
size_t i = 0; i < 3u; ++i)
506 detail::consume(field_view);
512 if (!is_char<'*'>(*std::ranges::begin(stream_view)))
514 auto constexpr is_legal_alph = char_is_valid_for<seq_legal_alph_type>;
517 if (!is_legal_alph(c))
519 "char_is_valid_for<" +
520 detail::type_name_as_string<seq_legal_alph_type> +
521 "> evaluated to false on " +
522 detail::make_printable(c)};
526 if constexpr (detail::decays_to_ignore_v<seq_type>)
528 if constexpr (!detail::decays_to_ignore_v<align_type>)
531 "If you want to read ALIGNMENT but not SEQ, the alignment"
532 " object must store a sequence container at the second (query) position.");
534 if (!tmp_cigar_vector.empty())
537 auto tmp_iter = std::ranges::begin(seq_stream);
538 std::ranges::advance(tmp_iter, offset_tmp);
540 for (; seq_length > 0; --seq_length)
542 get<1>(align).push_back(std::ranges::range_value_t<
decltype(get<1>(align))>{}.assign_char(*tmp_iter));
546 std::ranges::advance(tmp_iter, soft_clipping_end);
555 detail::consume(seq_stream);
560 read_forward_range_field(seq_stream,
seq);
562 if constexpr (!detail::decays_to_ignore_v<align_type>)
564 if (!tmp_cigar_vector.empty())
566 assign_unaligned(get<1>(align),
575 ++std::ranges::begin(field_view);
580 auto const tab_or_end = is_char<'\t'> || is_char<'\r'> || is_char<'\n'>;
581 auto qual_view = stream_view | detail::take_until_or_throw(tab_or_end);
582 if constexpr (!detail::decays_to_ignore_v<qual_type>)
583 read_forward_range_field(qual_view,
qual);
585 detail::consume(qual_view);
587 if constexpr (!detail::decays_to_ignore_v<seq_type> && !detail::decays_to_ignore_v<qual_type>)
589 if (std::ranges::distance(
seq) != 0 && std::ranges::distance(
qual) != 0 &&
590 std::ranges::distance(
seq) != std::ranges::distance(
qual))
592 throw format_error{detail::to_string(
"Sequence length (", std::ranges::distance(
seq),
593 ") and quality length (", std::ranges::distance(
qual),
594 ") must be the same.")};
600 while (is_char<'\t'>(*std::ranges::begin(stream_view)))
602 ++std::ranges::begin(stream_view);
603 auto stream_until_tab_or_end = stream_view | detail::take_until_or_throw(tab_or_end);
604 if constexpr (!detail::decays_to_ignore_v<tag_dict_type>)
605 read_sam_dict_field(stream_until_tab_or_end, tag_dict);
607 detail::consume(stream_until_tab_or_end);
610 detail::consume(stream_view | detail::take_until(!(is_char<'\r'> || is_char<'\n'>)));
616 if constexpr (!detail::decays_to_ignore_v<align_type>)
618 int32_t ref_idx{(ref_id_tmp.empty()) ? -1 : 0};
620 if constexpr (!detail::decays_to_ignore_v<ref_seqs_type>)
622 if (!ref_id_tmp.empty())
624 assert(header.
ref_dict.count(ref_id_tmp) != 0);
625 ref_idx = header.
ref_dict[ref_id_tmp];
629 construct_alignment(align, tmp_cigar_vector, ref_idx, ref_seqs, ref_offset_tmp, ref_length);
632 if constexpr (!detail::decays_to_ignore_v<cigar_type>)
633 std::swap(cigar_vector, tmp_cigar_vector);
637template <
typename stream_type,
638 typename header_type,
641 typename ref_seq_type,
642 typename ref_id_type,
646 typename tag_dict_type,
647 typename e_value_type,
648 typename bit_score_type>
651 header_type && header,
655 int32_t
const offset,
656 ref_seq_type && SEQAN3_DOXYGEN_ONLY(ref_seq),
657 ref_id_type && ref_id,
664 tag_dict_type && tag_dict,
665 e_value_type && SEQAN3_DOXYGEN_ONLY(e_value),
666 bit_score_type && SEQAN3_DOXYGEN_ONLY(bit_score))
684 static_assert((std::ranges::forward_range<seq_type> &&
686 "The seq object must be a std::ranges::forward_range over "
687 "letters that model seqan3::alphabet.");
689 static_assert((std::ranges::forward_range<id_type> &&
691 "The id object must be a std::ranges::forward_range over "
692 "letters that model seqan3::alphabet.");
694 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
696 static_assert((std::ranges::forward_range<ref_id_type> ||
697 std::integral<std::remove_reference_t<ref_id_type>> ||
698 detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>),
699 "The ref_id object must be a std::ranges::forward_range "
700 "over letters that model seqan3::alphabet.");
702 if constexpr (std::integral<std::remove_cvref_t<ref_id_type>> ||
703 detail::is_type_specialisation_of_v<std::remove_cvref_t<ref_id_type>,
std::optional>)
704 static_assert(!detail::decays_to_ignore_v<header_type>,
705 "If you give indices as reference id information the header must also be present.");
709 "The align object must be a std::pair of two ranges whose "
710 "value_type is comparable to seqan3::gap");
712 static_assert((std::tuple_size_v<std::remove_cvref_t<align_type>> == 2 &&
713 std::equality_comparable_with<gap, std::ranges::range_reference_t<decltype(std::get<0>(align))>> &&
714 std::equality_comparable_with<
gap, std::ranges::range_reference_t<
decltype(std::get<1>(align))>>),
715 "The align object must be a std::pair of two ranges whose "
716 "value_type is comparable to seqan3::gap");
718 static_assert((std::ranges::forward_range<qual_type> &&
720 "The qual object must be a std::ranges::forward_range "
721 "over letters that model seqan3::alphabet.");
724 "The mate object must be a std::tuple of size 3 with "
725 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
726 "2) a std::integral or std::optional<std::integral>, and "
727 "3) a std::integral.");
729 static_assert(((std::ranges::forward_range<decltype(std::get<0>(
mate))> ||
732 (std::integral<std::remove_cvref_t<decltype(std::get<1>(
mate))>> ||
734 std::integral<std::remove_cvref_t<decltype(std::get<2>(
mate))>>),
735 "The mate object must be a std::tuple of size 3 with "
736 "1) a std::ranges::forward_range with a value_type modelling seqan3::alphabet, "
737 "2) a std::integral or std::optional<std::integral>, and "
738 "3) a std::integral.");
740 if constexpr (std::integral<std::remove_cvref_t<decltype(std::get<0>(
mate))>> ||
742 static_assert(!detail::decays_to_ignore_v<header_type>,
743 "If you give indices as mate reference id information the header must also be present.");
746 "The tag_dict object must be of type seqan3::sam_tag_dictionary.");
751 if constexpr (!detail::decays_to_ignore_v<header_type> &&
752 !detail::decays_to_ignore_v<ref_id_type> &&
753 !std::integral<std::remove_reference_t<ref_id_type>> &&
754 !detail::is_type_specialisation_of_v<std::remove_reference_t<ref_id_type>,
std::optional>)
761 if constexpr (std::ranges::contiguous_range<
decltype(
ref_id)> &&
762 std::ranges::sized_range<
decltype(
ref_id)> &&
763 std::ranges::borrowed_range<
decltype(
ref_id)>)
772 "The ref_id type is not convertible to the reference id information stored in the "
773 "reference dictionary of the header object.");
779 throw format_error{detail::to_string(
"The ref_id '",
ref_id,
"' was not in the list of references:",
785 throw format_error{
"The ref_offset object must be a std::integral >= 0."};
790 if constexpr (!detail::decays_to_ignore_v<header_type>)
794 write_header(stream, options, header);
795 header_was_written =
true;
803 detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
804 constexpr char separator{
'\t'};
806 write_range_or_asterisk(stream_it,
id);
807 *stream_it = separator;
809 stream_it.write_number(
static_cast<uint16_t
>(
flag));
810 *stream_it = separator;
812 if constexpr (!detail::decays_to_ignore_v<ref_id_type>)
814 if constexpr (std::integral<std::remove_reference_t<ref_id_type>>)
816 write_range_or_asterisk(stream_it, (header.
ref_ids())[
ref_id]);
818 else if constexpr (detail::is_type_specialisation_of_v<std::remove_reference_t<ref_id_type>,
std::optional>)
821 write_range_or_asterisk(stream_it, (header.
ref_ids())[
ref_id.value()]);
827 write_range_or_asterisk(stream_it,
ref_id);
835 *stream_it = separator;
838 stream_it.write_number(
ref_offset.value_or(-1) + 1);
839 *stream_it = separator;
841 stream_it.write_number(
static_cast<unsigned>(
mapq));
842 *stream_it = separator;
844 if (!std::ranges::empty(cigar_vector))
846 for (
auto & c : cigar_vector)
847 stream_it.write_range(c.to_string());
849 else if (!std::ranges::empty(get<0>(align)) && !std::ranges::empty(get<1>(align)))
856 for (
auto chr : get<1>(align))
864 write_range_or_asterisk(stream_it, detail::get_cigar_string(align,
offset, off_end));
871 *stream_it = separator;
873 if constexpr (std::integral<std::remove_reference_t<decltype(get<0>(
mate))>>)
875 write_range_or_asterisk(stream_it, (header.
ref_ids())[get<0>(
mate)]);
877 else if constexpr (detail::is_type_specialisation_of_v<std::remove_reference_t<decltype(get<0>(
mate))>,
std::optional>)
879 if (get<0>(
mate).has_value())
880 write_range_or_asterisk(stream_it, header.
ref_ids()[get<0>(
mate).value()]);
886 write_range_or_asterisk(stream_it, get<0>(
mate));
889 *stream_it = separator;
891 if constexpr (detail::is_type_specialisation_of_v<std::remove_cvref_t<decltype(get<1>(
mate))>,
std::optional>)
894 stream_it.write_number(get<1>(
mate).value_or(-1) + 1);
895 *stream_it = separator;
899 stream_it.write_number(get<1>(
mate));
900 *stream_it = separator;
903 stream_it.write_number(get<2>(
mate));
904 *stream_it = separator;
906 write_range_or_asterisk(stream_it,
seq);
907 *stream_it = separator;
909 write_range_or_asterisk(stream_it,
qual);
911 write_tag_fields(stream_it, tag_dict, separator);
934template <
typename stream_view_type, arithmetic value_type>
936 stream_view_type && stream_view,
940 while (std::ranges::begin(stream_view) != ranges::end(stream_view))
942 read_arithmetic_field(stream_view | detail::take_until(is_char<','>), value);
945 if (is_char<','>(*std::ranges::begin(stream_view)))
946 ++std::ranges::begin(stream_view);
948 variant = std::move(tmp_vector);
964template <
typename stream_view_type>
966 stream_view_type && stream_view)
971 while (std::ranges::begin(stream_view) != ranges::end(stream_view))
975 read_byte_field(stream_view | detail::take_exactly_or_throw(2), value);
979 throw format_error{
"Hexadecimal tag has an uneven number of digits!"};
985 variant = std::move(tmp_vector);
1005template <
typename stream_view_type>
1006inline void format_sam::read_sam_dict_field(stream_view_type && stream_view, sam_tag_dictionary & target)
1033 read_arithmetic_field(stream_view, tmp);
1040 read_arithmetic_field(stream_view, tmp);
1046 target[tag] = stream_view | views::to<std::string>;
1051 read_sam_byte_vector(target[tag], stream_view);
1060 switch (array_value_type_id)
1063 read_sam_dict_vector(target[tag], stream_view, int8_t{});
1066 read_sam_dict_vector(target[tag], stream_view, uint8_t{});
1069 read_sam_dict_vector(target[tag], stream_view, int16_t{});
1072 read_sam_dict_vector(target[tag], stream_view, uint16_t{});
1075 read_sam_dict_vector(target[tag], stream_view, int32_t{});
1078 read_sam_dict_vector(target[tag], stream_view, uint32_t{});
1081 read_sam_dict_vector(target[tag], stream_view,
float{});
1084 throw format_error{
std::string(
"The first character in the numerical ") +
1085 "id of a SAM tag must be one of [cCsSiIf] but '" + array_value_type_id +
1091 throw format_error{
std::string(
"The second character in the numerical id of a "
1092 "SAM tag must be one of [A,i,Z,H,B,f] but '") + type_id +
"' was given."};
1103template <
typename stream_it_t, std::ranges::forward_range field_type>
1104inline void format_sam::write_range_or_asterisk(stream_it_t & stream_it, field_type && field_value)
1106 if (std::ranges::empty(field_value))
1112 if constexpr (std::same_as<std::remove_cvref_t<std::ranges::range_reference_t<field_type>>,
char>)
1113 stream_it.write_range(field_value);
1125template <
typename stream_it_t>
1126inline void format_sam::write_range_or_asterisk(stream_it_t & stream_it,
char const *
const field_value)
1138template <
typename stream_it_t>
1139inline void format_sam::write_tag_fields(stream_it_t & stream_it, sam_tag_dictionary
const & tag_dict,
char const separator)
1141 auto const stream_variant_fn = [&stream_it] (
auto && arg)
1145 if constexpr (std::ranges::input_range<T>)
1147 if constexpr (std::same_as<std::remove_cvref_t<std::ranges::range_reference_t<T>>,
char>)
1149 stream_it.write_range(arg);
1151 else if constexpr (std::same_as<std::remove_cvref_t<std::ranges::range_reference_t<T>>,
std::byte>)
1153 if (!std::ranges::empty(arg))
1155 stream_it.write_number(std::to_integer<uint8_t>(*std::ranges::begin(arg)));
1160 stream_it.write_number(std::to_integer<uint8_t>(elem));
1166 if (!std::ranges::empty(arg))
1168 stream_it.write_number(*std::ranges::begin(arg));
1173 stream_it.write_number(elem);
1178 else if constexpr (std::same_as<std::remove_cvref_t<T>,
char>)
1184 stream_it.write_number(arg);
1188 for (
auto & [tag, variant] : tag_dict)
1190 *stream_it = separator;
1192 char const char0 = tag / 256;
1193 char const char1 = tag % 256;
1198 *stream_it = detail::sam_tag_type_char[variant.
index()];
1201 if (detail::sam_tag_type_char_extra[variant.
index()] !=
'\0')
1203 *stream_it = detail::sam_tag_type_char_extra[variant.
index()];
Core alphabet concept and free function/type trait wrappers.
The alphabet of a gap character '-'.
Definition: gap.hpp:39
The SAM tag dictionary class that stores all optional SAM fields.
Definition: sam_tag_dictionary.hpp:337
Provides seqan3::detail::fast_ostreambuf_iterator.
auto const to_char
A view that calls seqan3::to_char() on each element in the input range.
Definition: to_char.hpp:63
sam_flag
An enum flag that describes the properties of an aligned read (given as a SAM record).
Definition: sam_flag.hpp:76
@ none
None of the flags below are set.
@ flag
The alignment flag (bit information), uint16_t value.
@ ref_offset
Sequence (seqan3::field::ref_seq) relative start position (0-based), unsigned value.
@ mapq
The mapping quality of the seqan3::field::seq alignment, usually a Phred-scaled score.
@ offset
Sequence (seqan3::field::seq) relative start position (0-based), 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.
@ seq
The "sequence", usually a range of nucleotides or amino acids.
@ qual
The qualities, usually in Phred score notation.
constexpr auto is_space
Checks whether c is a space character.
Definition: predicate.hpp:128
typename decltype(detail::split_after< i >(list_t{}))::second_type drop
Return a seqan3::type_list of the types in the input type list, except the first n.
Definition: traits.hpp:412
decltype(detail::transform< trait_t >(list_t{})) transform
Apply a transformation trait to every type in the list and return a seqan3::type_list of the results.
Definition: traits.hpp:495
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:183
The generic alphabet concept that covers most data types used in ranges.
Resolves to std::ranges::implicitly_convertible_to<type1, type2>().
A more refined container concept than seqan3::container.
The generic concept for a (biological) sequence.
Whether a type behaves like a tuple.
Auxiliary functions for the alignment IO.
Provides seqan3::detail::istreambuf.
The main SeqAn3 namespace.
Definition: cleanup.hpp:4
The <ranges> header from C++20's standard library.
Provides seqan3::sam_file_output_options.
Provides helper data structures for the seqan3::sam_file_output.
Provides the seqan3::sam_tag_dictionary class and auxiliaries.
Provides seqan3::sequence_file_output_options.
Provides seqan3::views::slice.
Thrown if there is a parse error, such as reading an unexpected character from an input stream.
Definition: exception.hpp:48
The options type defines various option members that influence the behavior of all or some formats.
Definition: output_options.hpp:26
bool add_carriage_return
The default plain text line-ending is "\n", but on Windows an additional carriage return is recommend...
Definition: output_options.hpp:30
bool sam_require_header
Whether to require a header for SAM files.
Definition: output_options.hpp:44
The options type defines various option members that influence the behaviour of all or some formats.
Definition: output_options.hpp:26
Provides seqan3::views::take_until and seqan3::views::take_until_or_throw.
Provides seqan3::views::to.
Provides seqan3::views::to_char.
Provides traits to inspect some information of a type, for example its name.
Provides seqan3::tuple_like.