107 template <
typename stream_type,
108 typename legal_alph_type,
bool seq_qual_combined,
116 qual_type & SEQAN3_DOXYGEN_ONLY(qualities))
121 read_id(stream_view, options,
id);
124 read_seq(stream_view, options,
sequence);
128 template <
typename stream_type,
136 qual_type && SEQAN3_DOXYGEN_ONLY(qualities))
138 seqan3::detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};
141 if constexpr (detail::decays_to_ignore_v<id_type>)
143 throw std::logic_error{
"The ID field may not be set to ignore when writing FASTA files."};
147 if (std::ranges::empty(
id))
150 write_id(stream_it, options,
id);
154 if constexpr (detail::decays_to_ignore_v<seq_type>)
156 throw std::logic_error{
"The SEQ and SEQ_QUAL fields may not both be set to ignore when writing FASTA files."};
163 write_seq(stream_it, options,
sequence);
170 template <
typename stream_view_t,
171 typename seq_legal_alph_type,
bool seq_qual_combined,
173 void read_id(stream_view_t & stream_view,
177 auto const is_id = is_char<'>
'> || is_char<';
'>;
179 if (!is_id(*begin(stream_view)))
180 throw parse_error{std::string{"Expected to be on beginning of ID, but "} + is_id.msg +
181 " evaluated to false on " + detail::make_printable(*begin(stream_view))};
184 if constexpr (!detail::decays_to_ignore_v<id_type>)
186 if (options.truncate_ids)
188 #if SEQAN3_WORKAROUND_VIEW_PERFORMANCE
189 auto it = stream_view.begin();
190 auto e = stream_view.end();
191 for (; (it != e) && (is_id || is_blank)(*it); ++it)
194 bool at_delimiter = false;
195 for (; it != e; ++it)
197 if ((is_cntrl || is_blank)(*it))
202 id.push_back(assign_char_to(*it, std::ranges::range_value_t<id_type>{}));
206 throw unexpected_end_of_input{"FastA ID line did not end in newline."};
208 for (; (it != e) && ((!is_char<'\n
'>)(*it)); ++it)
211 #else // ↑↑↑ WORKAROUND | ORIGINAL ↓↓↓
213 std::ranges::copy(stream_view | std::views::drop_while(is_id || is_blank) // skip leading >
214 | views::take_until_or_throw(is_cntrl || is_blank) // read ID until delimiter…
215 | views::char_to<std::ranges::range_value_t<id_type>>,
216 std::cpp20::back_inserter(id)); // … ^A is old delimiter
218 // consume rest of line
219 detail::consume(stream_view | views::take_line_or_throw);
220 #endif // SEQAN3_WORKAROUND_VIEW_PERFORMANCE
225 #if SEQAN3_WORKAROUND_VIEW_PERFORMANCE
226 auto it = stream_view.begin();
227 auto e = stream_view.end();
228 for (; (it != e) && (is_id || is_blank)(*it); ++it)
231 bool at_delimiter = false;
232 for (; it != e; ++it)
234 if ((is_char<'\n
'>)(*it))
239 id.push_back(assign_char_to(*it, std::ranges::range_value_t<id_type>{}));
243 throw unexpected_end_of_input{"FastA ID line did not end in newline."};
245 #else // ↑↑↑ WORKAROUND | ORIGINAL ↓↓↓
247 std::ranges::copy(stream_view | views::take_line_or_throw // read line
248 | std::views::drop_while(is_id || is_blank) // skip leading >
249 | views::char_to<std::ranges::range_value_t<id_type>>,
250 std::cpp20::back_inserter(id));
251 #endif // SEQAN3_WORKAROUND_VIEW_PERFORMANCE
256 detail::consume(stream_view | views::take_line_or_throw);
261 template <typename stream_view_t,
262 typename seq_legal_alph_type, bool seq_qual_combined,
264 void read_seq(stream_view_t & stream_view,
265 sequence_file_input_options<seq_legal_alph_type, seq_qual_combined> const &,
268 auto constexpr is_id = is_char<'>
'> || is_char<';
'>;
270 if constexpr (!detail::decays_to_ignore_v<seq_type>)
272 auto constexpr not_in_alph = !is_in_alphabet<seq_legal_alph_type>;
274 #if SEQAN3_WORKAROUND_VIEW_PERFORMANCE
275 auto it = stream_view.begin();
276 auto e = stream_view.end();
277 for (; (it != e) && ((!is_id)(*it)); ++it)
279 if ((is_space || is_digit)(*it))
281 else if (not_in_alph(*it))
283 throw parse_error{std::string{"Encountered an unexpected letter: "} +
285 " evaluated to true on " +
286 detail::make_printable(*it)};
289 seq.push_back(assign_char_to(*it, std::ranges::range_value_t<seq_type>{}));
292 #else // ↑↑↑ WORKAROUND | ORIGINAL ↓↓↓
294 std::ranges::copy(stream_view | views::take_until(is_id) // until next header (or end)
295 | std::views::filter(!(is_space || is_digit))// ignore whitespace and numbers
296 | std::views::transform([not_in_alph] (char const c)
300 throw parse_error{std::string{"Encountered an unexpected letter: "} +
302 " evaluated to false on " +
303 detail::make_printable(c)};
306 }) // enforce legal alphabet
307 | views::char_to<std::ranges::range_value_t<seq_type>>, // convert to actual target alphabet
308 std::cpp20::back_inserter(seq));
309 #endif // SEQAN3_WORKAROUND_VIEW_PERFORMANCE
313 detail::consume(stream_view | views::take_until(is_id));
318 template <typename stream_it_t, typename id_type>
319 void write_id(stream_it_t & stream_it, sequence_file_output_options const & options, id_type && id)
321 if (options.fasta_legacy_id_marker)
326 if (options.fasta_blank_before_id)
329 stream_it.write_range(id);
330 stream_it.write_end_of_line(options.add_carriage_return);
334 template <typename stream_it_t, typename seq_type>
335 void write_seq(stream_it_t & stream_it, sequence_file_output_options const & options, seq_type && seq)
337 auto char_sequence = seq | views::to_char;
339 if (options.fasta_letters_per_line > 0)
341 /* Using `views::interleave` is probably the way to go but that needs performance-tuning.*/
342 auto it = std::ranges::begin(char_sequence);
343 auto end = std::ranges::end(char_sequence);
347 /* Note: This solution is slightly suboptimal for sized but non-random-access ranges.*/
348 auto current_end = it;
349 size_t steps = std::ranges::advance(current_end, options.fasta_letters_per_line, end);
350 using subrange_t = std::ranges::subrange<decltype(it), decltype(it), std::ranges::subrange_kind::sized>;
351 it = stream_it.write_range(subrange_t{it, current_end, (options.fasta_letters_per_line - steps)});
352 stream_it.write_end_of_line(options.add_carriage_return);
357 stream_it.write_range(char_sequence);
358 stream_it.write_end_of_line(options.add_carriage_return);
Adaptations of algorithms from the Ranges TS.
Provides aliases for qualified.
Provides alphabet adaptations for standard char types.
Provides seqan3::views::char_to.
Provides seqan3::dna5, container aliases and string literals.
constexpr auto istreambuf
A view factory that returns a view over the stream buffer of an input stream.
Definition: istreambuf.hpp:113
Provides seqan3::detail::ignore_output_iterator for writing to null stream.
The generic concept for a sequence.
Provides various utility functions.
Provides seqan3::fast_istreambuf_iterator and seqan3::fast_ostreambuf_iterator, as well as,...
Provides seqan3::views::istreambuf.
Provides seqan3::views::join.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
SeqAn specific customisations in the standard namespace.
Provides character predicates for tokenisation.
Provides various utility functions.
Provides various transformation traits used by the range module.
Adaptations of concepts from the Ranges TS.
Provides seqan3::sequence_file_output_options.
The options type defines various option members that influence the behaviour of all or some formats.
Definition: output_options.hpp:22
Provides seqan3::views::take.
Provides seqan3::views::take_exactly and seqan3::views::take_exactly_or_throw.
Provides seqan3::views::take_line and seqan3::views::take_line_or_throw.
Provides seqan3::views::take_until and seqan3::views::take_until_or_throw.
Provides seqan3::views::to_char.