46 #include <string_view> 50 #include <range/v3/algorithm/copy.hpp> 51 #include <range/v3/utility/iterator.hpp> 52 #include <range/v3/view/chunk.hpp> 53 #include <range/v3/view/drop_while.hpp> 54 #include <range/v3/view/join.hpp> 55 #include <range/v3/view/remove_if.hpp> 56 #include <range/v3/view/transform.hpp> 136 template <
typename stream_type,
137 typename seq_legal_alph_type,
138 bool structured_seq_combined,
142 typename structure_type,
143 typename energy_type,
145 typename comment_type,
146 typename offset_type>
147 void read(stream_type & stream,
152 structure_type & structure,
153 energy_type & energy,
154 react_type & SEQAN3_DOXYGEN_ONLY(react),
155 react_type & SEQAN3_DOXYGEN_ONLY(react_err),
156 comment_type & SEQAN3_DOXYGEN_ONLY(comment),
157 offset_type & SEQAN3_DOXYGEN_ONLY(offset))
160 decltype(std::istreambuf_iterator<char>{})>
161 { std::istreambuf_iterator<char>{stream}, std::istreambuf_iterator<char>{} };
164 auto constexpr is_id = is_char<'>
'>; 165 if (is_id(*begin(stream_view))) 167 if constexpr (!detail::decays_to_ignore_v<id_type>) 169 if (options.truncate_ids) 171 std::ranges::copy(stream_view | ranges::view::drop_while(is_id || is_blank) // skip leading > 172 | view::take_until_or_throw(is_cntrl || is_blank) 173 | view::char_to<value_type_t<id_type>>, 174 std::back_inserter(id)); 175 detail::consume(stream_view | view::take_line_or_throw); 179 std::ranges::copy(stream_view | ranges::view::drop_while(is_id || is_blank) // skip leading > 180 | view::take_line_or_throw 181 | view::char_to<value_type_t<id_type>>, 182 std::back_inserter(id)); 187 detail::consume(stream_view | view::take_line_or_throw); 190 else if constexpr (!detail::decays_to_ignore_v<id_type>) 192 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>; 193 if (!is_legal_seq(*begin(stream_view))) // if neither id nor seq found: throw 195 throw parse_error{std::string{"Expected to be on beginning of ID or sequence, but "} + 196 is_id.msg.string() + " and " + is_legal_seq.msg.string() + 197 " evaluated to false on " + detail::make_printable(*begin(stream_view))}; 202 if constexpr (!detail::decays_to_ignore_v<seq_type>) 204 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>; 205 std::ranges::copy(stream_view | view::take_line_or_throw // until end of line 206 | ranges::view::remove_if(is_space || is_digit) // ignore whitespace and numbers 207 | ranges::view::transform([is_legal_seq](char const c) 209 if (!is_legal_seq(c)) // enforce legal alphabet 211 throw parse_error{std::string{"Encountered an unexpected letter: "} + 212 is_legal_seq.msg.string() + 213 " evaluated to false on " + 214 detail::make_printable(c)}; 218 | view::char_to<value_type_t<seq_type>>, // convert to actual target alphabet 219 std::back_inserter(seq)); 223 detail::consume(stream_view | view::take_line_or_throw); 226 // READ STRUCTURE (if present) 227 if constexpr (!detail::decays_to_ignore_v<structure_type>) 229 if constexpr (structured_seq_combined) 231 assert(std::addressof(seq) == std::addressof(structure)); 232 using alph_type = typename value_type_t<structure_type>::structure_alphabet_type; 233 std::ranges::copy(read_structure<alph_type>(stream_view), begin(structure)); 235 if constexpr (!detail::decays_to_ignore_v<bpp_type>) 236 detail::bpp_from_rna_structure<alph_type>(bpp, structure); 240 using alph_type = value_type_t<structure_type>; 241 std::ranges::copy(read_structure<alph_type>(stream_view), std::back_inserter(structure)); 243 if constexpr (!detail::decays_to_ignore_v<bpp_type>) 244 detail::bpp_from_rna_structure<alph_type>(bpp, structure); 246 if constexpr (!detail::decays_to_ignore_v<seq_type>) 247 if (size(seq) != size(structure)) 248 throw parse_error{"Found sequence and associated structure of different length."}; 250 else if constexpr (!detail::decays_to_ignore_v<bpp_type>) 252 detail::bpp_from_rna_structure<wuss51>(bpp, read_structure<wuss51>(stream_view)); 254 if constexpr (!detail::decays_to_ignore_v<seq_type>) 255 if (size(seq) != size(bpp)) 256 throw parse_error{"Found sequence and associated structure of different length."}; 260 detail::consume(stream_view | view::take_until(is_space)); // until whitespace 263 // READ ENERGY (if present) 264 if constexpr (!detail::decays_to_ignore_v<energy_type>) 266 std::string e_str = stream_view | view::take_line 267 | ranges::view::remove_if(is_space || is_char<'(
'> || is_char<')
'>); 270 size_t num_processed; 271 energy = std::stod(e_str, &num_processed); 272 if (num_processed != e_str.size()) // [[unlikely]] 274 throw parse_error{std::string{"Failed to parse energy value '"} + e_str + "'."}; 280 detail::consume(stream_view | view::take_line); 282 detail::consume(stream_view | view::take_until(!is_space)); 284 // make sure "buffer at end" implies "stream at end" 285 if ((std::istreambuf_iterator<char>{stream} == std::istreambuf_iterator<char>{}) && (!stream.eof())) 287 stream.get(); // triggers error in stream and sets eof 292 template <typename stream_type, // constraints checked by file 293 typename seq_type, // other constraints checked inside function 296 typename structure_type, 297 typename energy_type, 299 typename comment_type, 300 typename offset_type> 301 void write(stream_type & stream, 302 structure_file_output_options const & options, 305 bpp_type && SEQAN3_DOXYGEN_ONLY(bpp), 306 structure_type && structure, 307 energy_type && energy, 308 react_type && SEQAN3_DOXYGEN_ONLY(react), 309 react_type && SEQAN3_DOXYGEN_ONLY(react_err), 310 comment_type && SEQAN3_DOXYGEN_ONLY(comment), 311 offset_type && SEQAN3_DOXYGEN_ONLY(offset)) 313 std::ranges::ostreambuf_iterator stream_it{stream}; 315 // WRITE ID (optional) 316 if constexpr (!detail::decays_to_ignore_v<id_type>) 322 std::ranges::copy(id, stream_it); 323 detail::write_eol(stream_it, options.add_carriage_return); 328 if constexpr (!detail::decays_to_ignore_v<seq_type>) 330 if (empty(seq)) //[[unlikely]] 331 throw std::runtime_error{"The SEQ field may not be empty when writing Vienna files."}; 333 std::ranges::copy(seq | view::to_char, stream_it); 334 detail::write_eol(stream_it, options.add_carriage_return); 338 throw std::logic_error{"The SEQ and STRUCTURED_SEQ fields may not both be set to ignore " 339 "when writing Vienna files."}; 342 // WRITE STRUCTURE (optional) 343 if constexpr (!detail::decays_to_ignore_v<structure_type>) 345 if (!empty(structure)) 346 std::ranges::copy(structure | view::to_char, stream_it); 348 // WRITE ENERGY (optional) 349 if constexpr (!detail::decays_to_ignore_v<energy_type>) 353 // TODO(joergi-w) enable the following when std::to_chars is implemented for float types 354 // auto [endptr, ec] = std::to_chars(str.data(), 355 // str.data() + str.size(), 357 // std::chars_format::fixed, 358 // options.precision); 359 // if (ec == std::errc()) 360 // std::ranges::copy(str.data(), endptr, stream_it); 362 // throw std::runtime_error{"The energy could not be transformed into a string."}; 367 std::array<char, 100> str; 368 int len = std::snprintf(str.data(), 100, "%.*f", options.precision, energy); 369 if (len < 0 || len >= 100) 370 throw std::runtime_error{"The energy could not be transformed into a string."}; 371 std::ranges::copy(str.data(), str.data() + len, stream_it); 376 detail::write_eol(stream_it, options.add_carriage_return); 378 else if constexpr (!detail::decays_to_ignore_v<energy_type>) 380 throw std::logic_error{"The ENERGY field cannot be written to a Vienna file without providing STRUCTURE."}; 392 template <typename alph_type, typename stream_view_type> 393 auto read_structure(stream_view_type & stream_view) 395 auto constexpr is_legal_structure = is_in_alphabet<alph_type>; 396 return stream_view | view::take_until(is_space) // until whitespace 397 | ranges::view::transform([is_legal_structure](char const c) 399 if (!is_legal_structure(c)) 402 std::string{"Encountered an unexpected letter: "} + 403 is_legal_structure.msg.string() + 404 " evaluated to false on " + detail::make_printable(c)}; 407 }) // enforce legal alphabet 408 | view::char_to<alph_type>; // convert to actual target alphabet 412 } // namespace seqan3 Provides C++20 additions to the <iterator> header.
Contains various shortcuts for common std::ranges functions.
Provides seqan3::view::take.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:58
Provides seqan3::view::take_line and seqan3::view::take_line_or_throw.
Helper functions (e.g. conversions) for the structure IO submodule.
Provides seqan3::view::subrange.
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.
std::ranges::iterator_range< it_t, sen_t > subrange
Create a view from a pair of iterator and sentinel.
Definition: subrange.hpp:96
Provides C++20 additions to the type_traits header.
Provides seqan3::view::to_char.
Provides parse conditions for tokenization.
Provides various metafunctions used by the range module.