SeqAn3
cartesian_composition.hpp
Go to the documentation of this file.
1 // ============================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ============================================================================
4 //
5 // Copyright (c) 2006-2018, Knut Reinert & Freie Universitaet Berlin
6 // Copyright (c) 2016-2018, Knut Reinert & MPI Molekulare Genetik
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
25 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 // DAMAGE.
32 //
33 // ============================================================================
34 
40 #pragma once
41 
42 #include <cassert>
43 #include <utility>
44 
45 #include <meta/meta.hpp>
46 
58 #include <seqan3/std/concepts>
59 
60 namespace seqan3::detail
61 {
62 
78 // anchor is false
79 template <typename cartesian_t, typename cartesian_derived_t, template <typename> typename fun_t, typename other_t>
80 inline bool constexpr one_component_is = false;
81 
83 
84 // default
85 template <typename ... cartesian_comps,
86  typename cartesian_derived_t,
87  template <typename> typename fun_t,
88  typename other_t>
89 inline bool constexpr one_component_is<cartesian_composition<cartesian_derived_t, cartesian_comps...>,
90  cartesian_derived_t,
91  fun_t,
92  other_t> =
93  !meta::empty<meta::find_if<meta::list<cartesian_comps...>, fun_t<other_t>>>::value;
94  //TODO do without meta
95 
96 // guard against self
97 template <typename ... cartesian_comps,
98  typename cartesian_derived_t,
99  template <typename> typename fun_t>
100 inline bool constexpr one_component_is<cartesian_composition<cartesian_derived_t, cartesian_comps...>,
101  cartesian_derived_t,
102  fun_t,
103  cartesian_composition<cartesian_derived_t, cartesian_comps...>> = false;
104 
105 // guard against self (derived)
106 template <typename ... cartesian_comps,
107  typename cartesian_derived_t,
108  template <typename> typename fun_t>
109 inline bool constexpr one_component_is<cartesian_composition<cartesian_derived_t, cartesian_comps...>,
110  cartesian_derived_t,
111  fun_t,
112  cartesian_derived_t> = false;
113 
114 // guard against types that have conversion operators to derived
115 template <typename ... cartesian_comps,
116  typename cartesian_derived_t,
117  template <typename> typename fun_t,
118  typename other_t>
119  requires convertible_to_by_member_concept<other_t, cartesian_derived_t>
120 inline bool constexpr one_component_is<cartesian_composition<cartesian_derived_t, cartesian_comps...>,
121  cartesian_derived_t,
122  fun_t,
123  other_t> = false;
124 
125 // guard against components
126 template <typename ... cartesian_comps,
127  typename cartesian_derived_t,
128  template <typename> typename fun_t,
129  typename other_t>
130  requires type_in_pack_v<other_t, cartesian_comps...>
131 // requires meta::in<recursive_cartesian_components<cartesian_composition<cartesian_derived_t, cartesian_comps...>>::type,
132 // other_t>::value
133 inline bool constexpr one_component_is<cartesian_composition<cartesian_derived_t, cartesian_comps...>,
134  cartesian_derived_t,
135  fun_t,
136  other_t> = false;
137 
138 // during comparisons, guard against types that could be converted to self (because that is preferred)
139 // (may not be done during assignment or construction because of recursiveness)
140 template <typename ... cartesian_comps,
141  typename cartesian_derived_t,
142  typename other_t>
143  requires implicitly_convertible_to_concept<other_t, cartesian_derived_t>
144 inline bool constexpr one_component_is<cartesian_composition<cartesian_derived_t, cartesian_comps...>,
145  cartesian_derived_t,
146  weakly_equality_comparable_with,
147  other_t> = false;
148 template <typename ... cartesian_comps,
149  typename cartesian_derived_t,
150  typename other_t>
151  requires implicitly_convertible_to_concept<other_t, cartesian_derived_t>
152 inline bool constexpr one_component_is<cartesian_composition<cartesian_derived_t, cartesian_comps...>,
153  cartesian_derived_t,
154  weakly_ordered_with,
155  other_t> = false;
157 
158 } // namespace seqan3::detail
159 
160 namespace seqan3
161 {
162 
163 // forwards
165 template <typename t>
166 decltype(auto) get();
167 
168 template <size_t i>
169 decltype(auto) get();
171 
204 template <typename derived_type,
205  typename ...component_types>
207  requires (detail::constexpr_semi_alphabet_concept<component_types> && ...)
210  public alphabet_base<derived_type,
211  (1 * ... * alphabet_size_v<component_types>),
212  void> // no char type, because this is only semi_alphabet
213 {
214 private:
216  using base_t = alphabet_base<derived_type,
217  (1 * ... * alphabet_size_v<component_types>),
218  void>; // no char type, because this is only semi_alphabet
219 
221  using component_list = meta::list<component_types...>;
222 
224  template <typename type>
225  static constexpr bool is_component =
226  meta::in<component_list, type>::value;
227 
229  template <typename type>
230  static constexpr bool is_unique_component =
231  is_component<type> &&
232  (meta::find_index<component_list, type>::value == meta::reverse_find_index<component_list, type>::value);
233 
238  template <typename alphabet_type, size_t index>
239  class component_proxy : public alphabet_proxy<component_proxy<alphabet_type, index>, alphabet_type>
240  {
241  private:
245  friend base_t;
246 
248  cartesian_composition *parent;
249 
251  constexpr void on_update() noexcept
252  {
253  parent->assign_rank(
254  parent->to_rank()
255  - parent->template to_component_rank<index>() * cartesian_composition::cummulative_alph_sizes[index]
256  + to_rank() * cartesian_composition::cummulative_alph_sizes[index]);
257  }
258 
259  public:
260  //Import from base type:
261  using base_t::to_rank;
262  using base_t::value_size;
263  using base_t::operator=;
264 
268  using typename base_t::rank_type;
269  using typename base_t::char_type;
270  using typename base_t::phred_type;
272 
276  constexpr component_proxy() : base_t{}, parent{} {}
277  constexpr component_proxy(component_proxy const &) = default;
278  constexpr component_proxy(component_proxy &&) = default;
279  constexpr component_proxy & operator=(component_proxy const &) = default;
280  constexpr component_proxy & operator=(component_proxy &&) = default;
281  ~component_proxy() = default;
282 
283  constexpr component_proxy(alphabet_type const l, cartesian_composition & p) :
284  base_t{l}, parent{&p}
285  {}
286 
287  // Does not inherit the base's constructor for alphabet_type so as not to cause ambiguity
289  };
290 
294  constexpr cartesian_composition() : base_t{} {}
295  constexpr cartesian_composition(cartesian_composition const &) = default;
296  constexpr cartesian_composition(cartesian_composition &&) = default;
297  constexpr cartesian_composition & operator=(cartesian_composition const &) = default;
298  constexpr cartesian_composition & operator=(cartesian_composition &&) = default;
299  ~cartesian_composition() = default;
300 
301  using base_t::base_t;
303 
306  friend derived_type;
307 
308 public:
309  // Import from base:
310  using base_t::value_size;
311  using typename base_t::rank_type;
312  using base_t::to_rank;
313  using base_t::assign_rank;
314 
317  using seqan3_cartesian_components = component_list;
320  using seqan3_recursive_cartesian_components =
321  meta::concat<component_list,
322  detail::transformation_trait_or_t<detail::recursive_cartesian_components<component_types>,
323  meta::list<>>...>;
324 
332  constexpr cartesian_composition(component_types ... components)
334  {
335  assign_rank(rank_sum_helper(components..., std::make_index_sequence<sizeof...(component_types)>{}));
336  }
337 
347  template <typename component_type>
349  requires is_unique_component<component_type>
351  constexpr explicit cartesian_composition(component_type const alph) : cartesian_composition{}
352  {
353  get<component_type>(*this) = alph;
354  }
355 
369  template <typename indirect_component_type>
371  requires detail::one_component_is<cartesian_composition, derived_type, detail::implicitly_convertible_from, indirect_component_type>
373  constexpr explicit cartesian_composition(indirect_component_type const alph) : cartesian_composition{}
374  {
375  using component_type = meta::front<meta::find_if<component_list, detail::implicitly_convertible_from<indirect_component_type>>>;
376  component_type tmp(alph); // delegate construction
377  get<component_type>(*this) = tmp;
378  }
379 
381  template <typename indirect_component_type>
382  requires !detail::one_component_is<cartesian_composition, derived_type, detail::implicitly_convertible_from, indirect_component_type> &&
383  detail::one_component_is<cartesian_composition, derived_type, detail::constructible_from, indirect_component_type>
384  constexpr explicit cartesian_composition(indirect_component_type const alph) : cartesian_composition{}
385  {
386  using component_type = meta::front<meta::find_if<component_list, detail::constructible_from<indirect_component_type>>>;
387  component_type tmp(alph); // delegate construction
388  get<component_type>(*this) = tmp;
389  }
391 
401  template <typename component_type>
403  requires is_unique_component<component_type>
405  constexpr derived_type & operator=(component_type const alph)
406  {
407  get<component_type>(*this) = alph;
408  return static_cast<derived_type &>(*this);
409  }
410 
420  template <typename indirect_component_type>
422  requires detail::one_component_is<cartesian_composition, derived_type, detail::assignable_from, indirect_component_type>
424  constexpr derived_type & operator=(indirect_component_type const alph)
425  {
426  using component_type = meta::front<meta::find_if<component_list, detail::assignable_from<indirect_component_type>>>;
427  get<component_type>(*this) = alph; // delegate assignment
428  return static_cast<derived_type &>(*this);
429  }
431  // If not assignable but implicit convertible, convert first and assign afterwards
432  template <typename indirect_component_type>
434  requires !detail::one_component_is<cartesian_composition, derived_type, detail::assignable_from, indirect_component_type> &&
435  detail::one_component_is<cartesian_composition, derived_type, detail::implicitly_convertible_from, indirect_component_type>
437  constexpr derived_type & operator=(indirect_component_type const alph)
438  {
439  using component_type = meta::front<meta::find_if<component_list, detail::implicitly_convertible_from<indirect_component_type>>>;
440  component_type tmp(alph);
441  get<component_type>(*this) = tmp;
442  return static_cast<derived_type &>(*this);
443  }
446 
455  template <size_t index>
456  friend constexpr auto get(cartesian_composition & l)
457  {
458  static_assert(index < sizeof...(component_types), "Index out of range.");
459 
460  using t = meta::at_c<component_list, index>;
461  t val{};
462 
463  using seqan3::assign_rank;
464  assign_rank(val, l.to_component_rank<index>());
465 
466  return component_proxy<t, index>{val, l};
467  }
468 
473  template <typename type>
474  friend constexpr auto get(cartesian_composition & l)
476  requires is_unique_component<type>
478  {
479  return get<meta::find_index<component_list, type>::value>(l);
480  }
481 
486  template <size_t index>
487  friend constexpr auto get(cartesian_composition const & l)
488  {
489  static_assert(index < sizeof...(component_types), "Index out of range.");
490 
491  using t = meta::at_c<component_list, index>;
492  t val{};
493 
494  using seqan3::assign_rank;
495  assign_rank(val, l.to_component_rank<index>());
496 
497  return val;
498  }
499 
504  template <typename type>
505  friend constexpr type get(cartesian_composition const & l)
507  requires is_unique_component<type>
509  {
510  return get<meta::find_index<component_list, type>::value>(l);
511  }
512 
515  template <typename type>
516  constexpr operator type() const
518  requires is_unique_component<type>
520  {
521  return get<type>(*this);
522  }
524 
530  template <typename indirect_component_type>
531  constexpr bool operator==(indirect_component_type const & rhs) const noexcept
533  requires detail::one_component_is<cartesian_composition, derived_type, detail::weakly_equality_comparable_with, indirect_component_type>
535  {
536  using component_type = meta::front<meta::find_if<component_list, detail::weakly_equality_comparable_with<indirect_component_type>>>;
537  return get<component_type>(*this) == rhs;
538  }
539 
540  template <typename indirect_component_type>
541  constexpr bool operator!=(indirect_component_type const & rhs) const noexcept
543  requires detail::one_component_is<cartesian_composition, derived_type, detail::weakly_equality_comparable_with, indirect_component_type>
545  {
546  using component_type = meta::front<meta::find_if<component_list, detail::weakly_equality_comparable_with<indirect_component_type>>>;
547  return get<component_type>(*this) != rhs;
548  }
549 
550  template <typename indirect_component_type>
551  constexpr bool operator<(indirect_component_type const & rhs) const noexcept
553  requires detail::one_component_is<cartesian_composition, derived_type, detail::weakly_ordered_with, indirect_component_type>
555  {
556  using component_type = meta::front<meta::find_if<component_list, detail::weakly_ordered_with<indirect_component_type>>>;
557  return get<component_type>(*this) < rhs;
558  }
559 
560  template <typename indirect_component_type>
561  constexpr bool operator>(indirect_component_type const & rhs) const noexcept
563  requires detail::one_component_is<cartesian_composition, derived_type, detail::weakly_ordered_with, indirect_component_type>
565  {
566  using component_type = meta::front<meta::find_if<component_list, detail::weakly_ordered_with<indirect_component_type>>>;
567  return get<component_type>(*this) > rhs;
568  }
569 
570  template <typename indirect_component_type>
571  constexpr bool operator<=(indirect_component_type const & rhs) const noexcept
573  requires detail::one_component_is<cartesian_composition, derived_type, detail::weakly_ordered_with, indirect_component_type>
575  {
576  using component_type = meta::front<meta::find_if<component_list, detail::weakly_ordered_with<indirect_component_type>>>;
577  return get<component_type>(*this) <= rhs;
578  }
579 
580  template <typename indirect_component_type>
581  constexpr bool operator>=(indirect_component_type const & rhs) const noexcept
583  requires detail::one_component_is<cartesian_composition, derived_type, detail::weakly_ordered_with, indirect_component_type>
585  {
586  using component_type = meta::front<meta::find_if<component_list, detail::weakly_ordered_with<indirect_component_type>>>;
587  return get<component_type>(*this) >= rhs;
588  }
590 
591 private:
593  template <size_t index>
594  constexpr rank_type to_component_rank() const
595  {
596  return (to_rank() / cummulative_alph_sizes[index]) % alphabet_size_v<meta::at_c<component_list, index>>;
597  }
598 
600  static constexpr std::array<rank_type, component_list::size()> cummulative_alph_sizes
601  {
602  [] () constexpr
603  {
604  // create array (1, |sigma1|, |sigma1|*|sigma2|, ... , |sigma1|*...*|sigmaN|)
605  std::array<rank_type, component_list::size() + 1> ret{};
606  ret[0] = 1;
607  size_t count = 1;
608  meta::for_each(meta::reverse<component_list>{}, [&] (auto && alph) constexpr
609  {
610  ret[count] = static_cast<rank_type>(alphabet_size_v<std::decay_t<decltype(alph)>> * ret[count - 1]);
611  ++count;
612  });
613 
614  // reverse and strip one: (|sigma1|*...*|sigmaN-1|, ... |sigma1|*|sigma2|, |sigma1|, 1)
615  // reverse order guarantees that the first alphabet is the most significant rank contributer
616  // resulting in element-wise alphabetical ordering on comparison
617  std::array<rank_type, component_list::size()> ret2{};
618  for (size_t i = 0; i < component_list::size(); ++i)
619  ret2[i] = ret[component_list::size() - i - 1];
620 
621  return ret2;
622  }()
623  };
624 
626  template <std::size_t ...idx>
627  static constexpr rank_type rank_sum_helper(component_types ... components, std::index_sequence<idx...> const &)
628  {
629  using seqan3::to_rank;
630  return ((to_rank(components) * cummulative_alph_sizes[idx]) + ...);
631  }
632 };
633 
639 template <typename indirect_component_type, typename derived_type, typename ...component_types>
641  requires detail::weakly_equality_comparable_by_members_with_concept<derived_type, indirect_component_type> &&
642  !detail::weakly_equality_comparable_by_members_with_concept<indirect_component_type, derived_type>
644 constexpr bool operator==(indirect_component_type const & lhs,
646 {
647  return rhs == lhs;
648 }
649 
650 template <typename indirect_component_type, typename derived_type, typename ...indirect_component_types>
652  requires detail::weakly_equality_comparable_by_members_with_concept<derived_type, indirect_component_type> &&
653  !detail::weakly_equality_comparable_by_members_with_concept<indirect_component_type, derived_type>
655 constexpr bool operator!=(indirect_component_type const & lhs,
657 {
658  return rhs != lhs;
659 }
660 
661 template <typename indirect_component_type, typename derived_type, typename ...indirect_component_types>
663  requires detail::weakly_ordered_by_members_with_concept<derived_type, indirect_component_type> &&
664  !detail::weakly_ordered_by_members_with_concept<indirect_component_type, derived_type>
666 constexpr bool operator<(indirect_component_type const & lhs,
668 {
669  return rhs > lhs;
670 }
671 
672 template <typename indirect_component_type, typename derived_type, typename ...indirect_component_types>
674  requires detail::weakly_ordered_by_members_with_concept<derived_type, indirect_component_type> &&
675  !detail::weakly_ordered_by_members_with_concept<indirect_component_type, derived_type>
677 constexpr bool operator>(indirect_component_type const & lhs,
679 {
680  return rhs < lhs;
681 }
682 
683 template <typename indirect_component_type, typename derived_type, typename ...indirect_component_types>
685  requires detail::weakly_ordered_by_members_with_concept<derived_type, indirect_component_type> &&
686  !detail::weakly_ordered_by_members_with_concept<indirect_component_type, derived_type>
688 constexpr bool operator<=(indirect_component_type const & lhs,
690 {
691  return rhs >= lhs;
692 }
693 
694 template <typename indirect_component_type, typename derived_type, typename ...indirect_component_types>
696  requires detail::weakly_ordered_by_members_with_concept<derived_type, indirect_component_type> &&
697  !detail::weakly_ordered_by_members_with_concept<indirect_component_type, derived_type>
699 constexpr bool operator>=(indirect_component_type const & lhs,
701 {
702  return rhs <= lhs;
703 }
705 
706 } // namespace seqan3
707 
708 namespace std
709 {
710 
713 template <std::size_t i, seqan3::detail::cartesian_composition_concept tuple_t>
714 struct tuple_element<i, tuple_t>
715 {
717  using type = meta::at_c<typename tuple_t::seqan3_cartesian_components, i>;
718 };
719 
722 template <seqan3::detail::cartesian_composition_concept tuple_t>
723 struct tuple_size<tuple_t> :
724  public std::integral_constant<size_t, tuple_t::seqan3_cartesian_components::size()>
725 {};
726 
727 } // namespace std
constexpr cartesian_composition(component_type const alph)
Construction via a value of one of the components.
Definition: cartesian_composition.hpp:351
detail::min_viable_uint_t< size - 1 > rank_type
The type of the alphabet when represented as a number (e.g. via to_rank()).
Definition: alphabet_base.hpp:89
Provides concepts for core language types and relations that don&#39;t have concepts in C++20 (yet)...
void char_type
The type of the alphabet when converted to char (e.g. via to_char()).
Definition: alphabet_base.hpp:87
The CRTP base for a combined alphabet that contains multiple values of different alphabets at the sam...
Definition: cartesian_composition.hpp:209
A CRTP-base that eases the definition of proxy types returned in place of regular alphabets...
Definition: alphabet_proxy.hpp:152
Contains metaprogramming utilities for integer types.
Provides seqan3::detail::transformation_trait_or.
Provides various metafunctions on a set of types, usually provided as template argument pack...
meta::at_c< typename tuple_t::seqan3_cartesian_components, i > type
Element type.
Definition: cartesian_composition.hpp:717
SeqAn specific customisations in the standard namespace.
Definition: align_result.hpp:221
constexpr derived_type & operator=(component_type const alph)
Assignment via a value of one of the components.
Definition: cartesian_composition.hpp:405
::ranges::size size
Alias for ranges::size. Obtains the size of a range whose size can be calculated in constant time...
Definition: ranges:195
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:58
Provides implementation detail for seqan3::union_composition and seqan3::cartesian_composition.
constexpr auto const & get(detail::configuration< cfg_elements_t... > const &cfg) noexcept
Definition: utility.hpp:364
Provides seqan3::tuple_like_concept.
constexpr alphabet_type & assign_rank(alphabet_type &alph, underlying_rank_t< alphabet_type > const rank) requires requires(alphabet_type alph)
Implementation of seqan3::semi_alphabet_concept::assign_rank() that delegates to a member function...
Definition: member_exposure.hpp:110
The Concepts library.
Free function/metafunction wrappers for alphabets with member functions/types.
Provides utility functions for tuple like interfaces.
Provides seqan3::alphabet_base.
Definition: aligned_sequence_concept.hpp:288
semi_alphabet_concept && assign_rank(semi_alphabet_concept &&alph, rank_type const rank)
Returns the alphabet letter&#39;s value in rank representation.
rank_type to_rank(semi_alphabet_concept const alph)
Returns the alphabet letter&#39;s value in rank representation.
::ranges::empty empty
Alias for ranges::empty. Checks whether a range is empty.
Definition: ranges:205
Core alphabet concept and free function/metafunction wrappers.
constexpr derived_type & operator=(indirect_component_type const alph)
Assignment via a value of a subtype that is assignable to one of the components.
Definition: cartesian_composition.hpp:424
A CRTP-base that makes defining a custom alphabet easier.
Definition: alphabet_base.hpp:77
Quality alphabet concept.
constexpr cartesian_composition(indirect_component_type const alph)
Construction via a value of a subtype that is assignable to one of the components.
Definition: cartesian_composition.hpp:373
constexpr underlying_rank_t< alphabet_type > to_rank(alphabet_type const alph) requires requires(alphabet_type alph)
Implementation of seqan3::semi_alphabet_concept::to_rank() that delegates to a member function...
Definition: member_exposure.hpp:97
auto const to_rank
A view that calls seqan3::to_rank() on each element in the input range.
Definition: to_rank.hpp:90