SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
concept.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/type_traits>
16 
23 
24 // ============================================================================
25 // forwards
26 // ============================================================================
27 
28 namespace seqan3::custom
29 {
30 
47 template <typename t>
48 struct alphabet
49 {};
50 
52 template <typename t>
53 struct alphabet<t const> : alphabet<t>
54 {};
55 
56 template <typename t>
57 struct alphabet<t &> : alphabet<t>
58 {};
59 
60 template <typename t>
61 struct alphabet<t const &> : alphabet<t>
62 {};
64 
65 } // namespace seqan3::custom
66 
67 // ============================================================================
68 // to_rank()
69 // ============================================================================
70 
71 namespace seqan3::detail::adl_only
72 {
73 
75 template <typename ...args_t>
76 void to_rank(args_t ...) = delete;
77 
79 struct to_rank_fn
80 {
81 public:
82  SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet<decltype(v)>::to_rank(v)) // explicit customisation
83  SEQAN3_CPO_IMPL(1, to_rank(v) ) // ADL
84  SEQAN3_CPO_IMPL(0, v.to_rank() ) // member
85 
86 public:
88  template <typename alph_t>
90  requires requires (alph_t const a)
91  {
92  { impl(priority_tag<2>{}, a) };
93  requires noexcept(impl(priority_tag<2>{}, a));
94  requires std::integral<decltype(impl(priority_tag<2>{}, a))>;
95  }
97  constexpr auto operator()(alph_t const a) const noexcept
98  {
99  return impl(priority_tag<2>{}, a);
100  }
101 };
102 
103 } // namespace seqan3::detail::adl_only
104 
105 namespace seqan3
106 {
107 
146 inline constexpr auto to_rank = detail::adl_only::to_rank_fn{};
148 
151 template <typename semi_alphabet_type>
153  requires requires { { seqan3::to_rank(std::declval<semi_alphabet_type>()) }; }
155 using alphabet_rank_t = decltype(seqan3::to_rank(std::declval<semi_alphabet_type>()));
156 
157 } // namespace seqan3
158 
159 // ============================================================================
160 // assign_rank_to()
161 // ============================================================================
162 
163 namespace seqan3::detail::adl_only
164 {
165 
167 template <typename ...args_t>
168 void assign_rank_to(args_t ...) = delete;
169 
172 struct assign_rank_to_fn
173 {
174 public:
175  SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::assign_rank_to(args..., v))) // explicit customisation
176  SEQAN3_CPO_IMPL(1, (assign_rank_to(args..., v) )) // ADL
177  SEQAN3_CPO_IMPL(0, (v.assign_rank(args...) )) // member
178 
179 public:
181  template <typename alph_t>
183  requires requires (seqan3::alphabet_rank_t<alph_t> const r, alph_t & a)
184  {
185  { impl(priority_tag<2>{}, a, r) };
186  requires noexcept(impl(priority_tag<2>{}, a, r));
187  requires std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, r))>;
188  }
190  constexpr alph_t operator()(seqan3::alphabet_rank_t<alph_t> const r, alph_t && a) const noexcept
191  {
192  return impl(priority_tag<2>{}, a, r);
193  }
194 };
195 
196 } // namespace seqan3::detail::adl_only
197 
198 namespace seqan3
199 {
200 
244 inline constexpr auto assign_rank_to = detail::adl_only::assign_rank_to_fn{};
246 } // namespace seqan3
247 
248 // ============================================================================
249 // to_char()
250 // ============================================================================
251 
252 namespace seqan3::detail::adl_only
253 {
254 
256 template <typename ...args_t>
257 void to_char(args_t ...) = delete;
258 
261 struct to_char_cpo : public detail::customisation_point_object<to_char_cpo, 2>
262 {
264  using base_t = detail::customisation_point_object<to_char_cpo, 2>;
266  using base_t::base_t;
267 
272  template <typename alphabet_t>
273  static constexpr auto SEQAN3_CPO_OVERLOAD(priority_tag<2>, alphabet_t && alphabet)
274  (
275  /*return*/ seqan3::custom::alphabet<alphabet_t>::to_char(std::forward<alphabet_t>(alphabet)) /*;*/
276  );
277 
282  template <typename alphabet_t>
283  static constexpr auto SEQAN3_CPO_OVERLOAD(priority_tag<1>, alphabet_t && alphabet)
284  (
285  /*return*/ to_char(std::forward<alphabet_t>(alphabet)) /*;*/
286  );
287 
292  template <typename alphabet_t>
293  static constexpr auto SEQAN3_CPO_OVERLOAD(priority_tag<0>, alphabet_t && alphabet)
294  (
295  /*return*/ std::forward<alphabet_t>(alphabet).to_char() /*;*/
296  );
297 };
298 
299 } // namespace seqan3::detail::adl_only
300 
301 namespace seqan3
302 {
303 
343 inline constexpr auto to_char = detail::adl_only::to_char_cpo{};
345 
351 template <typename alphabet_type>
353  requires requires (alphabet_type const a) { { seqan3::to_char(a) }; }
355 using alphabet_char_t = decltype(seqan3::to_char(std::declval<alphabet_type const>()));
356 
357 } // namespace seqan3
358 
359 // ============================================================================
360 // assign_char_to()
361 // ============================================================================
362 
363 namespace seqan3::detail::adl_only
364 {
365 
367 template <typename ...args_t>
368 void assign_char_to(args_t ...) = delete;
369 
372 struct assign_char_to_fn
373 {
374 public:
375  SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::assign_char_to(args..., v))) // explicit customisation
376  SEQAN3_CPO_IMPL(1, (assign_char_to(args..., v) )) // ADL
377  SEQAN3_CPO_IMPL(0, (v.assign_char(args...) )) // member
378 
379 public:
381  template <typename alph_t>
383  requires requires (seqan3::alphabet_char_t<alph_t> const r, alph_t & a)
384  {
385  { impl(priority_tag<2>{}, a, r) };
386  requires noexcept(impl(priority_tag<2>{}, a, r));
387  requires std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, r))>;
388  }
390  constexpr alph_t operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t && a) const noexcept
391  {
392  return impl(priority_tag<2>{}, a, r);
393  }
394 };
395 
396 } // namespace seqan3::detail::adl_only
397 
398 namespace seqan3
399 {
400 
444 inline constexpr auto assign_char_to = detail::adl_only::assign_char_to_fn{};
446 } // namespace seqan3
447 
448 // ============================================================================
449 // char_is_valid_for()
450 // ============================================================================
451 
452 namespace seqan3::detail::adl_only
453 {
454 
456 template <typename ...args_t>
457 void char_is_valid_for(args_t ...) = delete;
458 
463 template <typename alph_t>
464 struct char_is_valid_for_fn
465 {
466 public:
471 
472  SEQAN3_CPO_IMPL(3, (deferred_type_t<seqan3::custom::alphabet<alph_t>, decltype(v)>::char_is_valid(v))) // expl. cst.
473  SEQAN3_CPO_IMPL(2, (char_is_valid_for(v, s_alph_t{}) )) // ADL
474  SEQAN3_CPO_IMPL(1, (deferred_type_t<std::remove_cvref_t<alph_t>, decltype(v)>::char_is_valid(v) )) // member
475  SEQAN3_CPO_IMPL(0, (seqan3::to_char(seqan3::assign_char_to(v, s_alph_t{})) == v )) // fallback
476 
477 public:
479  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
481  requires requires (alphabet_char_t<alph_t> const a)
482  {
483  { impl(priority_tag<3>{}, a, dummy{}) };
484  requires noexcept(impl(priority_tag<3>{}, a, dummy{}));
485  SEQAN3_RETURN_TYPE_CONSTRAINT(impl(priority_tag<3>{}, a, dummy{}), std::convertible_to, bool);
486  }
488  constexpr bool operator()(alphabet_char_t<alph_t> const a) const noexcept
489  {
490  return impl(priority_tag<3>{}, a);
491  }
492 };
493 
494 } // namespace seqan3::detail::adl_only
495 
496 namespace seqan3
497 {
498 
547 template <typename alph_t>
549  requires requires { { to_char(std::declval<alph_t>()) }; } // to_char() is required by some defs
551 inline constexpr auto char_is_valid_for = detail::adl_only::char_is_valid_for_fn<alph_t>{};
553 } // namespace seqan3
554 
555 // ============================================================================
556 // assign_char_strictly_to()
557 // ============================================================================
558 
559 namespace seqan3::detail::adl_only
560 {
561 
564 struct assign_char_strictly_to_fn
565 {
567  template <typename alphabet_t>
568  constexpr decltype(auto) operator()(seqan3::alphabet_char_t<alphabet_t> const chr, alphabet_t && alphabet) const
570  requires requires ()
571  {
572  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::assign_char_to(chr, std::forward<alphabet_t>(alphabet)),
573  std::convertible_to, alphabet_t);
574  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::char_is_valid_for<alphabet_t>(chr), std::same_as, bool);
575  }
577  {
578  if (!seqan3::char_is_valid_for<alphabet_t>(chr))
579  throw seqan3::invalid_char_assignment{detail::type_name_as_string<alphabet_t>, chr};
580 
581  return seqan3::assign_char_to(chr, std::forward<alphabet_t>(alphabet));
582  }
583 };
584 
585 } // namespace seqan3::detail::adl_only
586 
587 namespace seqan3
588 {
589 
615 inline constexpr auto assign_char_strictly_to = detail::adl_only::assign_char_strictly_to_fn{};
617 } // namespace seqan3
618 
619 // ============================================================================
620 // alphabet_size
621 // ============================================================================
622 
623 namespace seqan3::detail::adl_only
624 {
625 
627 template <typename ...args_t>
628 void alphabet_size(args_t ...) = delete;
629 
634 template <typename alph_t>
635 struct alphabet_size_fn
636 {
637 public:
640  seqan3::is_constexpr_default_constructible_v<std::remove_cvref_t<alph_t>>,
643 
644  SEQAN3_CPO_IMPL(2, (deferred_type_t<seqan3::custom::alphabet<alph_t>, decltype(v)>::alphabet_size)) // expl. cst.
645  SEQAN3_CPO_IMPL(1, (alphabet_size(v) )) // ADL
646  SEQAN3_CPO_IMPL(0, (deferred_type_t<std::remove_cvref_t<alph_t>, decltype(v)>::alphabet_size )) // member
647 
648 public:
650  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
652  requires requires
653  {
654  { impl(priority_tag<2>{}, s_alph_t{}, dummy{}) };
655  requires noexcept(impl(priority_tag<2>{}, s_alph_t{}, dummy{}));
656  requires std::integral<std::remove_cvref_t<decltype(impl(priority_tag<2>{}, s_alph_t{}, dummy{}))>>;
657  }
659  constexpr auto operator()() const noexcept
660  {
661  // The following cannot be added to the list of constraints, because it is not properly deferred
662  // for incomplete types which leads to breakage.
663  static_assert(SEQAN3_IS_CONSTEXPR(impl(priority_tag<2>{}, s_alph_t{})),
664  "Only overloads that are marked constexpr are picked up by seqan3::alphabet_size.");
665  return impl(priority_tag<2>{}, s_alph_t{});
666  }
667 };
668 
669 #if SEQAN3_WORKAROUND_GCC_89953
670 template <typename alph_t>
671  requires requires { { alphabet_size_fn<alph_t>{} }; }
672 inline constexpr auto alphabet_size_obj = alphabet_size_fn<alph_t>{};
673 #endif // SEQAN3_WORKAROUND_GCC_89953
674 
675 } // namespace seqan3::detail::adl_only
676 
677 namespace seqan3
678 {
679 
720 #if SEQAN3_WORKAROUND_GCC_89953
721 template <typename alph_t>
723  requires requires { { detail::adl_only::alphabet_size_fn<alph_t>{} }; } &&
724  requires { { detail::adl_only::alphabet_size_obj<alph_t>() }; } // ICE workarounds
726 inline constexpr auto alphabet_size = detail::adl_only::alphabet_size_obj<alph_t>();
727 #else // ^^^ workaround / no workaround vvv
728 template <typename alph_t>
730  requires requires { { detail::adl_only::alphabet_size_fn<alph_t>{}() }; }
732 inline constexpr auto alphabet_size = detail::adl_only::alphabet_size_fn<alph_t>{}();
733 #endif // SEQAN3_WORKAROUND_GCC_89953
734 
735 // ============================================================================
736 // semialphabet
737 // ============================================================================
738 
781 template <typename t>
782 SEQAN3_CONCEPT semialphabet =
783  std::totally_ordered<t> &&
784  std::copy_constructible<t> &&
785  std::is_nothrow_copy_constructible_v<t> &&
786  requires (t v)
787 {
788  { seqan3::alphabet_size<t> };
789  { seqan3::to_rank(v) };
790 };
792 
793 // ============================================================================
794 // writable_semialphabet
795 // ============================================================================
796 
832 template <typename t>
833 SEQAN3_CONCEPT writable_semialphabet = semialphabet<t> && requires (t v, alphabet_rank_t<t> r)
834 {
835  { seqan3::assign_rank_to(r, v) };
836 };
838 
839 // ============================================================================
840 // alphabet
841 // ============================================================================
842 
871 template <typename t>
872 SEQAN3_CONCEPT alphabet = semialphabet<t> && requires (t v)
873 {
874  { seqan3::to_char(v) };
875 };
877 
878 // ============================================================================
879 // writable_alphabet
880 // ============================================================================
881 
919 template <typename t>
920 SEQAN3_CONCEPT writable_alphabet = alphabet<t> && writable_semialphabet<t> && requires (t v, alphabet_char_t<t> c)
921 {
922  { seqan3::assign_char_to(c, v) };
923 };
925 
926 // ============================================================================
927 // serialisation
928 // ============================================================================
929 
951 template <cereal_output_archive archive_t, semialphabet alphabet_t>
952 alphabet_rank_t<alphabet_t> CEREAL_SAVE_MINIMAL_FUNCTION_NAME(archive_t const &, alphabet_t const & l)
953 {
954  return to_rank(l);
955 }
956 
970 template <cereal_input_archive archive_t, typename wrapped_alphabet_t>
971 void CEREAL_LOAD_MINIMAL_FUNCTION_NAME(archive_t const &,
972  wrapped_alphabet_t && l,
973  alphabet_rank_t<detail::strip_cereal_wrapper_t<wrapped_alphabet_t>> const & r)
975 {
976  assign_rank_to(r, static_cast<detail::strip_cereal_wrapper_t<wrapped_alphabet_t> &>(l));
977 }
982 } // namespace seqan3
983 
984 namespace seqan3::detail
985 {
986 // ============================================================================
987 // constexpr_semialphabet
988 // ============================================================================
989 
999 template <typename t>
1000 SEQAN3_CONCEPT constexpr_semialphabet = semialphabet<t> && requires
1001 {
1002  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1004 };
1006 
1007 // ============================================================================
1008 // writable_constexpr_semialphabet
1009 // ============================================================================
1010 
1021 template <typename t>
1022 SEQAN3_CONCEPT writable_constexpr_semialphabet = constexpr_semialphabet<t> && writable_semialphabet<t> && requires
1023 {
1024  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1025  requires SEQAN3_IS_CONSTEXPR(seqan3::assign_rank_to(alphabet_rank_t<t>{}, std::remove_reference_t<t>{}));
1026 };
1028 
1029 // ============================================================================
1030 // constexpr_alphabet
1031 // ============================================================================
1032 
1043 template <typename t>
1044 SEQAN3_CONCEPT constexpr_alphabet = constexpr_semialphabet<t> && alphabet<t> && requires
1045 {
1046  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1048 };
1050 
1051 // ============================================================================
1052 // writable_constexpr_alphabet
1053 // ============================================================================
1054 
1066 template <typename t>
1067 SEQAN3_CONCEPT writable_constexpr_alphabet =
1068  constexpr_alphabet<t> && writable_constexpr_semialphabet<t> && writable_alphabet<t> && requires
1069 {
1070  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1071  requires SEQAN3_IS_CONSTEXPR(seqan3::assign_char_to(alphabet_char_t<t>{}, std::remove_reference_t<t>{}));
1072 };
1074 
1075 } // namespace seqan3::detail
Exceptions thrown by entities in the alphabet module.
Adaptions of concepts from the Cereal library.
Helper utilities for defining customisation point objects (CPOs).
#define SEQAN3_CPO_IMPL(PRIO, TERM)
A macro that helps defining the overload set of a customisation point.
Definition: customisation_point.hpp:47
#define SEQAN3_CPO_OVERLOAD(...)
A macro that helps to define a seqan3::detail::customisation_point_object.
Definition: customisation_point.hpp:113
Provides concepts for core language types and relations that don't have concepts in C++20 (yet).
constexpr auto assign_char_to
Assign a character to an alphabet object.
Definition: concept.hpp:435
constexpr auto to_char
Return the char representation of an alphabet object.
Definition: concept.hpp:334
decltype(seqan3::to_rank(std::declval< semi_alphabet_type >())) alphabet_rank_t
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank.
Definition: concept.hpp:155
constexpr auto alphabet_size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:723
constexpr auto assign_rank_to
Assign a rank to an alphabet object.
Definition: concept.hpp:244
decltype(seqan3::to_char(std::declval< alphabet_type const >())) alphabet_char_t
The char_type of the alphabet; defined as the return type of seqan3::to_char.
Definition: concept.hpp:346
constexpr auto char_is_valid_for
Returns whether a character is in the valid set of a seqan3::alphabet (usually implies a bijective ma...
Definition: concept.hpp:542
constexpr auto assign_char_strictly_to
Assign a character to an alphabet object, throw if the character is not valid.
Definition: concept.hpp:606
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:146
#define SEQAN3_IS_CONSTEXPR(...)
Returns true if the expression passed to this macro can be evaluated at compile time,...
Definition: basic.hpp:28
The generic alphabet concept that covers most data types used in ranges.
The basis for seqan3::alphabet, but requires only rank interface (not char).
Refines seqan3::alphabet and adds assignability.
A refinement of seqan3::semialphabet that adds assignability.
A namespace for third party and standard library specialisations of SeqAn customisation points.
Definition: char.hpp:44
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
#define SEQAN3_RETURN_TYPE_CONSTRAINT(expression, concept_name,...)
Same as writing {expression} -> concept_name<type1[, ...]> in a concept definition.
Definition: platform.hpp:57
A type that can be specialised to provide customisation point implementations so that third party typ...
Definition: concept.hpp:49
An exception typically thrown by seqan3::alphabet::assign_char_strict.
Definition: exception.hpp:26
Provides traits to inspect some information of a type, for example its name.
Provides C++20 additions to the type_traits header.
Provides various type traits on generic types.