SeqAn3  3.0.3
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 
33 namespace seqan3::detail
34 {
35 
36 template <std::ranges::view urng_t>
38  requires std::ranges::sized_range<urng_t> &&
39  std::ranges::random_access_range<urng_t> &&
42 class view_translate;
43 
44 template <std::ranges::view urng_t>
46  requires std::ranges::sized_range<urng_t> &&
47  std::ranges::random_access_range<urng_t> &&
50 class view_translate_single;
51 
52 } // namespace seqan3::detail
53 
54 // ============================================================================
55 // translation_frames
56 // ============================================================================
57 
58 namespace seqan3
59 {
60 
67 enum 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 #ifdef SEQAN3_DEPRECATED_310
95 #endif // SEQAN3_DEPRECATED_310
96 };
97 
101 template <>
102 constexpr bool add_enum_bitwise_operators<translation_frames> = true;
104 
105 }
106 
107 namespace seqan3::detail
108 {
109 
110 // ============================================================================
111 // translate_fn (adaptor definition for both views)
112 // ============================================================================
113 
117 template <bool single>
118 struct translate_fn
119 {
121  static constexpr translation_frames default_frames = single ?
124 
126  constexpr auto operator()(translation_frames const tf = default_frames) const
127  {
128  return detail::adaptor_from_functor{*this, tf};
129  }
130 
136  template <std::ranges::range urng_t>
137  constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
138  {
139  static_assert(std::ranges::viewable_range<urng_t>,
140  "The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
141  static_assert(std::ranges::sized_range<urng_t>,
142  "The range parameter to views::translate[_single] must model std::ranges::sized_range.");
143  static_assert(std::ranges::random_access_range<urng_t>,
144  "The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
145  static_assert(nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>,
146  "The range parameter to views::translate[_single] must be over elements of seqan3::nucleotide_alphabet.");
147 
148  if constexpr (single)
149  return detail::view_translate_single{std::forward<urng_t>(urange), tf};
150  else
151  return detail::view_translate{std::forward<urng_t>(urange), tf};
152  }
153 
155  template <std::ranges::range urng_t>
156  constexpr friend auto operator|(urng_t && urange, translate_fn const & me)
157  {
158  return me(std::forward<urng_t>(urange));
159  }
160 };
161 
162 // ============================================================================
163 // view_translate_single (range definition)
164 // ============================================================================
165 
172 template <std::ranges::view urng_t>
174  requires std::ranges::sized_range<urng_t> &&
175  std::ranges::random_access_range<urng_t> &&
178 class view_translate_single : public std::ranges::view_base
179 {
180 private:
182  urng_t urange;
186  static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of "
187  "forward_frame0, reverse_frame0, forward_frame1, "
188  "reverse_frame1, forward_frame2 and reverse_frame2."};
189 public:
194  using reference = aa27;
196  using const_reference = aa27;
198  using value_type = aa27;
200  using size_type = std::ranges::range_size_t<urng_t>;
202  using difference_type = std::ranges::range_difference_t<urng_t>;
204  using iterator = detail::random_access_iterator<view_translate_single>;
206  using const_iterator = detail::random_access_iterator<view_translate_single const>;
208 
212  view_translate_single() noexcept = default;
213  constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
214  constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
215  constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
216  constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
217  ~view_translate_single() noexcept = default;
218 
219 
228  view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::forward_frame0)
229  : urange{std::move(_urange)}, tf{_tf}
230  {
231  if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
232  {
233  throw std::invalid_argument(multiple_frame_error.c_str());
234  }
235  }
236 
245  template <typename rng_t>
247  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>) &&
248  std::ranges::viewable_range<rng_t> &&
249  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
251  view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::forward_frame0)
252  : view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
253  {}
255 
272  iterator begin() noexcept
273  {
274  return {*this, 0};
275  }
276 
278  const_iterator begin() const noexcept
279  {
280  return {*this, 0};
281  }
282 
296  iterator end() noexcept
297  {
298  return {*this, size()};
299  }
300 
302  const_iterator end() const noexcept
303  {
304  return {*this, size()};
305  }
307 
319  size_type size()
320  {
321  switch (tf)
322  {
324  [[fallthrough]];
326  return std::ranges::size(urange) / 3;
327  break;
329  [[fallthrough]];
331  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
332  break;
334  [[fallthrough]];
336  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
337  break;
338  default:
339  throw std::invalid_argument(multiple_frame_error.c_str());
340  break;
341  }
342  }
343 
345  size_type size() const
346  {
347  switch (tf)
348  {
350  [[fallthrough]];
352  return std::ranges::size(urange) / 3;
353  break;
355  [[fallthrough]];
357  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
358  break;
360  [[fallthrough]];
362  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
363  break;
364  default:
365  throw std::invalid_argument(multiple_frame_error.c_str());
366  break;
367  }
368  }
369 
388  reference operator[](size_type const n)
389  {
390  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
391  // we catch that error in debug-builds to make this function consistent with the behaviour in
392  // release-builds (-DNDEBUG).
393 #ifndef NDEBUG
394  try { assert(n < size()); } catch (std::invalid_argument const &) {}
395 #endif
396 
397  switch (tf)
398  {
400  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
401  break;
403  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
404  complement((urange)[(urange).size() - n * 3 - 2]),
405  complement((urange)[(urange).size() - n * 3 - 3]));
406  break;
408  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
409  break;
411  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
412  complement((urange)[(urange).size() - n * 3 - 3]),
413  complement((urange)[(urange).size() - n * 3 - 4]));
414  break;
416  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
417  break;
419  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
420  complement((urange)[(urange).size() - n * 3 - 4]),
421  complement((urange)[(urange).size() - n * 3 - 5]));
422  break;
423  default:
424  throw std::invalid_argument(multiple_frame_error.c_str());
425  break;
426  }
427  }
428 
430  const_reference operator[](size_type const n) const
431  {
432  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
433  // we catch that error in debug-builds to make this function consistent with the behaviour in
434  // release-builds (-DNDEBUG).
435 #ifndef NDEBUG
436  try { assert(n < size()); } catch (std::invalid_argument const &) {}
437 #endif
438 
439  switch (tf)
440  {
442  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
443  break;
445  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]),
446  complement((urange)[(urange).size() - n * 3 - 2]),
447  complement((urange)[(urange).size() - n * 3 - 3]));
448  break;
450  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
451  break;
453  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]),
454  complement((urange)[(urange).size() - n * 3 - 3]),
455  complement((urange)[(urange).size() - n * 3 - 4]));
456  break;
458  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
459  break;
461  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]),
462  complement((urange)[(urange).size() - n * 3 - 4]),
463  complement((urange)[(urange).size() - n * 3 - 5]));
464  break;
465  default:
466  throw std::invalid_argument(multiple_frame_error.c_str());
467  break;
468  }
469  }
471 };
472 
474 template <typename urng_t>
475 view_translate_single(urng_t &&, translation_frames const) -> view_translate_single<std::views::all_t<urng_t>>;
476 
477 
479 template <typename urng_t>
480 view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
481 
482 } // namespace seqan3::detail
483 
484 // ============================================================================
485 // translate_single (adaptor object)
486 // ============================================================================
487 
488 namespace seqan3::views
489 {
490 
539 inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
540 
541 } // seqan3::views
542 
543 // ============================================================================
544 // view_translate (range definition)
545 // ============================================================================
546 
547 namespace seqan3::detail
548 {
549 
558 template <std::ranges::view urng_t>
560  requires std::ranges::sized_range<urng_t> &&
561  std::ranges::random_access_range<urng_t> &&
564 class view_translate : public std::ranges::view_base
565 {
566 private:
568  urng_t urange;
572  small_vector<translation_frames, 6> selected_frames{};
573 
574 public:
579  using reference = view_translate_single<urng_t>;
581  using const_reference = reference;
583  using value_type = reference;
585  using size_type = std::ranges::range_size_t<urng_t>;
587  using difference_type = std::ranges::range_difference_t<urng_t>;
589  using iterator = detail::random_access_iterator<view_translate>;
591  using const_iterator = detail::random_access_iterator<view_translate const>;
593 
594 protected:
601  // unfortunately we cannot specialise the variable template so we have to add an auxiliary here
602  template <typename t>
603  requires (range_dimension_v<t> == range_dimension_v<value_type> + 1) &&
604  std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
606  static constexpr bool is_compatible_this_aux = true;
609 
610 public:
611 
615  view_translate() noexcept = default;
616  constexpr view_translate(view_translate const & rhs) noexcept = default;
617  constexpr view_translate(view_translate && rhs) noexcept = default;
618  constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
619  constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
620  ~view_translate() noexcept = default;
621 
626  view_translate(urng_t _urange, translation_frames const _tf = translation_frames::six_frames)
627  : urange{std::move(_urange)}, tf{_tf}
628  {
630  selected_frames.push_back(translation_frames::forward_frame0);
632  selected_frames.push_back(translation_frames::forward_frame1);
634  selected_frames.push_back(translation_frames::forward_frame2);
636  selected_frames.push_back(translation_frames::reverse_frame0);
638  selected_frames.push_back(translation_frames::reverse_frame1);
640  selected_frames.push_back(translation_frames::reverse_frame2);
641  }
642 
647  template <typename rng_t>
649  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) &&
650  std::ranges::viewable_range<rng_t> &&
651  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
653  view_translate(rng_t && _urange, translation_frames const _tf)
654  : view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
655  {}
656 
658  #ifdef SEQAN3_DEPRECATED_310
659  template <typename rng_t>
661  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) &&
662  std::ranges::viewable_range<rng_t> &&
663  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
665  view_translate(rng_t && _urange)
666  : view_translate{std::views::all(std::forward<rng_t>(_urange)), translation_frames::six_frames}
667  {}
668  #endif // SEQAN3_DEPRECATED_310
670 
687  iterator begin() noexcept
688  {
689  return {*this, 0};
690  }
691 
693  const_iterator begin() const noexcept
694  {
695  return {*this, 0};
696  }
697 
711  iterator end() noexcept
712  {
713  return {*this, size()};
714  }
715 
717  const_iterator end() const noexcept
718  {
719  return {*this, size()};
720  }
721 
733  size_type size() noexcept
734  {
735  return (size_type) selected_frames.size();
736  }
737 
739  size_type size() const noexcept
740  {
741  return (size_type) selected_frames.size();
742  }
743 
762  reference operator[](size_type const n)
763  {
764  assert(n < size());
765  return urange | views::translate_single(selected_frames[n]);
766  }
767 
769  const_reference operator[](size_type const n) const
770  {
771  assert(n < size());
772  return urange | views::translate_single(selected_frames[n]);
773  }
775 };
776 
780 #ifdef SEQAN3_DEPRECATED_310
781 template <typename urng_t>
783  requires std::ranges::sized_range<urng_t> &&
784  std::ranges::random_access_range<urng_t> &&
787 view_translate (urng_t &&) -> view_translate<std::views::all_t<urng_t>>;
788 #endif // SEQAN3_DEPRECATED_310
789 
791 template <typename urng_t>
793  requires std::ranges::sized_range<urng_t> &&
794  std::ranges::random_access_range<urng_t> &&
797 view_translate(urng_t &&, translation_frames const) -> view_translate<std::views::all_t<urng_t>>;
798 } // namespace seqan3::detail
799 
800 // ============================================================================
801 // translate (adaptor object)
802 // ============================================================================
803 
804 namespace seqan3::views
805 {
806 
859 inline constexpr auto translate = deep{detail::translate_fn<false>{}};
861 
862 } // 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 library.
Provides various transformation traits used by the range module.
Provides seqan3::dna5, container aliases and string literals.
T end(T... args)
T forward(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
auto operator|(validator1_type &&vali1, validator2_type &&vali2)
Enables the chaining of validators.
Definition: validators.hpp:1103
constexpr auto complement
Return the complement of a nucleotide object.
Definition: concept.hpp:104
@ single
The text is a single range.
Definition: concept.hpp:83
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto translate
A view that translates nucleotide into aminoacid alphabet with 1, 2, 3 or 6 frames.
Definition: translate.hpp:859
constexpr auto translate_single
A view that translates nucleotide into aminoacid alphabet for one of the six frames.
Definition: translate.hpp:539
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:74
A concept that indicates whether an alphabet represents nucleotides.
The SeqAn namespace for views.
Definition: char_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: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.
SeqAn specific customisations in the standard namespace.
#define SEQAN3_DEPRECATED_310
Deprecation message for SeqAn 3.1.0 release.
Definition: platform.hpp:203
Adaptations of concepts from the Ranges TS.
Provides functions for translating a triplet of nucleotides into an amino acid.
A constexpr string implementation to manipulate string literals at compile time.
Provides seqan3::views::deep.