20 #include <type_traits> 108 template <
typename stream_type,
109 typename seq_legal_alph_type,
110 bool structured_seq_combined,
114 typename structure_type,
115 typename energy_type,
117 typename comment_type,
118 typename offset_type>
126 react_type & SEQAN3_DOXYGEN_ONLY(
react),
127 react_type & SEQAN3_DOXYGEN_ONLY(
react_err),
128 comment_type & SEQAN3_DOXYGEN_ONLY(
comment),
129 offset_type & SEQAN3_DOXYGEN_ONLY(
offset))
134 auto constexpr is_id = is_char<'>
'>; 135 if (is_id(*begin(stream_view))) 137 if constexpr (!detail::decays_to_ignore_v<id_type>) 139 if (options.truncate_ids) 141 std::ranges::copy(stream_view | std::views::drop_while(is_id || is_blank) // skip leading > 142 | views::take_until_or_throw(is_cntrl || is_blank) 143 | views::char_to<value_type_t<id_type>>, 144 std::ranges::back_inserter(id)); 145 detail::consume(stream_view | views::take_line_or_throw); 149 std::ranges::copy(stream_view | std::views::drop_while(is_id || is_blank) // skip leading > 150 | views::take_line_or_throw 151 | views::char_to<value_type_t<id_type>>, 152 std::ranges::back_inserter(id)); 157 detail::consume(stream_view | views::take_line_or_throw); 160 else if constexpr (!detail::decays_to_ignore_v<id_type>) 162 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>; 163 if (!is_legal_seq(*begin(stream_view))) // if neither id nor seq found: throw 165 throw parse_error{std::string{"Expected to be on beginning of ID or sequence, but "} + 166 is_id.msg + " and " + is_legal_seq.msg + 167 " evaluated to false on " + detail::make_printable(*begin(stream_view))}; 172 if constexpr (!detail::decays_to_ignore_v<seq_type>) 174 auto constexpr is_legal_seq = is_in_alphabet<seq_legal_alph_type>; 175 std::ranges::copy(stream_view | views::take_line_or_throw // until end of line 176 | std::views::filter(!(is_space || is_digit)) // ignore whitespace and numbers 177 | std::views::transform([is_legal_seq](char const c) 179 if (!is_legal_seq(c)) // enforce legal alphabet 181 throw parse_error{std::string{"Encountered an unexpected letter: "} + 183 " evaluated to false on " + 184 detail::make_printable(c)}; 188 | views::char_to<value_type_t<seq_type>>, // convert to actual target alphabet 189 std::ranges::back_inserter(seq)); 193 detail::consume(stream_view | views::take_line_or_throw); 196 // READ STRUCTURE (if present) 197 [[maybe_unused]] int64_t structure_length{}; 198 if constexpr (!detail::decays_to_ignore_v<structure_type>) 200 if constexpr (structured_seq_combined) 202 assert(std::addressof(seq) == std::addressof(structure)); 203 using alph_type = typename value_type_t<structure_type>::structure_alphabet_type; 204 // We need the structure_length parameter to count the length of the structure while reading 205 // because we cannot infer it from the (already resized) structure_seq object. 206 auto res = std::ranges::copy(read_structure<alph_type>(stream_view), std::ranges::begin(structure)); 207 structure_length = std::ranges::distance(std::ranges::begin(structure), res.out); 209 if constexpr (!detail::decays_to_ignore_v<bpp_type>) 210 detail::bpp_from_rna_structure<alph_type>(bpp, structure); 214 using alph_type = value_type_t<structure_type>; 215 std::ranges::copy(read_structure<alph_type>(stream_view), std::ranges::back_inserter(structure)); 216 structure_length = std::ranges::distance(structure); 218 if constexpr (!detail::decays_to_ignore_v<bpp_type>) 219 detail::bpp_from_rna_structure<alph_type>(bpp, structure); 222 else if constexpr (!detail::decays_to_ignore_v<bpp_type>) 224 detail::bpp_from_rna_structure<wuss51>(bpp, read_structure<wuss51>(stream_view)); 225 structure_length = std::ranges::distance(bpp); 229 detail::consume(stream_view | views::take_until(is_space)); // until whitespace 232 if constexpr (!detail::decays_to_ignore_v<seq_type> && 233 !(detail::decays_to_ignore_v<structure_type> && detail::decays_to_ignore_v<bpp_type>)) 235 if (std::ranges::distance(seq) != structure_length) 236 throw parse_error{"Found sequence and associated structure of different length."}; 239 // READ ENERGY (if present) 240 if constexpr (!detail::decays_to_ignore_v<energy_type>) 242 std::string e_str = stream_view | views::take_line 243 | std::views::filter(!(is_space || is_char<'(
'> || is_char<')
'>)) 244 | views::to<std::string>; 247 size_t num_processed; 248 energy = std::stod(e_str, &num_processed); 249 if (num_processed != e_str.size()) // [[unlikely]] 251 throw parse_error{std::string{"Failed to parse energy value '"} + e_str + "'."}; 257 detail::consume(stream_view | views::take_line); 259 detail::consume(stream_view | views::take_until(!is_space)); 263 template <typename stream_type, // constraints checked by file 264 typename seq_type, // other constraints checked inside function 267 typename structure_type, 268 typename energy_type, 270 typename comment_type, 271 typename offset_type> 272 void write_structure_record(stream_type & stream, 273 structure_file_output_options const & options, 276 bpp_type && SEQAN3_DOXYGEN_ONLY(bpp), 277 structure_type && structure, 278 energy_type && energy, 279 react_type && SEQAN3_DOXYGEN_ONLY(react), 280 react_type && SEQAN3_DOXYGEN_ONLY(react_err), 281 comment_type && SEQAN3_DOXYGEN_ONLY(comment), 282 offset_type && SEQAN3_DOXYGEN_ONLY(offset)) 284 seqan3::ostreambuf_iterator stream_it{stream}; 286 // WRITE ID (optional) 287 if constexpr (!detail::decays_to_ignore_v<id_type>) 293 std::ranges::copy(id, stream_it); 294 detail::write_eol(stream_it, options.add_carriage_return); 299 if constexpr (!detail::decays_to_ignore_v<seq_type>) 301 if (empty(seq)) //[[unlikely]] 302 throw std::runtime_error{"The SEQ field may not be empty when writing Vienna files."}; 304 std::ranges::copy(seq | views::to_char, stream_it); 305 detail::write_eol(stream_it, options.add_carriage_return); 309 throw std::logic_error{"The SEQ and STRUCTURED_SEQ fields may not both be set to ignore " 310 "when writing Vienna files."}; 313 // WRITE STRUCTURE (optional) 314 if constexpr (!detail::decays_to_ignore_v<structure_type>) 316 if (!empty(structure)) 317 std::ranges::copy(structure | views::to_char, stream_it); 319 // WRITE ENERGY (optional) 320 if constexpr (!detail::decays_to_ignore_v<energy_type>) 324 // TODO(joergi-w) enable the following when std::to_chars is implemented for float types 325 // auto [endptr, ec] = std::to_chars(str.data(), 326 // str.data() + str.size(), 328 // std::chars_format::fixed, 329 // options.precision); 330 // if (ec == std::errc()) 331 // std::ranges::copy(str.data(), endptr, stream_it); 333 // throw std::runtime_error{"The energy could not be transformed into a string."}; 338 std::array<char, 100> str; 339 int len = std::snprintf(str.data(), 100, "%.*f", options.precision, energy); 340 if (len < 0 || len >= 100) 341 throw std::runtime_error{"The energy could not be transformed into a string."}; 342 std::ranges::copy(str.data(), str.data() + len, stream_it); 347 detail::write_eol(stream_it, options.add_carriage_return); 349 else if constexpr (!detail::decays_to_ignore_v<energy_type>) 351 throw std::logic_error{"The ENERGY field cannot be written to a Vienna file without providing STRUCTURE."}; 362 template <typename alph_type, typename stream_view_type> 363 auto read_structure(stream_view_type & stream_view) 365 auto constexpr is_legal_structure = is_in_alphabet<alph_type>; 366 return stream_view | views::take_until(is_space) // until whitespace 367 | std::views::transform([is_legal_structure](char const c) 369 if (!is_legal_structure(c)) 372 std::string{"Encountered an unexpected letter: "} + 373 is_legal_structure.msg + 374 " evaluated to false on " + detail::make_printable(c)}; 377 }) // enforce legal alphabet 378 | views::char_to<alph_type>; // convert to actual target alphabet 382 } // namespace seqan3::detail
Provides seqan3::views::istreambuf.
Base pair probability matrix of interactions, usually a matrix of float numbers.
Provides various shortcuts for common std::ranges functions.
Provides seqan3::views::to.
Provides seqan3::views::take.
The main SeqAn3 namespace.
The "sequence", usually a range of nucleotides or amino acids.
Provides seqan3::views::take_line and seqan3::views::take_line_or_throw.
Helper functions (e.g. conversions) for the structure IO submodule.
Energy of a folded sequence, represented by one float number.
Provides seqan3::structure_file_output_options.
Provides seqan3::views::take_until and seqan3::views::take_until_or_throw.
Provides alphabet adaptations for standard char types.
Provides various utility functions.
Provides various utility functions.
Provides seqan3::views::char_to.
Comment field of arbitrary content, usually a string.
Adaptations of concepts from the Ranges TS.
Reactivity error values given in a vector corresponding to REACT.
Provides the WUSS format for RNA structure.
Sequence (SEQ) relative start position (0-based), unsigned value.
Provides character predicates for tokenisation.
Provides seqan3::ostream and seqan3::ostreambuf iterator.
Fixed interactions, usually a string of structure alphabet characters.
Reactivity values of the sequence characters given in a vector of float numbers.
Adaptations of algorithms from the Ranges TS.
Provides seqan3::views::to_char.
Provides various transformation traits used by the range module.
constexpr auto istreambuf
A view factory that returns a view over the stream buffer of an input stream.
Definition: istreambuf.hpp:113