SeqAn3 3.1.0
The Modern C++ library for sequence analysis.
translate.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2021, Knut Reinert & MPI für molekulare Genetik
4// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6// -----------------------------------------------------------------------------------------------------
7
13#pragma once
14
15#include <seqan3/std/concepts>
16#include <seqan3/std/ranges>
17#include <vector>
18#include <stdexcept>
19
28
29// ============================================================================
30// forwards
31// ============================================================================
32
33namespace seqan3::detail
34{
35
36template <std::ranges::view urng_t>
38 requires std::ranges::sized_range<urng_t> &&
39 std::ranges::random_access_range<urng_t> &&
42class view_translate;
43
44template <std::ranges::view urng_t>
46 requires std::ranges::sized_range<urng_t> &&
47 std::ranges::random_access_range<urng_t> &&
50class view_translate_single;
51
52} // namespace seqan3::detail
53
54// ============================================================================
55// translation_frames
56// ============================================================================
57
58namespace seqan3
59{
60
67enum class translation_frames : uint8_t
68{
69 forward_frame0 = 1,
70 forward_frame1 = 1 << 1,
71 forward_frame2 = 1 << 2,
72 reverse_frame0 = 1 << 3,
73 reverse_frame1 = 1 << 4,
74 reverse_frame2 = 1 << 5,
81};
82
86template <>
87constexpr bool add_enum_bitwise_operators<translation_frames> = true;
89
90}
91
92namespace seqan3::detail
93{
94
95// ============================================================================
96// translate_fn (adaptor definition for both views)
97// ============================================================================
98
102template <bool single>
103struct translate_fn
104{
106 static constexpr translation_frames default_frames = single ?
109
111 constexpr auto operator()(translation_frames const tf = default_frames) const
112 {
113 return detail::adaptor_from_functor{*this, tf};
114 }
115
121 template <std::ranges::range urng_t>
122 constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
123 {
124 static_assert(std::ranges::viewable_range<urng_t>,
125 "The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
126 static_assert(std::ranges::sized_range<urng_t>,
127 "The range parameter to views::translate[_single] must model std::ranges::sized_range.");
128 static_assert(std::ranges::random_access_range<urng_t>,
129 "The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
131 "The range parameter to views::translate[_single] must be over elements of seqan3::nucleotide_alphabet.");
132
133 if constexpr (single)
134 return detail::view_translate_single{std::forward<urng_t>(urange), tf};
135 else
136 return detail::view_translate{std::forward<urng_t>(urange), tf};
137 }
138
140 template <std::ranges::range urng_t>
141 constexpr friend auto operator|(urng_t && urange, translate_fn const & me)
142 {
143 return me(std::forward<urng_t>(urange));
144 }
145};
146
147// ============================================================================
148// view_translate_single (range definition)
149// ============================================================================
150
157template <std::ranges::view urng_t>
159 requires std::ranges::sized_range<urng_t> &&
160 std::ranges::random_access_range<urng_t> &&
163class view_translate_single : public std::ranges::view_base
164{
165private:
167 urng_t urange;
171 static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of "
172 "forward_frame0, reverse_frame0, forward_frame1, "
173 "reverse_frame1, forward_frame2 and reverse_frame2."};
174public:
179 using reference = aa27;
181 using const_reference = aa27;
183 using value_type = aa27;
185 using size_type = std::ranges::range_size_t<urng_t>;
187 using difference_type = std::ranges::range_difference_t<urng_t>;
189 using iterator = detail::random_access_iterator<view_translate_single>;
191 using const_iterator = detail::random_access_iterator<view_translate_single const>;
193
197 view_translate_single() noexcept = default;
198 constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
199 constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
200 constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
201 constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
202 ~view_translate_single() noexcept = default;
203
204
213 view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::forward_frame0)
214 : urange{std::move(_urange)}, tf{_tf}
215 {
216 if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
217 {
218 throw std::invalid_argument(multiple_frame_error.c_str());
219 }
220 }
221
230 template <typename rng_t>
232 requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>) &&
233 std::ranges::viewable_range<rng_t> &&
234 std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
236 view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::forward_frame0)
237 : view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
238 {}
240
257 iterator begin() noexcept
258 {
259 return {*this, 0};
260 }
261
263 const_iterator begin() const noexcept
264 {
265 return {*this, 0};
266 }
267
281 iterator end() noexcept
282 {
283 return {*this, size()};
284 }
285
287 const_iterator end() const noexcept
288 {
289 return {*this, size()};
290 }
292
304 size_type size()
305 {
306 switch (tf)
307 {
309 [[fallthrough]];
311 return std::ranges::size(urange) / 3;
312 break;
314 [[fallthrough]];
316 return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
317 break;
319 [[fallthrough]];
321 return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
322 break;
323 default:
324 throw std::invalid_argument(multiple_frame_error.c_str());
325 break;
326 }
327 }
328
330 size_type size() const
331 {
332 switch (tf)
333 {
335 [[fallthrough]];
337 return std::ranges::size(urange) / 3;
338 break;
340 [[fallthrough]];
342 return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
343 break;
345 [[fallthrough]];
347 return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
348 break;
349 default:
350 throw std::invalid_argument(multiple_frame_error.c_str());
351 break;
352 }
353 }
354
373 reference operator[](size_type const n)
374 {
375 // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
376 // we catch that error in debug-builds to make this function consistent with the behaviour in
377 // release-builds (-DNDEBUG).
378#ifndef NDEBUG
379 try { assert(n < size()); } catch (std::invalid_argument const &) {}
380#endif
381
382 switch (tf)
383 {
385 return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
386 break;
388 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
389 complement((urange)[(urange).size() - n * 3 - 2]),
390 complement((urange)[(urange).size() - n * 3 - 3]));
391 break;
393 return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
394 break;
396 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
397 complement((urange)[(urange).size() - n * 3 - 3]),
398 complement((urange)[(urange).size() - n * 3 - 4]));
399 break;
401 return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
402 break;
404 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
405 complement((urange)[(urange).size() - n * 3 - 4]),
406 complement((urange)[(urange).size() - n * 3 - 5]));
407 break;
408 default:
409 throw std::invalid_argument(multiple_frame_error.c_str());
410 break;
411 }
412 }
413
415 const_reference operator[](size_type const n) const
416 {
417 // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
418 // we catch that error in debug-builds to make this function consistent with the behaviour in
419 // release-builds (-DNDEBUG).
420#ifndef NDEBUG
421 try { assert(n < size()); } catch (std::invalid_argument const &) {}
422#endif
423
424 switch (tf)
425 {
427 return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
428 break;
430 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
431 complement((urange)[(urange).size() - n * 3 - 2]),
432 complement((urange)[(urange).size() - n * 3 - 3]));
433 break;
435 return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
436 break;
438 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
439 complement((urange)[(urange).size() - n * 3 - 3]),
440 complement((urange)[(urange).size() - n * 3 - 4]));
441 break;
443 return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
444 break;
446 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
447 complement((urange)[(urange).size() - n * 3 - 4]),
448 complement((urange)[(urange).size() - n * 3 - 5]));
449 break;
450 default:
451 throw std::invalid_argument(multiple_frame_error.c_str());
452 break;
453 }
454 }
456};
457
459template <typename urng_t>
460view_translate_single(urng_t &&, translation_frames const) -> view_translate_single<std::views::all_t<urng_t>>;
461
462
464template <typename urng_t>
465view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
466
467} // namespace seqan3::detail
468
469// ============================================================================
470// translate_single (adaptor object)
471// ============================================================================
472
473namespace seqan3::views
474{
475
524inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
525
526} // seqan3::views
527
528// ============================================================================
529// view_translate (range definition)
530// ============================================================================
531
532namespace seqan3::detail
533{
534
543template <std::ranges::view urng_t>
545 requires std::ranges::sized_range<urng_t> &&
546 std::ranges::random_access_range<urng_t> &&
549class view_translate : public std::ranges::view_base
550{
551private:
553 urng_t urange;
557 small_vector<translation_frames, 6> selected_frames{};
558
559public:
564 using reference = view_translate_single<urng_t>;
566 using const_reference = reference;
568 using value_type = reference;
570 using size_type = std::ranges::range_size_t<urng_t>;
572 using difference_type = std::ranges::range_difference_t<urng_t>;
574 using iterator = detail::random_access_iterator<view_translate>;
576 using const_iterator = detail::random_access_iterator<view_translate const>;
578
579protected:
586 // unfortunately we cannot specialise the variable template so we have to add an auxiliary here
587 template <typename t>
588 requires (range_dimension_v<t> == range_dimension_v<value_type> + 1) &&
589 std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
590 std::remove_cvref_t<range_innermost_value_t<t>>>
591 static constexpr bool is_compatible_this_aux = true;
594
595public:
596
600 view_translate() noexcept = default;
601 constexpr view_translate(view_translate const & rhs) noexcept = default;
602 constexpr view_translate(view_translate && rhs) noexcept = default;
603 constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
604 constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
605 ~view_translate() noexcept = default;
606
611 view_translate(urng_t _urange, translation_frames const _tf = translation_frames::six_frames)
612 : urange{std::move(_urange)}, tf{_tf}
613 {
615 selected_frames.push_back(translation_frames::forward_frame0);
617 selected_frames.push_back(translation_frames::forward_frame1);
619 selected_frames.push_back(translation_frames::forward_frame2);
621 selected_frames.push_back(translation_frames::reverse_frame0);
623 selected_frames.push_back(translation_frames::reverse_frame1);
625 selected_frames.push_back(translation_frames::reverse_frame2);
626 }
627
632 template <typename rng_t>
634 requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) &&
635 std::ranges::viewable_range<rng_t> &&
636 std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
638 view_translate(rng_t && _urange, translation_frames const _tf)
639 : view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
640 {}
642
659 iterator begin() noexcept
660 {
661 return {*this, 0};
662 }
663
665 const_iterator begin() const noexcept
666 {
667 return {*this, 0};
668 }
669
683 iterator end() noexcept
684 {
685 return {*this, size()};
686 }
687
689 const_iterator end() const noexcept
690 {
691 return {*this, size()};
692 }
693
705 size_type size() noexcept
706 {
707 return (size_type) selected_frames.size();
708 }
709
711 size_type size() const noexcept
712 {
713 return (size_type) selected_frames.size();
714 }
715
734 reference operator[](size_type const n)
735 {
736 assert(n < size());
737 return urange | views::translate_single(selected_frames[n]);
738 }
739
741 const_reference operator[](size_type const n) const
742 {
743 assert(n < size());
744 return urange | views::translate_single(selected_frames[n]);
745 }
747};
748
750template <typename urng_t>
752 requires std::ranges::sized_range<urng_t> &&
753 std::ranges::random_access_range<urng_t> &&
756view_translate(urng_t &&, translation_frames const) -> view_translate<std::views::all_t<urng_t>>;
757} // namespace seqan3::detail
758
759// ============================================================================
760// translate (adaptor object)
761// ============================================================================
762
763namespace seqan3::views
764{
813inline constexpr auto translate = deep{detail::translate_fn<false>{}};
814
815} // namespace seqan3::views
Provides seqan3::aa27, container aliases and string literals.
Provides seqan3::detail::adaptor_from_functor.
Provides seqan3::add_enum_bitwise_operators.
T begin(T... args)
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition: deep.hpp:104
The <concepts> header from C++20's standard library.
Provides various transformation traits used by the range module.
Provides seqan3::views::deep.
Provides seqan3::dna5, container aliases and string literals.
T end(T... args)
constexpr aa27 translate_triplet(nucl_type const &n1, nucl_type const &n2, nucl_type const &n3) noexcept
Translate one nucleotide triplet into single amino acid (single nucleotide interface).
Definition: translation.hpp:55
constexpr auto complement
Return the complement of a nucleotide object.
Definition: concept.hpp:104
constexpr auto translate
A view that translates nucleotide into aminoacid alphabet with 1, 2, 3 or 6 frames.
Definition: translate.hpp:813
constexpr auto translate_single
A view that translates nucleotide into aminoacid alphabet for one of the six frames.
Definition: translate.hpp:524
auto operator|(validator1_type &&vali1, validator2_type &&vali2)
Enables the chaining of validators.
Definition: validators.hpp:1120
@ single
The text is a single range.
Definition: concept.hpp:74
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
A concept that indicates whether an alphabet represents nucleotides.
T is_same_v
The SeqAn namespace for views.
Definition: char_to.hpp:22
The main SeqAn3 namespace.
Definition: cigar_operation_table.hpp:2
translation_frames
Specialisation values for single and multiple translation frames.
Definition: translate.hpp:68
@ forward_frame2
The third forward frame starting at position 2.
@ forward_frame0
The first forward frame starting at position 0.
@ reverse_frames
All reverse frames.
@ forward_frames
All forward frames.
@ reverse_frame0
The first reverse frame starting at position 0.
@ forward_reverse2
The first third and third reverse frame.
@ reverse_frame2
The third reverse frame starting at position 2.
@ forward_frame1
The second forward frame starting at position 1.
@ reverse_frame1
The second reverse frame starting at position 1.
@ forward_reverse0
The first forward and first reverse frame.
@ forward_reverse1
The second forward and second reverse frame.
The <ranges> header from C++20's standard library.
A constexpr string implementation to manipulate string literals at compile time.
Provides functions for translating a triplet of nucleotides into an amino acid.