SeqAn3 3.2.0
The Modern C++ library for sequence analysis.
translate.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2022, 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 <concepts>
16#include <ranges>
17#include <stdexcept>
18#include <vector>
19
28
29// ============================================================================
30// forwards
31// ============================================================================
32
33namespace seqan3::detail
34{
35
36template <std::ranges::view urng_t>
37 requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
39class view_translate;
40
41template <std::ranges::view urng_t>
42 requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
44class view_translate_single;
45
46} // namespace seqan3::detail
47
48// ============================================================================
49// translation_frames
50// ============================================================================
51
52namespace seqan3
53{
54
61enum class translation_frames : uint8_t
62{
63 forward_frame0 = 1,
64 forward_frame1 = 1 << 1,
65 forward_frame2 = 1 << 2,
66 reverse_frame0 = 1 << 3,
67 reverse_frame1 = 1 << 4,
68 reverse_frame2 = 1 << 5,
75};
76
80template <>
81constexpr bool add_enum_bitwise_operators<translation_frames> = true;
83
84} // namespace seqan3
85
86namespace seqan3::detail
87{
88
89// ============================================================================
90// translate_fn (adaptor definition for both views)
91// ============================================================================
92
96template <bool single>
97struct translate_fn
98{
100 static constexpr translation_frames default_frames =
102
104 constexpr auto operator()(translation_frames const tf = default_frames) const
105 {
106 return detail::adaptor_from_functor{*this, tf};
107 }
108
114 template <std::ranges::range urng_t>
115 constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
116 {
117 static_assert(std::ranges::viewable_range<urng_t>,
118 "The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
119 static_assert(std::ranges::sized_range<urng_t>,
120 "The range parameter to views::translate[_single] must model std::ranges::sized_range.");
121 static_assert(std::ranges::random_access_range<urng_t>,
122 "The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
123 static_assert(
125 "The range parameter to views::translate[_single] must be over elements of seqan3::nucleotide_alphabet.");
126
127 if constexpr (single)
128 return detail::view_translate_single{std::forward<urng_t>(urange), tf};
129 else
130 return detail::view_translate{std::forward<urng_t>(urange), tf};
131 }
132
134 template <std::ranges::range urng_t>
135 constexpr friend auto operator|(urng_t && urange, translate_fn const & me)
136 {
137 return me(std::forward<urng_t>(urange));
138 }
139};
140
141// ============================================================================
142// view_translate_single (range definition)
143// ============================================================================
144
151template <std::ranges::view urng_t>
152 requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
154class view_translate_single : public std::ranges::view_base
155{
156private:
158 urng_t urange;
162 static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of "
163 "forward_frame0, reverse_frame0, forward_frame1, "
164 "reverse_frame1, forward_frame2 and reverse_frame2."};
165
166public:
171 using reference = aa27;
173 using const_reference = aa27;
175 using value_type = aa27;
177 using size_type = std::ranges::range_size_t<urng_t>;
179 using difference_type = std::ranges::range_difference_t<urng_t>;
181 using iterator = detail::random_access_iterator<view_translate_single>;
183 using const_iterator = detail::random_access_iterator<view_translate_single const>;
185
189 view_translate_single() noexcept = default;
190 constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
191 constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
192 constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
193 constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
194 ~view_translate_single() noexcept = default;
195
204 view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::forward_frame0) :
205 urange{std::move(_urange)},
206 tf{_tf}
207 {
208 if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
209 {
210 throw std::invalid_argument(multiple_frame_error.c_str());
211 }
212 }
213
222 template <typename rng_t>
223 requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>)
224 && std::ranges::viewable_range<rng_t>
225 && std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
226 view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::forward_frame0) :
227 view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
228 {}
230
247 iterator begin() noexcept
248 {
249 return {*this, 0};
250 }
251
253 const_iterator begin() const noexcept
254 {
255 return {*this, 0};
256 }
257
271 iterator end() noexcept
272 {
273 return {*this, size()};
274 }
275
277 const_iterator end() const noexcept
278 {
279 return {*this, size()};
280 }
282
294 size_type size()
295 {
296 switch (tf)
297 {
299 [[fallthrough]];
301 return std::ranges::size(urange) / 3;
302 break;
304 [[fallthrough]];
306 return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
307 break;
309 [[fallthrough]];
311 return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
312 break;
313 default:
314 throw std::invalid_argument(multiple_frame_error.c_str());
315 break;
316 }
317 }
318
320 size_type size() const
321 {
322 switch (tf)
323 {
325 [[fallthrough]];
327 return std::ranges::size(urange) / 3;
328 break;
330 [[fallthrough]];
332 return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
333 break;
335 [[fallthrough]];
337 return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
338 break;
339 default:
340 throw std::invalid_argument(multiple_frame_error.c_str());
341 break;
342 }
343 }
344
363 reference operator[](size_type const n)
364 {
365 // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
366 // we catch that error in debug-builds to make this function consistent with the behaviour in
367 // release-builds (-DNDEBUG).
368#ifndef NDEBUG
369 try
370 {
371 assert(n < size());
372 }
373 catch (std::invalid_argument const &)
374 {}
375#endif
376
377 switch (tf)
378 {
380 return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
381 break;
383 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
384 complement((urange)[(urange).size() - n * 3 - 2]),
385 complement((urange)[(urange).size() - n * 3 - 3]));
386 break;
388 return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
389 break;
391 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
392 complement((urange)[(urange).size() - n * 3 - 3]),
393 complement((urange)[(urange).size() - n * 3 - 4]));
394 break;
396 return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
397 break;
399 return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
400 complement((urange)[(urange).size() - n * 3 - 4]),
401 complement((urange)[(urange).size() - n * 3 - 5]));
402 break;
403 default:
404 throw std::invalid_argument(multiple_frame_error.c_str());
405 break;
406 }
407 }
408
410 const_reference operator[](size_type const n) const
411 {
412 // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
413 // we catch that error in debug-builds to make this function consistent with the behaviour in
414 // release-builds (-DNDEBUG).
415#ifndef NDEBUG
416 try
417 {
418 assert(n < size());
419 }
420 catch (std::invalid_argument const &)
421 {}
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
463template <typename urng_t>
464view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
465
466} // namespace seqan3::detail
467
468// ============================================================================
469// translate_single (adaptor object)
470// ============================================================================
471
472namespace seqan3::views
473{
474
523inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
524
525} // namespace seqan3::views
526
527// ============================================================================
528// view_translate (range definition)
529// ============================================================================
530
531namespace seqan3::detail
532{
533
542template <std::ranges::view urng_t>
543 requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
545class view_translate : public std::ranges::view_base
546{
547private:
549 urng_t urange;
553 small_vector<translation_frames, 6> selected_frames{};
554
555public:
560 using reference = view_translate_single<urng_t>;
562 using const_reference = reference;
564 using value_type = reference;
566 using size_type = std::ranges::range_size_t<urng_t>;
568 using difference_type = std::ranges::range_difference_t<urng_t>;
570 using iterator = detail::random_access_iterator<view_translate>;
572 using const_iterator = detail::random_access_iterator<view_translate const>;
574
575protected:
582 // unfortunately we cannot specialise the variable template so we have to add an auxiliary here
583 template <typename t>
584 requires (range_dimension_v<t> == range_dimension_v<value_type> + 1)
585 && std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
586 std::remove_cvref_t<range_innermost_value_t<t>>>
587 static constexpr bool is_compatible_this_aux = true;
590
591public:
595 view_translate() noexcept = default;
596 constexpr view_translate(view_translate const & rhs) noexcept = default;
597 constexpr view_translate(view_translate && rhs) noexcept = default;
598 constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
599 constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
600 ~view_translate() noexcept = default;
601
606 view_translate(urng_t _urange, translation_frames const _tf = translation_frames::six_frames) :
607 urange{std::move(_urange)},
608 tf{_tf}
609 {
611 selected_frames.push_back(translation_frames::forward_frame0);
613 selected_frames.push_back(translation_frames::forward_frame1);
615 selected_frames.push_back(translation_frames::forward_frame2);
617 selected_frames.push_back(translation_frames::reverse_frame0);
619 selected_frames.push_back(translation_frames::reverse_frame1);
621 selected_frames.push_back(translation_frames::reverse_frame2);
622 }
623
628 template <typename rng_t>
629 requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) && std::ranges::viewable_range<rng_t>
630 && std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
631 view_translate(rng_t && _urange, translation_frames const _tf) :
632 view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
633 {}
635
652 iterator begin() noexcept
653 {
654 return {*this, 0};
655 }
656
658 const_iterator begin() const noexcept
659 {
660 return {*this, 0};
661 }
662
676 iterator end() noexcept
677 {
678 return {*this, size()};
679 }
680
682 const_iterator end() const noexcept
683 {
684 return {*this, size()};
685 }
686
698 size_type size() noexcept
699 {
700 return (size_type)selected_frames.size();
701 }
702
704 size_type size() const noexcept
705 {
706 return (size_type)selected_frames.size();
707 }
708
727 reference operator[](size_type const n)
728 {
729 assert(n < size());
730 return urange | views::translate_single(selected_frames[n]);
731 }
732
734 const_reference operator[](size_type const n) const
735 {
736 assert(n < size());
737 return urange | views::translate_single(selected_frames[n]);
738 }
740};
741
743template <typename urng_t>
744 requires std::ranges::sized_range<urng_t> && std::ranges::random_access_range<urng_t>
746 view_translate(urng_t &&, translation_frames const) -> view_translate<std::views::all_t<urng_t>>;
747} // namespace seqan3::detail
748
749// ============================================================================
750// translate (adaptor object)
751// ============================================================================
752
753namespace seqan3::views
754{
803inline constexpr auto translate = deep{detail::translate_fn<false>{}};
804
805} // 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
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:105
constexpr auto translate
A view that translates nucleotide into aminoacid alphabet with 1, 2, 3 or 6 frames.
Definition: translate.hpp:803
constexpr auto translate_single
A view that translates nucleotide into aminoacid alphabet for one of the six frames.
Definition: translate.hpp:523
auto operator|(validator1_type &&vali1, validator2_type &&vali2)
Enables the chaining of validators.
Definition: validators.hpp:1124
@ single
The text is a single range.
Definition: concept.hpp:93
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:146
A concept that indicates whether an alphabet represents nucleotides.
T is_same_v
The SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
translation_frames
Specialisation values for single and multiple translation frames.
Definition: translate.hpp:62
@ 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.
A constexpr string implementation to manipulate string literals at compile time.
Provides functions for translating a triplet of nucleotides into an amino acid.