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-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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 
30 
31 // ============================================================================
32 // forwards
33 // ============================================================================
34 
35 namespace seqan3::detail
36 {
37 
38 template <std::ranges::view urng_t>
40  requires std::ranges::sized_range<urng_t> &&
41  std::ranges::random_access_range<urng_t> &&
44 class view_translate;
45 
46 template <std::ranges::view urng_t>
48  requires std::ranges::sized_range<urng_t> &&
49  std::ranges::random_access_range<urng_t> &&
52 class view_translate_single;
53 
54 } // namespace seqan3::detail
55 
56 // ============================================================================
57 // translation_frames
58 // ============================================================================
59 
60 namespace seqan3
61 {
62 
69 enum class translation_frames : uint8_t
70 {
71  FWD_FRAME_0 = 1,
72  FWD_FRAME_1 = 1 << 1,
73  FWD_FRAME_2 = 1 << 2,
74  REV_FRAME_0 = 1 << 3,
75  REV_FRAME_1 = 1 << 4,
76  REV_FRAME_2 = 1 << 5,
82  SIX_FRAME = FWD | REV
83 };
84 
88 template <>
89 constexpr bool add_enum_bitwise_operators<translation_frames> = true;
91 
92 }
93 
94 namespace seqan3::detail
95 {
96 
97 // ============================================================================
98 // translate_fn (adaptor definition for both views)
99 // ============================================================================
100 
104 template <bool single>
105 struct translate_fn
106 {
108  static constexpr translation_frames default_frames = single ?
111 
113  constexpr auto operator()(translation_frames const tf = default_frames) const
114  {
115  return detail::adaptor_from_functor{*this, tf};
116  }
117 
123  template <std::ranges::range urng_t>
124  constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
125  {
126  static_assert(std::ranges::viewable_range<urng_t>,
127  "The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
128  static_assert(std::ranges::sized_range<urng_t>,
129  "The range parameter to views::translate[_single] must model std::ranges::sized_range.");
130  static_assert(std::ranges::random_access_range<urng_t>,
131  "The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
132  static_assert(nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>,
133  "The range parameter to views::translate[_single] must be over elements of seqan3::nucleotide_alphabet.");
134 
135  if constexpr (single)
136  return detail::view_translate_single{std::forward<urng_t>(urange), tf};
137  else
138  return detail::view_translate{std::forward<urng_t>(urange), tf};
139  }
140 
142  template <std::ranges::range urng_t>
143  constexpr friend auto operator|(urng_t && urange, translate_fn const & me)
144  {
145  return me(std::forward<urng_t>(urange));
146  }
147 };
148 
149 // ============================================================================
150 // view_translate_single (range definition)
151 // ============================================================================
152 
159 template <std::ranges::view urng_t>
161  requires std::ranges::sized_range<urng_t> &&
162  std::ranges::random_access_range<urng_t> &&
165 class view_translate_single : public std::ranges::view_base
166 {
167 private:
169  urng_t urange;
173  static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of FWD_FRAME_0, "
174  "REV_FRAME_0, FWD_FRAME_1, REV_FRAME_1, FWD_FRAME_2 and "
175  "REV_FRAME_2."};
176 public:
181  using reference = aa27;
183  using const_reference = aa27;
185  using value_type = aa27;
187  using size_type = std::ranges::range_size_t<urng_t>;
189  using difference_type = std::ranges::range_difference_t<urng_t>;
191  using iterator = detail::random_access_iterator<view_translate_single>;
193  using const_iterator = detail::random_access_iterator<view_translate_single const>;
195 
199  view_translate_single() noexcept = default;
200  constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
201  constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
202  constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
203  constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
204  ~view_translate_single() noexcept = default;
205 
206 
215  view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::FWD_FRAME_0)
216  : urange{std::move(_urange)}, tf{_tf}
217  {
218  if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
219  {
220  throw std::invalid_argument(multiple_frame_error.c_str());
221  }
222  }
223 
232  template <typename rng_t>
234  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>) &&
235  std::ranges::viewable_range<rng_t> &&
236  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
238  view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::FWD_FRAME_0)
239  : view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
240  {}
242 
259  iterator begin() noexcept
260  {
261  return {*this, 0};
262  }
263 
265  const_iterator begin() const noexcept
266  {
267  return {*this, 0};
268  }
269 
283  iterator end() noexcept
284  {
285  return {*this, size()};
286  }
287 
289  const_iterator end() const noexcept
290  {
291  return {*this, size()};
292  }
294 
306  size_type size()
307  {
308  switch (tf)
309  {
311  [[fallthrough]];
313  return std::ranges::size(urange) / 3;
314  break;
316  [[fallthrough]];
318  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
319  break;
321  [[fallthrough]];
323  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
324  break;
325  default:
326  throw std::invalid_argument(multiple_frame_error.c_str());
327  break;
328  }
329  }
330 
332  size_type size() const
333  {
334  switch (tf)
335  {
337  [[fallthrough]];
339  return std::ranges::size(urange) / 3;
340  break;
342  [[fallthrough]];
344  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
345  break;
347  [[fallthrough]];
349  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
350  break;
351  default:
352  throw std::invalid_argument(multiple_frame_error.c_str());
353  break;
354  }
355  }
356 
375  reference operator[](size_type const n)
376  {
377  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
378  // we catch that error in debug-builds to make this function consistent with the behaviour in
379  // release-builds (-DNDEBUG).
380 #ifndef NDEBUG
381  try { assert(n < size()); } catch (std::invalid_argument const &) {}
382 #endif
383 
384  switch (tf)
385  {
387  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
388  break;
390  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]), complement((urange)[(urange).size() - n * 3 - 2]), 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]), complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]));
397  break;
399  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
400  break;
402  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]), complement((urange)[(urange).size() - n * 3 - 5]));
403  break;
404  default:
405  throw std::invalid_argument(multiple_frame_error.c_str());
406  break;
407  }
408  }
409 
411  const_reference operator[](size_type const n) const
412  {
413  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
414  // we catch that error in debug-builds to make this function consistent with the behaviour in
415  // release-builds (-DNDEBUG).
416 #ifndef NDEBUG
417  try { assert(n < size()); } catch (std::invalid_argument const &) {}
418 #endif
419 
420  switch (tf)
421  {
423  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
424  break;
426  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]), complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]));
427  break;
429  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
430  break;
432  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]));
433  break;
435  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
436  break;
438  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]), complement((urange)[(urange).size() - n * 3 - 5]));
439  break;
440  default:
441  throw std::invalid_argument(multiple_frame_error.c_str());
442  break;
443  }
444  }
446 };
447 
449 template <typename urng_t>
450 view_translate_single(urng_t &&, translation_frames const) -> view_translate_single<std::views::all_t<urng_t>>;
451 
452 
454 template <typename urng_t>
455 view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
456 
457 } // namespace seqan3::detail
458 
459 // ============================================================================
460 // translate_single (adaptor object)
461 // ============================================================================
462 
463 namespace seqan3::views
464 {
465 
514 inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
515 
516 } // seqan3::views
517 
518 // ============================================================================
519 // view_translate (range definition)
520 // ============================================================================
521 
522 namespace seqan3::detail
523 {
524 
533 template <std::ranges::view urng_t>
535  requires std::ranges::sized_range<urng_t> &&
536  std::ranges::random_access_range<urng_t> &&
539 class view_translate : public std::ranges::view_base
540 {
541 private:
543  urng_t urange;
547  small_vector<translation_frames, 6> selected_frames{};
548 
549 public:
554  using reference = view_translate_single<urng_t>;
556  using const_reference = reference;
558  using value_type = reference;
560  using size_type = std::ranges::range_size_t<urng_t>;
562  using difference_type = std::ranges::range_difference_t<urng_t>;
564  using iterator = detail::random_access_iterator<view_translate>;
566  using const_iterator = detail::random_access_iterator<view_translate const>;
568 
569 protected:
576  // unfortunately we cannot specialise the variable template so we have to add an auxiliary here
577  template <typename t>
578  requires (range_dimension_v<t> == range_dimension_v<value_type> + 1) &&
579  std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
581  static constexpr bool is_compatible_this_aux = true;
584 
585 public:
586 
590  view_translate() noexcept = default;
591  constexpr view_translate(view_translate const & rhs) noexcept = default;
592  constexpr view_translate(view_translate && rhs) noexcept = default;
593  constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
594  constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
595  ~view_translate() noexcept = default;
596 
601  view_translate(urng_t _urange, translation_frames const _tf = translation_frames::SIX_FRAME)
602  : urange{std::move(_urange)}, tf{_tf}
603  {
605  selected_frames.push_back(translation_frames::FWD_FRAME_0);
607  selected_frames.push_back(translation_frames::FWD_FRAME_1);
609  selected_frames.push_back(translation_frames::FWD_FRAME_2);
611  selected_frames.push_back(translation_frames::REV_FRAME_0);
613  selected_frames.push_back(translation_frames::REV_FRAME_1);
615  selected_frames.push_back(translation_frames::REV_FRAME_2);
616  }
617 
622  template <typename rng_t>
624  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) &&
625  std::ranges::viewable_range<rng_t> &&
626  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
628  view_translate(rng_t && _urange, translation_frames const _tf)
629  : view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
630  {}
631 
633  #ifdef SEQAN3_DEPRECATED_310
634  template <typename rng_t>
636  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) &&
637  std::ranges::viewable_range<rng_t> &&
638  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
640  view_translate(rng_t && _urange)
641  : view_translate{std::views::all(std::forward<rng_t>(_urange)), translation_frames::SIX_FRAME}
642  {}
643  #endif // SEQAN3_DEPRECATED_310
645 
662  iterator begin() noexcept
663  {
664  return {*this, 0};
665  }
666 
668  const_iterator begin() const noexcept
669  {
670  return {*this, 0};
671  }
672 
686  iterator end() noexcept
687  {
688  return {*this, size()};
689  }
690 
692  const_iterator end() const noexcept
693  {
694  return {*this, size()};
695  }
696 
708  size_type size() noexcept
709  {
710  return (size_type) selected_frames.size();
711  }
712 
714  size_type size() const noexcept
715  {
716  return (size_type) selected_frames.size();
717  }
718 
737  reference operator[](size_type const n)
738  {
739  assert(n < size());
740  return urange | views::translate_single(selected_frames[n]);
741  }
742 
744  const_reference operator[](size_type const n) const
745  {
746  assert(n < size());
747  return urange | views::translate_single(selected_frames[n]);
748  }
750 };
751 
755 #ifdef SEQAN3_DEPRECATED_310
756 template <typename urng_t>
758  requires std::ranges::sized_range<urng_t> &&
759  std::ranges::random_access_range<urng_t> &&
762 view_translate (urng_t &&) -> view_translate<std::views::all_t<urng_t>>;
763 #endif // SEQAN3_DEPRECATED_310
764 
766 template <typename urng_t>
768  requires std::ranges::sized_range<urng_t> &&
769  std::ranges::random_access_range<urng_t> &&
772 view_translate(urng_t &&, translation_frames const) -> view_translate<std::views::all_t<urng_t>>;
773 } // namespace seqan3::detail
774 
775 // ============================================================================
776 // translate (adaptor object)
777 // ============================================================================
778 
779 namespace seqan3::views
780 {
781 
834 inline constexpr auto translate = deep{detail::translate_fn<false>{}};
836 
837 } // namespace seqan3::views
Provides seqan3::aa27, container aliases and string literals.
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:103
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:1104
constexpr auto complement
Return the complement of a nucleotide object.
Definition: concept.hpp:104
@ single
The text is a single range.
Definition: concept.hpp:84
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:150
constexpr auto translate
A view that translates nucleotide into aminoacid alphabet with 1, 2, 3 or 6 frames.
Definition: translate.hpp:834
constexpr auto translate_single
A view that translates nucleotide into aminoacid alphabet for one of the six frames.
Definition: translate.hpp:514
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:70
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:70
@ FWD_REV_0
The first forward and first reverse frame.
@ REV_FRAME_0
The first reverse frame starting at position 0.
@ REV_FRAME_1
The second reverse frame starting at position 1.
@ FWD_REV_2
The first third and third reverse frame.
@ FWD_FRAME_2
The third forward frame starting at position 2.
@ FWD_FRAME_1
The second forward frame starting at position 1.
@ FWD
All forward frames.
@ REV_FRAME_2
The third reverse frame starting at position 2.
@ REV
All reverse frames.
@ FWD_FRAME_0
The first forward frame starting at position 0.
@ FWD_REV_1
The second forward and second reverse frame.
SeqAn specific customisations in the standard namespace.
Provides the seqan3::detail::random_access_iterator class.
Adaptations of concepts from the standard library.
Adaptations of concepts from the Ranges TS.
A constexpr string implementation to manipulate string literals at compile time.
Provides functions for translating a triplet of nucleotides into an amino acid.
Provides seqan3::views::deep.