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 
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 
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 {
262 public:
263  SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet<decltype(v)>::to_char(v)) // explicit customisation
264  SEQAN3_CPO_IMPL(1, to_char(v) ) // ADL
265  SEQAN3_CPO_IMPL(0, v.to_char() ) // member
266 
267 public:
269  template <typename alph_t>
271  requires requires (alph_t const a)
272  {
273  { impl(priority_tag<2>{}, a) };
274  requires noexcept(impl(priority_tag<2>{}, a));
275  requires builtin_character<decltype(impl(priority_tag<2>{}, a))>;
276  }
278  constexpr decltype(auto) operator()(alph_t const a) const noexcept
279  {
280  return impl(priority_tag<2>{}, a);
281  }
282 };
283 
284 } // namespace seqan3::detail::adl_only
285 
286 namespace seqan3
287 {
288 
328 inline constexpr auto to_char = detail::adl_only::to_char_fn{};
330 
336 template <typename alphabet_type>
338  requires requires (alphabet_type const a) { { seqan3::to_char(a) }; }
340 using alphabet_char_t = decltype(seqan3::to_char(std::declval<alphabet_type const>()));
341 
342 } // namespace seqan3
343 
344 // ============================================================================
345 // assign_char_to()
346 // ============================================================================
347 
348 namespace seqan3::detail::adl_only
349 {
350 
352 template <typename ...args_t>
353 void assign_char_to(args_t ...) = delete;
354 
358 {
359 public:
360  SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::assign_char_to(args..., v))) // explicit customisation
361  SEQAN3_CPO_IMPL(1, (assign_char_to(args..., v) )) // ADL
362  SEQAN3_CPO_IMPL(0, (v.assign_char(args...) )) // member
363 
364 public:
366  template <typename alph_t>
368  requires requires (seqan3::alphabet_char_t<alph_t> const r, alph_t & a)
369  {
370  { impl(priority_tag<2>{}, a, r) };
371  requires noexcept(impl(priority_tag<2>{}, a, r));
372  requires std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, r))>;
373  }
375  constexpr alph_t operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t && a) const noexcept
376  {
377  return impl(priority_tag<2>{}, a, r);
378  }
379 };
380 
381 } // namespace seqan3::detail::adl_only
382 
383 namespace seqan3
384 {
385 
431 } // namespace seqan3
432 
433 // ============================================================================
434 // char_is_valid_for()
435 // ============================================================================
436 
437 namespace seqan3::detail::adl_only
438 {
439 
441 template <typename ...args_t>
442 void char_is_valid_for(args_t ...) = delete;
443 
448 template <typename alph_t>
450 {
451 public:
456 
457  SEQAN3_CPO_IMPL(3, (deferred_type_t<seqan3::custom::alphabet<alph_t>, decltype(v)>::char_is_valid(v))) // expl. cst.
459  SEQAN3_CPO_IMPL(1, (deferred_type_t<std::remove_cvref_t<alph_t>, decltype(v)>::char_is_valid(v) )) // member
461 
462 public:
464  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
466  requires requires (alphabet_char_t<alph_t> const a)
467  {
468  { impl(priority_tag<3>{}, a, dummy{}) };
469  requires noexcept(impl(priority_tag<3>{}, a, dummy{}));
470  SEQAN3_RETURN_TYPE_CONSTRAINT(impl(priority_tag<3>{}, a, dummy{}), std::convertible_to, bool);
471  }
473  constexpr bool operator()(alphabet_char_t<alph_t> const a) const noexcept
474  {
475  return impl(priority_tag<3>{}, a);
476  }
477 };
478 
479 } // namespace seqan3::detail::adl_only
480 
481 namespace seqan3
482 {
483 
532 template <typename alph_t>
534  requires requires { { to_char(std::declval<alph_t>()) }; } // to_char() is required by some defs
538 } // namespace seqan3
539 
540 // ============================================================================
541 // assign_char_strictly_to()
542 // ============================================================================
543 
544 namespace seqan3::detail::adl_only
545 {
546 
550 {
552  template <typename alph_t>
554  requires requires (alph_t a, seqan3::alphabet_char_t<alph_t> r)
555  {
556  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::assign_char_to(r, a), std::convertible_to, alph_t);
557  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::char_is_valid_for<alph_t>(r), std::same_as, bool);
558  }
560  decltype(auto) operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t & a) const
561  {
562  if (!seqan3::char_is_valid_for<alph_t>(r))
563  throw seqan3::invalid_char_assignment{detail::type_name_as_string<alph_t>, r};
564 
565  return seqan3::assign_char_to(r, a);
566  }
567 
569  template <typename alph_t>
571  requires requires (alph_t a, seqan3::alphabet_char_t<alph_t> r)
572  {
573  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::assign_char_to(r, a), std::convertible_to, alph_t);
574  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::char_is_valid_for<alph_t>(r), std::same_as, bool);
575  }
577  auto operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t && a) const
578  {
579  return operator()(r, a); // call above function but return by value
580  }
581 };
582 
583 } // namespace seqan3::detail::adl_only
584 
585 namespace seqan3
586 {
587 
615 } // namespace seqan3
616 
617 // ============================================================================
618 // alphabet_size
619 // ============================================================================
620 
621 namespace seqan3::detail::adl_only
622 {
623 
625 template <typename ...args_t>
626 void alphabet_size(args_t ...) = delete;
627 
632 template <typename alph_t>
634 {
635 public:
638  seqan3::is_constexpr_default_constructible_v<std::remove_cvref_t<alph_t>>,
641 
644  SEQAN3_CPO_IMPL(0, (deferred_type_t<std::remove_cvref_t<alph_t>, decltype(v)>::alphabet_size )) // member
645 
646 public:
648  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
650  requires requires
651  {
652  { impl(priority_tag<2>{}, s_alph_t{}, dummy{}) };
653  requires noexcept(impl(priority_tag<2>{}, s_alph_t{}, dummy{}));
654  requires std::integral<std::remove_cvref_t<decltype(impl(priority_tag<2>{}, s_alph_t{}, dummy{}))>>;
655  }
657  constexpr auto operator()() const noexcept
658  {
659  // The following cannot be added to the list of constraints, because it is not properly deferred
660  // for incomplete types which leads to breakage.
661  static_assert(SEQAN3_IS_CONSTEXPR(impl(priority_tag<2>{}, s_alph_t{})),
662  "Only overloads that are marked constexpr are picked up by seqan3::alphabet_size.");
663  return impl(priority_tag<2>{}, s_alph_t{});
664  }
665 };
666 
667 #if SEQAN3_WORKAROUND_GCC_89953
668 template <typename alph_t>
669  requires requires { { alphabet_size_fn<alph_t>{} }; }
670 inline constexpr auto alphabet_size_obj = alphabet_size_fn<alph_t>{};
671 #endif // SEQAN3_WORKAROUND_GCC_89953
672 
673 } // namespace seqan3::detail::adl_only
674 
675 namespace seqan3
676 {
677 
718 #if SEQAN3_WORKAROUND_GCC_89953
719 template <typename alph_t>
721  requires requires { { detail::adl_only::alphabet_size_fn<alph_t>{} }; } &&
722  requires { { detail::adl_only::alphabet_size_obj<alph_t>() }; } // ICE workarounds
724 inline constexpr auto alphabet_size = detail::adl_only::alphabet_size_obj<alph_t>();
725 #else // ^^^ workaround / no workaround vvv
726 template <typename alph_t>
728  requires requires { { detail::adl_only::alphabet_size_fn<alph_t>{}() }; }
731 #endif // SEQAN3_WORKAROUND_GCC_89953
732 
733 // ============================================================================
734 // semialphabet
735 // ============================================================================
736 
779 template <typename t>
780 SEQAN3_CONCEPT semialphabet =
781  std::totally_ordered<t> &&
782  std::copy_constructible<t> &&
783  std::is_nothrow_copy_constructible_v<t> &&
784  requires (t v)
785 {
786  { seqan3::alphabet_size<t> };
787  { seqan3::to_rank(v) };
788 };
790 
791 // ============================================================================
792 // writable_semialphabet
793 // ============================================================================
794 
830 template <typename t>
831 SEQAN3_CONCEPT writable_semialphabet = semialphabet<t> && requires (t v, alphabet_rank_t<t> r)
832 {
833  { seqan3::assign_rank_to(r, v) };
834 };
836 
837 // ============================================================================
838 // alphabet
839 // ============================================================================
840 
869 template <typename t>
870 SEQAN3_CONCEPT alphabet = semialphabet<t> && requires (t v)
871 {
872  { seqan3::to_char(v) };
873 };
875 
876 // ============================================================================
877 // writable_alphabet
878 // ============================================================================
879 
917 template <typename t>
918 SEQAN3_CONCEPT writable_alphabet = alphabet<t> && writable_semialphabet<t> && requires (t v, alphabet_char_t<t> c)
919 {
920  { seqan3::assign_char_to(c, v) };
921 };
923 
924 // ============================================================================
925 // serialisation
926 // ============================================================================
927 
949 template <cereal_output_archive archive_t, semialphabet alphabet_t>
950 alphabet_rank_t<alphabet_t> CEREAL_SAVE_MINIMAL_FUNCTION_NAME(archive_t const &, alphabet_t const & l)
951 {
952  return to_rank(l);
953 }
954 
968 template <cereal_input_archive archive_t, typename wrapped_alphabet_t>
969 void CEREAL_LOAD_MINIMAL_FUNCTION_NAME(archive_t const &,
970  wrapped_alphabet_t && l,
971  alphabet_rank_t<detail::strip_cereal_wrapper_t<wrapped_alphabet_t>> const & r)
973 {
974  assign_rank_to(r, static_cast<detail::strip_cereal_wrapper_t<wrapped_alphabet_t> &>(l));
975 }
980 } // namespace seqan3
981 
982 namespace seqan3::detail
983 {
984 // ============================================================================
985 // constexpr_semialphabet
986 // ============================================================================
987 
997 template <typename t>
998 SEQAN3_CONCEPT constexpr_semialphabet = semialphabet<t> && requires
999 {
1000  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1002 };
1004 
1005 // ============================================================================
1006 // writable_constexpr_semialphabet
1007 // ============================================================================
1008 
1019 template <typename t>
1021 {
1022  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1023  requires SEQAN3_IS_CONSTEXPR(seqan3::assign_rank_to(alphabet_rank_t<t>{}, std::remove_reference_t<t>{}));
1024 };
1026 
1027 // ============================================================================
1028 // constexpr_alphabet
1029 // ============================================================================
1030 
1041 template <typename t>
1042 SEQAN3_CONCEPT constexpr_alphabet = constexpr_semialphabet<t> && alphabet<t> && requires
1043 {
1044  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1046 };
1048 
1049 // ============================================================================
1050 // writable_constexpr_alphabet
1051 // ============================================================================
1052 
1064 template <typename t>
1065 SEQAN3_CONCEPT writable_constexpr_alphabet =
1067 {
1068  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1069  requires SEQAN3_IS_CONSTEXPR(seqan3::assign_char_to(alphabet_char_t<t>{}, std::remove_reference_t<t>{}));
1070 };
1072 
1073 } // 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.
#define SEQAN3_CPO_IMPL(PRIO, TERM)
A macro that helps defining the overload set of a customisation point.
Definition: customisation_point.hpp:45
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:429
constexpr auto to_char
Return the char representation of an alphabet object.
Definition: concept.hpp:328
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:730
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:340
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:536
constexpr auto assign_char_strictly_to
Assign a character to an alphabet object, throw if the character is not valid.
Definition: concept.hpp:613
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:146
typename deferred_type< t, dependent_ts... >::type deferred_type_t
Return the type identity; further arguments are ignored, but can make this type dependent if they are...
Definition: basic.hpp:134
#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.
This concept encompasses exactly the types char, signed char, unsigned char, wchar_t,...
A seqan3::alphabet that has constexpr accessors.
A seqan3::semialphabet that has constexpr accessors.
A seqan3::writable_alphabet that has constexpr accessors.
A seqan3::writable_semialphabet that has a constexpr assignment.
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 internal SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
SeqAn specific customisations in the standard namespace.
#define CEREAL_LOAD_MINIMAL_FUNCTION_NAME
Macro for Cereal's load_minimal function.
Definition: platform.hpp:140
#define CEREAL_SAVE_MINIMAL_FUNCTION_NAME
Macro for Cereal's save_minimal function.
Definition: platform.hpp:142
#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
Functor definition used indirectly by for seqan3::detail::alphabet_size.
Definition: concept.hpp:634
constexpr auto operator()() const noexcept
Operator definition.
Definition: concept.hpp:657
static constexpr decltype(auto) impl(seqan3::detail::priority_tag< 2 >, [[maybe_unused]] t &&v, [[maybe_unused]] arg_ts &&... args) noexcept(noexcept((deferred_type_t< seqan3::custom::alphabet< alph_t >, decltype(v)>::alphabet_size))) requires requires(seqan3
A customisation point overload.
Definition: concept.hpp:642
Functor definition for seqan3::assign_char_strictly_to.
Definition: concept.hpp:550
auto operator()(seqan3::alphabet_char_t< alph_t > const r, alph_t &&a) const
Operator overload for rvalues.
Definition: concept.hpp:577
decltype(auto) operator()(seqan3::alphabet_char_t< alph_t > const r, alph_t &a) const
Operator overload for lvalues.
Definition: concept.hpp:560
Functor definition for seqan3::assign_char_to.
Definition: concept.hpp:358
static constexpr decltype(auto) impl(seqan3::detail::priority_tag< 2 >, [[maybe_unused]] t &&v, [[maybe_unused]] arg_ts &&... args) noexcept(noexcept((seqan3::custom::alphabet< decltype(v)>::assign_char_to(args..., v)))) requires requires(seqan3
A customisation point overload.
Definition: concept.hpp:360
constexpr alph_t operator()(seqan3::alphabet_char_t< alph_t > const r, alph_t &&a) const noexcept
Operator definition.
Definition: concept.hpp:375
Functor definition for seqan3::assign_rank_to.
Definition: concept.hpp:173
constexpr alph_t operator()(seqan3::alphabet_rank_t< alph_t > const r, alph_t &&a) const noexcept
Operator definition.
Definition: concept.hpp:190
static constexpr decltype(auto) impl(seqan3::detail::priority_tag< 2 >, [[maybe_unused]] t &&v, [[maybe_unused]] arg_ts &&... args) noexcept(noexcept((seqan3::custom::alphabet< decltype(v)>::assign_rank_to(args..., v)))) requires requires(seqan3
A customisation point overload.
Definition: concept.hpp:175
Functor definition for seqan3::char_is_valid_for.
Definition: concept.hpp:450
constexpr bool operator()(alphabet_char_t< alph_t > const a) const noexcept
Operator definition.
Definition: concept.hpp:473
static constexpr decltype(auto) impl(seqan3::detail::priority_tag< 3 >, [[maybe_unused]] t &&v, [[maybe_unused]] arg_ts &&... args) noexcept(noexcept((deferred_type_t< seqan3::custom::alphabet< alph_t >, decltype(v)>::char_is_valid(v)))) requires requires(seqan3
A customisation point overload.
Definition: concept.hpp:457
Functor definition for seqan3::to_char.
Definition: concept.hpp:261
static constexpr decltype(auto) impl(seqan3::detail::priority_tag< 2 >, [[maybe_unused]] t &&v, [[maybe_unused]] arg_ts &&... args) noexcept(noexcept(seqan3::custom::alphabet< decltype(v)>::to_char(v))) requires requires(seqan3
A customisation point overload.
Definition: concept.hpp:263
Functor definition for seqan3::to_rank.
Definition: concept.hpp:80
static constexpr decltype(auto) impl(seqan3::detail::priority_tag< 2 >, [[maybe_unused]] t &&v, [[maybe_unused]] arg_ts &&... args) noexcept(noexcept(seqan3::custom::alphabet< decltype(v)>::to_rank(v))) requires requires(seqan3
A customisation point overload.
Definition: concept.hpp:82
constexpr auto operator()(alph_t const a) const noexcept
Operator definition.
Definition: concept.hpp:97
A tag that allows controlled overload resolution via implicit base conversion rules.
Definition: customisation_point.hpp:31
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.