21 #include <type_traits> 24 #include <range/v3/algorithm/copy.hpp> 25 #include <range/v3/view/chunk.hpp> 26 #include <range/v3/view/drop_while.hpp> 27 #include <range/v3/view/join.hpp> 28 #include <range/v3/view/remove_if.hpp> 29 #include <range/v3/view/transform.hpp> 109 class structure_file_input_format<format_vienna>
113 using format_tag = format_vienna;
118 structure_file_input_format() noexcept = default;
119 structure_file_input_format(structure_file_input_format const &) = delete;
122 structure_file_input_format & operator=(structure_file_input_format const &) = delete;
123 structure_file_input_format(structure_file_input_format &&) noexcept = default;
124 structure_file_input_format & operator=(structure_file_input_format &&) noexcept = default;
125 ~structure_file_input_format() noexcept = default;
129 template <typename stream_type,
130 typename seq_legal_alph_type,
131 bool structured_seq_combined,
135 typename structure_type,
136 typename energy_type,
138 typename comment_type,
139 typename offset_type>
140 void read(stream_type & stream,
141 structure_file_input_options<seq_legal_alph_type, structured_seq_combined> const & options,
145 structure_type & structure,
146 energy_type & energy,
147 react_type & SEQAN3_DOXYGEN_ONLY(react),
148 react_type & SEQAN3_DOXYGEN_ONLY(react_err),
149 comment_type & SEQAN3_DOXYGEN_ONLY(comment),
150 offset_type & SEQAN3_DOXYGEN_ONLY(offset))
155 auto constexpr is_id = is_char<'>
'>; 156 if (is_id(*begin(stream_view))) 158 if constexpr (!detail::decays_to_ignore_v<id_type>) 160 if (options.truncate_ids) 162 std::ranges::copy(stream_view | std::view::drop_while(is_id || is_blank) // skip leading > 163 | view::take_until_or_throw(is_cntrl || is_blank) 164 | view::char_to<value_type_t<id_type>>, 165 std::back_inserter(id)); 166 detail::consume(stream_view | view::take_line_or_throw); 170 std::ranges::copy(stream_view | std::view::drop_while(is_id || is_blank) // skip leading > 171 | view::take_line_or_throw 172 | view::char_to<value_type_t<id_type>>, 173 std::back_inserter(id)); 178 detail::consume(stream_view | view::take_line_or_throw); 181 else if constexpr (!detail::decays_to_ignore_v<id_type>) 183 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>; 184 if (!is_legal_seq(*begin(stream_view))) // if neither id nor seq found: throw 186 throw parse_error{std::string{"Expected to be on beginning of ID or sequence, but "} + 187 is_id.msg.str() + " and " + is_legal_seq.msg.str() + 188 " evaluated to false on " + detail::make_printable(*begin(stream_view))}; 193 if constexpr (!detail::decays_to_ignore_v<seq_type>) 195 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>; 196 std::ranges::copy(stream_view | view::take_line_or_throw // until end of line 197 | std::view::filter(!(is_space || is_digit)) // ignore whitespace and numbers 198 | std::view::transform([is_legal_seq](char const c) 200 if (!is_legal_seq(c)) // enforce legal alphabet 202 throw parse_error{std::string{"Encountered an unexpected letter: "} + 203 is_legal_seq.msg.str() + 204 " evaluated to false on " + 205 detail::make_printable(c)}; 209 | view::char_to<value_type_t<seq_type>>, // convert to actual target alphabet 210 std::back_inserter(seq)); 214 detail::consume(stream_view | view::take_line_or_throw); 217 // READ STRUCTURE (if present) 218 if constexpr (!detail::decays_to_ignore_v<structure_type>) 220 if constexpr (structured_seq_combined) 222 assert(std::addressof(seq) == std::addressof(structure)); 223 using alph_type = typename value_type_t<structure_type>::structure_alphabet_type; 224 std::ranges::copy(read_structure<alph_type>(stream_view), begin(structure)); 226 if constexpr (!detail::decays_to_ignore_v<bpp_type>) 227 detail::bpp_from_rna_structure<alph_type>(bpp, structure); 231 using alph_type = value_type_t<structure_type>; 232 std::ranges::copy(read_structure<alph_type>(stream_view), std::back_inserter(structure)); 234 if constexpr (!detail::decays_to_ignore_v<bpp_type>) 235 detail::bpp_from_rna_structure<alph_type>(bpp, structure); 237 if constexpr (!detail::decays_to_ignore_v<seq_type>) 238 if (size(seq) != size(structure)) 239 throw parse_error{"Found sequence and associated structure of different length."}; 241 else if constexpr (!detail::decays_to_ignore_v<bpp_type>) 243 detail::bpp_from_rna_structure<wuss51>(bpp, read_structure<wuss51>(stream_view)); 245 if constexpr (!detail::decays_to_ignore_v<seq_type>) 246 if (size(seq) != size(bpp)) 247 throw parse_error{"Found sequence and associated structure of different length."}; 251 detail::consume(stream_view | view::take_until(is_space)); // until whitespace 254 // READ ENERGY (if present) 255 if constexpr (!detail::decays_to_ignore_v<energy_type>) 257 std::string e_str = stream_view | view::take_line 258 | std::view::filter(!(is_space || is_char<'(
'> || is_char<')
'>)); 261 size_t num_processed; 262 energy = std::stod(e_str, &num_processed); 263 if (num_processed != e_str.size()) // [[unlikely]] 265 throw parse_error{std::string{"Failed to parse energy value '"} + e_str + "'."}; 271 detail::consume(stream_view | view::take_line); 273 detail::consume(stream_view | view::take_until(!is_space)); 284 template <typename alph_type, typename stream_view_type> 285 auto read_structure(stream_view_type & stream_view) 287 auto constexpr is_legal_structure = is_in_alphabet<alph_type>; 288 return stream_view | view::take_until(is_space) // until whitespace 289 | std::view::transform([is_legal_structure](char const c) 291 if (!is_legal_structure(c)) 294 std::string{"Encountered an unexpected letter: "} + 295 is_legal_structure.msg.str() + 296 " evaluated to false on " + detail::make_printable(c)}; 299 }) // enforce legal alphabet 300 | view::char_to<alph_type>; // convert to actual target alphabet 307 class structure_file_output_format<format_vienna> 311 using format_tag = format_vienna; 316 structure_file_output_format() noexcept = default; //!< Defaulted. 318 structure_file_output_format(structure_file_output_format const &) = delete; 320 structure_file_output_format & operator=(structure_file_output_format const &) = delete; 321 structure_file_output_format(structure_file_output_format &&) noexcept = default; //!< Defaulted. 322 structure_file_output_format & operator=(structure_file_output_format &&) noexcept = default; //!< Defaulted. 323 ~structure_file_output_format() noexcept = default; //!< Defaulted. 327 template <typename stream_type, // constraints checked by file 328 typename seq_type, // other constraints checked inside function 331 typename structure_type, 332 typename energy_type, 334 typename comment_type, 335 typename offset_type> 336 void write(stream_type & stream, 337 structure_file_output_options const & options, 340 bpp_type && SEQAN3_DOXYGEN_ONLY(bpp), 341 structure_type && structure, 342 energy_type && energy, 343 react_type && SEQAN3_DOXYGEN_ONLY(react), 344 react_type && SEQAN3_DOXYGEN_ONLY(react_err), 345 comment_type && SEQAN3_DOXYGEN_ONLY(comment), 346 offset_type && SEQAN3_DOXYGEN_ONLY(offset)) 348 seqan3::ostreambuf_iterator stream_it{stream}; 350 // WRITE ID (optional) 351 if constexpr (!detail::decays_to_ignore_v<id_type>) 357 std::ranges::copy(id, stream_it); 358 detail::write_eol(stream_it, options.add_carriage_return); 363 if constexpr (!detail::decays_to_ignore_v<seq_type>) 365 if (empty(seq)) //[[unlikely]] 366 throw std::runtime_error{"The SEQ field may not be empty when writing Vienna files."}; 368 std::ranges::copy(seq | view::to_char, stream_it); 369 detail::write_eol(stream_it, options.add_carriage_return); 373 throw std::logic_error{"The SEQ and STRUCTURED_SEQ fields may not both be set to ignore " 374 "when writing Vienna files."}; 377 // WRITE STRUCTURE (optional) 378 if constexpr (!detail::decays_to_ignore_v<structure_type>) 380 if (!empty(structure)) 381 std::ranges::copy(structure | view::to_char, stream_it); 383 // WRITE ENERGY (optional) 384 if constexpr (!detail::decays_to_ignore_v<energy_type>) 388 // TODO(joergi-w) enable the following when std::to_chars is implemented for float types 389 // auto [endptr, ec] = std::to_chars(str.data(), 390 // str.data() + str.size(), 392 // std::chars_format::fixed, 393 // options.precision); 394 // if (ec == std::errc()) 395 // std::ranges::copy(str.data(), endptr, stream_it); 397 // throw std::runtime_error{"The energy could not be transformed into a string."}; 402 std::array<char, 100> str; 403 int len = std::snprintf(str.data(), 100, "%.*f", options.precision, energy); 404 if (len < 0 || len >= 100) 405 throw std::runtime_error{"The energy could not be transformed into a string."}; 406 std::ranges::copy(str.data(), str.data() + len, stream_it); 411 detail::write_eol(stream_it, options.add_carriage_return); 413 else if constexpr (!detail::decays_to_ignore_v<energy_type>) 415 throw std::logic_error{"The ENERGY field cannot be written to a Vienna file without providing STRUCTURE."}; 420 } // namespace seqan3::detail
Provides seqan3::view::istreambuf.
constexpr sequenced_policy seq
Global execution policy object for sequenced execution policy.
Definition: execution.hpp:54
Provides various shortcuts for common std::ranges functions.
constexpr auto istreambuf
A view factory that returns a view over the stream buffer of an input stream.
Definition: istreambuf.hpp:245
Provides seqan3::view::take.
The main SeqAn3 namespace.
Provides seqan3::view::take_line and seqan3::view::take_line_or_throw.
Helper functions (e.g. conversions) for the structure IO submodule.
Provides seqan3::structure_file_output_options.
Provides seqan3::view::take_until and seqan3::view::take_until_or_throw.
Provides various utility functions.
Provides various utility functions.
Provides seqan3::view::char_to.
Adaptations of concepts from the Ranges TS.
Provides the WUSS format for RNA structure.
Definition: aligned_sequence_concept.hpp:35
Provides character predicates for tokenisation.
Provides seqan3::ostream and seqan3::ostreambuf iterator.
Adaptations of algorithms from the Ranges TS.
Provides seqan3::view::to_char.
Provides various transformation traits used by the range module.