 |
SeqAn3
3.0.2
The Modern C++ library for sequence analysis.
|
|
Go to the documentation of this file.
20 #include <type_traits>
107 template <
typename stream_type,
108 typename seq_legal_alph_type,
109 bool structured_seq_combined,
113 typename structure_type,
114 typename energy_type,
116 typename comment_type,
117 typename offset_type>
123 structure_type & structure,
124 energy_type & energy,
125 react_type & SEQAN3_DOXYGEN_ONLY(react),
126 react_type & SEQAN3_DOXYGEN_ONLY(react_err),
127 comment_type & SEQAN3_DOXYGEN_ONLY(comment),
128 offset_type & SEQAN3_DOXYGEN_ONLY(offset))
133 auto constexpr is_id = is_char<'>
'>;
134 if (is_id(*begin(stream_view)))
136 if constexpr (!detail::decays_to_ignore_v<id_type>)
138 if (options.truncate_ids)
140 std::ranges::copy(stream_view | std::views::drop_while(is_id || is_blank) // skip leading >
141 | views::take_until_or_throw(is_cntrl || is_blank)
142 | views::char_to<std::ranges::range_value_t<id_type>>,
143 std::cpp20::back_inserter(id));
144 detail::consume(stream_view | views::take_line_or_throw);
148 std::ranges::copy(stream_view | std::views::drop_while(is_id || is_blank) // skip leading >
149 | views::take_line_or_throw
150 | views::char_to<std::ranges::range_value_t<id_type>>,
151 std::cpp20::back_inserter(id));
156 detail::consume(stream_view | views::take_line_or_throw);
159 else if constexpr (!detail::decays_to_ignore_v<id_type>)
161 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>;
162 if (!is_legal_seq(*begin(stream_view))) // if neither id nor seq found: throw
164 throw parse_error{std::string{"Expected to be on beginning of ID or sequence, but "} +
165 is_id.msg + " and " + is_legal_seq.msg +
166 " evaluated to false on " + detail::make_printable(*begin(stream_view))};
171 if constexpr (!detail::decays_to_ignore_v<seq_type>)
173 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>;
174 std::ranges::copy(stream_view | views::take_line_or_throw // until end of line
175 | std::views::filter(!(is_space || is_digit)) // ignore whitespace and numbers
176 | std::views::transform([is_legal_seq](char const c)
178 if (!is_legal_seq(c)) // enforce legal alphabet
180 throw parse_error{std::string{"Encountered an unexpected letter: "} +
182 " evaluated to false on " +
183 detail::make_printable(c)};
187 | views::char_to<std::ranges::range_value_t<seq_type>>, // convert to actual target alphabet
188 std::cpp20::back_inserter(seq));
192 detail::consume(stream_view | views::take_line_or_throw);
195 // READ STRUCTURE (if present)
196 [[maybe_unused]] int64_t structure_length{};
197 if constexpr (!detail::decays_to_ignore_v<structure_type>)
199 if constexpr (structured_seq_combined)
201 assert(std::addressof(seq) == std::addressof(structure));
202 using alph_type = typename std::ranges::range_value_t<structure_type>::structure_alphabet_type;
203 // We need the structure_length parameter to count the length of the structure while reading
204 // because we cannot infer it from the (already resized) structure_seq object.
205 auto res = std::ranges::copy(read_structure<alph_type>(stream_view), std::ranges::begin(structure));
206 structure_length = std::ranges::distance(std::ranges::begin(structure), res.out);
208 if constexpr (!detail::decays_to_ignore_v<bpp_type>)
209 detail::bpp_from_rna_structure<alph_type>(bpp, structure);
213 using alph_type = std::ranges::range_value_t<structure_type>;
214 std::ranges::copy(read_structure<alph_type>(stream_view), std::cpp20::back_inserter(structure));
215 structure_length = std::ranges::distance(structure);
217 if constexpr (!detail::decays_to_ignore_v<bpp_type>)
218 detail::bpp_from_rna_structure<alph_type>(bpp, structure);
221 else if constexpr (!detail::decays_to_ignore_v<bpp_type>)
223 detail::bpp_from_rna_structure<wuss51>(bpp, read_structure<wuss51>(stream_view));
224 structure_length = std::ranges::distance(bpp);
228 detail::consume(stream_view | views::take_until(is_space)); // until whitespace
231 if constexpr (!detail::decays_to_ignore_v<seq_type> &&
232 !(detail::decays_to_ignore_v<structure_type> && detail::decays_to_ignore_v<bpp_type>))
234 if (std::ranges::distance(seq) != structure_length)
235 throw parse_error{"Found sequence and associated structure of different length."};
238 // READ ENERGY (if present)
239 if constexpr (!detail::decays_to_ignore_v<energy_type>)
241 std::string e_str = stream_view | views::take_line
242 | std::views::filter(!(is_space || is_char<'(
'> || is_char<')
'>))
243 | views::to<std::string>;
246 size_t num_processed;
247 energy = std::stod(e_str, &num_processed);
248 if (num_processed != e_str.size()) // [[unlikely]]
250 throw parse_error{std::string{"Failed to parse energy value '"} + e_str + "'."};
256 detail::consume(stream_view | views::take_line);
258 detail::consume(stream_view | views::take_until(!is_space));
262 template <typename stream_type, // constraints checked by file
263 typename seq_type, // other constraints checked inside function
266 typename structure_type,
267 typename energy_type,
269 typename comment_type,
270 typename offset_type>
271 void write_structure_record(stream_type & stream,
272 structure_file_output_options const & options,
275 bpp_type && SEQAN3_DOXYGEN_ONLY(bpp),
276 structure_type && structure,
277 energy_type && energy,
278 react_type && SEQAN3_DOXYGEN_ONLY(react),
279 react_type && SEQAN3_DOXYGEN_ONLY(react_err),
280 comment_type && SEQAN3_DOXYGEN_ONLY(comment),
281 offset_type && SEQAN3_DOXYGEN_ONLY(offset))
283 std::cpp20::ostreambuf_iterator stream_it{stream};
285 // WRITE ID (optional)
286 if constexpr (!detail::decays_to_ignore_v<id_type>)
288 if (!std::ranges::empty(id))
292 std::ranges::copy(id, stream_it);
293 detail::write_eol(stream_it, options.add_carriage_return);
298 if constexpr (!detail::decays_to_ignore_v<seq_type>)
300 if (std::ranges::empty(seq)) //[[unlikely]]
301 throw std::runtime_error{"The SEQ field may not be empty when writing Vienna files."};
303 std::ranges::copy(seq | views::to_char, stream_it);
304 detail::write_eol(stream_it, options.add_carriage_return);
308 throw std::logic_error{"The SEQ and STRUCTURED_SEQ fields may not both be set to ignore "
309 "when writing Vienna files."};
312 // WRITE STRUCTURE (optional)
313 if constexpr (!detail::decays_to_ignore_v<structure_type>)
315 if (!std::ranges::empty(structure))
316 std::ranges::copy(structure | views::to_char, stream_it);
318 // WRITE ENERGY (optional)
319 if constexpr (!detail::decays_to_ignore_v<energy_type>)
323 // TODO(joergi-w) enable the following when std::to_chars is implemented for float types
324 // auto [endptr, ec] = std::to_chars(str.data(),
325 // str.data() + str.size(),
327 // std::chars_format::fixed,
328 // options.precision);
329 // if (ec == std::errc())
330 // std::ranges::copy(str.data(), endptr, stream_it);
332 // throw std::runtime_error{"The energy could not be transformed into a string."};
337 std::array<char, 100> str;
338 int len = std::snprintf(str.data(), 100, "%.*f", options.precision, energy);
339 if (len < 0 || len >= 100)
340 throw std::runtime_error{"The energy could not be transformed into a string."};
341 std::ranges::copy(str.data(), str.data() + len, stream_it);
346 detail::write_eol(stream_it, options.add_carriage_return);
348 else if constexpr (!detail::decays_to_ignore_v<energy_type>)
350 throw std::logic_error{"The ENERGY field cannot be written to a Vienna file without providing STRUCTURE."};
361 template <typename alph_type, typename stream_view_type>
362 auto read_structure(stream_view_type & stream_view)
364 auto constexpr is_legal_structure = is_in_alphabet<alph_type>;
365 return stream_view | views::take_until(is_space) // until whitespace
366 | std::views::transform([is_legal_structure](char const c)
368 if (!is_legal_structure(c))
371 std::string{"Encountered an unexpected letter: "} +
372 is_legal_structure.msg +
373 " evaluated to false on " + detail::make_printable(c)};
376 }) // enforce legal alphabet
377 | views::char_to<alph_type>; // convert to actual target alphabet
381 } // namespace seqan3::detail
Provides the WUSS format for RNA structure.
Provides seqan3::views::take_until and seqan3::views::take_until_or_throw.
Helper functions (e.g. conversions) for the structure IO submodule.
Adaptations of algorithms from the Ranges TS.
constexpr sequenced_policy seq
Global execution policy object for sequenced execution policy.
Definition: execution.hpp:54
Provides seqan3::structure_file_output_options.
Provides seqan3::views::to.
Provides various transformation traits used by the range module.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
Provides alphabet adaptations for standard char types.
Provides seqan3::views::to_char.
Provides seqan3::views::take.
Adaptations of concepts from the Ranges TS.
Provides character predicates for tokenisation.
SeqAn specific customisations in the standard namespace.
Provides seqan3::views::istreambuf.
Provides seqan3::views::take_line and seqan3::views::take_line_or_throw.
Provides seqan3::fast_istreambuf_iterator and seqan3::fast_ostreambuf_iterator, as well as,...
Provides various utility functions.
Provides various utility functions.
Provides seqan3::views::char_to.
constexpr auto istreambuf
A view factory that returns a view over the stream buffer of an input stream.
Definition: istreambuf.hpp:113