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 
66 enum class translation_frames : uint8_t
67 {
68  FWD_FRAME_0 = 1,
69  FWD_FRAME_1 = 1 << 1,
70  FWD_FRAME_2 = 1 << 2,
71  REV_FRAME_0 = 1 << 3,
72  REV_FRAME_1 = 1 << 4,
73  REV_FRAME_2 = 1 << 5,
79  SIX_FRAME = FWD | REV
80 };
81 
85 template <>
86 constexpr bool add_enum_bitwise_operators<translation_frames> = true;
88 
89 }
90 
91 namespace seqan3::detail
92 {
93 
94 // ============================================================================
95 // translate_fn (adaptor definition for both views)
96 // ============================================================================
97 
101 template <bool single>
102 struct translate_fn
103 {
105  static constexpr translation_frames default_frames = single ?
108 
110  constexpr auto operator()(translation_frames const tf = default_frames) const
111  {
112  return detail::adaptor_from_functor{*this, tf};
113  }
114 
120  template <std::ranges::range urng_t>
121  constexpr auto operator()(urng_t && urange, translation_frames const tf = default_frames) const
122  {
123  static_assert(std::ranges::viewable_range<urng_t>,
124  "The range parameter to views::translate[_single] cannot be a temporary of a non-view range.");
125  static_assert(std::ranges::sized_range<urng_t>,
126  "The range parameter to views::translate[_single] must model std::ranges::sized_range.");
127  static_assert(std::ranges::random_access_range<urng_t>,
128  "The range parameter to views::translate[_single] must model std::ranges::random_access_range.");
129  static_assert(nucleotide_alphabet<std::ranges::range_reference_t<urng_t>>,
130  "The range parameter to views::translate[_single] must be over elements of seqan3::nucleotide_alphabet.");
131 
132  if constexpr (single)
133  return detail::view_translate_single{std::forward<urng_t>(urange), tf};
134  else
135  return detail::view_translate{std::forward<urng_t>(urange), tf};
136  }
137 
139  template <std::ranges::range urng_t>
140  constexpr friend auto operator|(urng_t && urange, translate_fn const & me)
141  {
142  return me(std::forward<urng_t>(urange));
143  }
144 };
145 
146 // ============================================================================
147 // view_translate_single (range definition)
148 // ============================================================================
149 
156 template <std::ranges::view urng_t>
158  requires std::ranges::sized_range<urng_t> &&
159  std::ranges::random_access_range<urng_t> &&
162 class view_translate_single : public std::ranges::view_base
163 {
164 private:
166  urng_t urange;
170  static constexpr small_string multiple_frame_error{"Error: Invalid type of frame. Choose one out of FWD_FRAME_0, "
171  "REV_FRAME_0, FWD_FRAME_1, REV_FRAME_1, FWD_FRAME_2 and "
172  "REV_FRAME_2."};
173 public:
178  using reference = aa27;
180  using const_reference = aa27;
182  using value_type = aa27;
184  using size_type = std::ranges::range_size_t<urng_t>;
186  using difference_type = std::ranges::range_difference_t<urng_t>;
188  using iterator = detail::random_access_iterator<view_translate_single>;
190  using const_iterator = detail::random_access_iterator<view_translate_single const>;
192 
196  view_translate_single() noexcept = default;
197  constexpr view_translate_single(view_translate_single const & rhs) noexcept = default;
198  constexpr view_translate_single(view_translate_single && rhs) noexcept = default;
199  constexpr view_translate_single & operator=(view_translate_single const & rhs) noexcept = default;
200  constexpr view_translate_single & operator=(view_translate_single && rhs) noexcept = default;
201  ~view_translate_single() noexcept = default;
202 
203 
212  view_translate_single(urng_t _urange, translation_frames const _tf = translation_frames::FWD_FRAME_0)
213  : urange{std::move(_urange)}, tf{_tf}
214  {
215  if (__builtin_popcount(static_cast<uint8_t>(_tf)) > 1)
216  {
217  throw std::invalid_argument(multiple_frame_error.c_str());
218  }
219  }
220 
229  template <typename rng_t>
231  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate_single>) &&
232  std::ranges::viewable_range<rng_t> &&
233  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
235  view_translate_single(rng_t && _urange, translation_frames const _tf = translation_frames::FWD_FRAME_0)
236  : view_translate_single{std::views::all(std::forward<rng_t>(_urange)), _tf}
237  {}
239 
256  iterator begin() noexcept
257  {
258  return {*this, 0};
259  }
260 
262  const_iterator begin() const noexcept
263  {
264  return {*this, 0};
265  }
266 
280  iterator end() noexcept
281  {
282  return {*this, size()};
283  }
284 
286  const_iterator end() const noexcept
287  {
288  return {*this, size()};
289  }
291 
303  size_type size()
304  {
305  switch (tf)
306  {
308  [[fallthrough]];
310  return std::ranges::size(urange) / 3;
311  break;
313  [[fallthrough]];
315  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
316  break;
318  [[fallthrough]];
320  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
321  break;
322  default:
323  throw std::invalid_argument(multiple_frame_error.c_str());
324  break;
325  }
326  }
327 
329  size_type size() const
330  {
331  switch (tf)
332  {
334  [[fallthrough]];
336  return std::ranges::size(urange) / 3;
337  break;
339  [[fallthrough]];
341  return (std::max<size_type>(std::ranges::size(urange), 1) - 1) / 3;
342  break;
344  [[fallthrough]];
346  return (std::max<size_type>(std::ranges::size(urange), 2) - 2) / 3;
347  break;
348  default:
349  throw std::invalid_argument(multiple_frame_error.c_str());
350  break;
351  }
352  }
353 
372  reference operator[](size_type const n)
373  {
374  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
375  // we catch that error in debug-builds to make this function consistent with the behaviour in
376  // release-builds (-DNDEBUG).
377 #ifndef NDEBUG
378  try { assert(n < size()); } catch (std::invalid_argument const &) {}
379 #endif
380 
381  switch (tf)
382  {
384  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
385  break;
387  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]), complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]));
388  break;
390  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
391  break;
393  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]), 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]), complement((urange)[(urange).size() - n * 3 - 4]), complement((urange)[(urange).size() - n * 3 - 5]));
400  break;
401  default:
402  throw std::invalid_argument(multiple_frame_error.c_str());
403  break;
404  }
405  }
406 
408  const_reference operator[](size_type const n) const
409  {
410  // size will throw (only in debug-builds!) if translation_frames is neither (FWD|REV)_FRAME_(0|1|2),
411  // we catch that error in debug-builds to make this function consistent with the behaviour in
412  // release-builds (-DNDEBUG).
413 #ifndef NDEBUG
414  try { assert(n < size()); } catch (std::invalid_argument const &) {}
415 #endif
416 
417  switch (tf)
418  {
420  return translate_triplet((urange)[n * 3], (urange)[n * 3 + 1], (urange)[n * 3 + 2]);
421  break;
423  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 1]), complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]));
424  break;
426  return translate_triplet((urange)[n * 3 + 1], (urange)[n * 3 + 2], (urange)[n * 3 + 3]);
427  break;
429  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 2]), complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]));
430  break;
432  return translate_triplet((urange)[n * 3 + 2], (urange)[n * 3 + 3], (urange)[n * 3 + 4]);
433  break;
435  return translate_triplet(complement((urange)[(urange).size() - n * 3 - 3]), complement((urange)[(urange).size() - n * 3 - 4]), complement((urange)[(urange).size() - n * 3 - 5]));
436  break;
437  default:
438  throw std::invalid_argument(multiple_frame_error.c_str());
439  break;
440  }
441  }
443 };
444 
446 template <typename urng_t>
447 view_translate_single(urng_t &&, translation_frames const) -> view_translate_single<std::views::all_t<urng_t>>;
448 
449 
451 template <typename urng_t>
452 view_translate_single(urng_t &&) -> view_translate_single<std::views::all_t<urng_t>>;
453 
454 } // namespace seqan3::detail
455 
456 // ============================================================================
457 // translate_single (adaptor object)
458 // ============================================================================
459 
460 namespace seqan3::views
461 {
462 
509 inline constexpr auto translate_single = deep{detail::translate_fn<true>{}};
510 
511 } // seqan3::views
512 
513 // ============================================================================
514 // view_translate (range definition)
515 // ============================================================================
516 
517 namespace seqan3::detail
518 {
519 
528 template <std::ranges::view urng_t>
530  requires std::ranges::sized_range<urng_t> &&
531  std::ranges::random_access_range<urng_t> &&
534 class view_translate : public std::ranges::view_base
535 {
536 private:
538  urng_t urange;
542  small_vector<translation_frames, 6> selected_frames{};
543 
544 public:
549  using reference = view_translate_single<urng_t>;
551  using const_reference = reference;
553  using value_type = reference;
555  using size_type = std::ranges::range_size_t<urng_t>;
557  using difference_type = std::ranges::range_difference_t<urng_t>;
559  using iterator = detail::random_access_iterator<view_translate>;
561  using const_iterator = detail::random_access_iterator<view_translate const>;
563 
564 protected:
571  // unfortunately we cannot specialise the variable template so we have to add an auxiliary here
572  template <typename t>
573  requires (range_dimension_v<t> == range_dimension_v<value_type> + 1) &&
574  std::is_same_v<std::remove_cvref_t<range_innermost_value_t<value_type>>,
576  static constexpr bool is_compatible_this_aux = true;
579 
580 public:
581 
585  view_translate() noexcept = default;
586  constexpr view_translate(view_translate const & rhs) noexcept = default;
587  constexpr view_translate(view_translate && rhs) noexcept = default;
588  constexpr view_translate & operator=(view_translate const & rhs) noexcept = default;
589  constexpr view_translate & operator=(view_translate && rhs) noexcept = default;
590  ~view_translate() noexcept = default;
591 
596  view_translate(urng_t _urange, translation_frames const _tf = translation_frames::SIX_FRAME)
597  : urange{std::move(_urange)}, tf{_tf}
598  {
600  selected_frames.push_back(translation_frames::FWD_FRAME_0);
602  selected_frames.push_back(translation_frames::FWD_FRAME_1);
604  selected_frames.push_back(translation_frames::FWD_FRAME_2);
606  selected_frames.push_back(translation_frames::REV_FRAME_0);
608  selected_frames.push_back(translation_frames::REV_FRAME_1);
610  selected_frames.push_back(translation_frames::REV_FRAME_2);
611  }
612 
617  template <typename rng_t>
619  requires (!std::same_as<std::remove_cvref_t<rng_t>, view_translate>) &&
620  std::ranges::viewable_range<rng_t> &&
621  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<rng_t>>>
623  view_translate(rng_t && _urange, translation_frames const _tf = translation_frames::SIX_FRAME)
624  : view_translate{std::views::all(std::forward<rng_t>(_urange)), _tf}
625  {}
627 
644  iterator begin() noexcept
645  {
646  return {*this, 0};
647  }
648 
650  const_iterator begin() const noexcept
651  {
652  return {*this, 0};
653  }
654 
668  iterator end() noexcept
669  {
670  return {*this, size()};
671  }
672 
674  const_iterator end() const noexcept
675  {
676  return {*this, size()};
677  }
678 
690  size_type size() noexcept
691  {
692  return (size_type) selected_frames.size();
693  }
694 
696  size_type size() const noexcept
697  {
698  return (size_type) selected_frames.size();
699  }
700 
719  reference operator[](size_type const n)
720  {
721  assert(n < size());
722  return urange | views::translate_single(selected_frames[n]);
723  }
724 
726  const_reference operator[](size_type const n) const
727  {
728  assert(n < size());
729  return urange | views::translate_single(selected_frames[n]);
730  }
732 };
733 
735 template <typename urng_t>
737  requires std::ranges::sized_range<urng_t> &&
738  std::ranges::random_access_range<urng_t> &&
741 view_translate(urng_t &&, translation_frames const = translation_frames{}) -> view_translate<std::views::all_t<urng_t>>;
742 
743 } // namespace seqan3::detail
744 
745 // ============================================================================
746 // translate (adaptor object)
747 // ============================================================================
748 
749 namespace seqan3::views
750 {
751 
798 inline constexpr auto translate = deep{detail::translate_fn<false>{}};
800 
801 } // 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:102
The Concepts 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)
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:798
constexpr auto translate_single
A view that translates nucleotide into aminoacid alphabet for one of the six frames.
Definition: translate.hpp:509
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.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
translation_frames
Specialisation values for single and multiple translation frames.
Definition: translate.hpp:67
@ 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.