SeqAn3  3.0.2
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 
21 #include <seqan3/std/type_traits>
22 
23 // ============================================================================
24 // forwards
25 // ============================================================================
26 
27 namespace seqan3::custom
28 {
29 
46 template <typename t>
47 struct alphabet
48 {};
49 
51 template <typename t>
52 struct alphabet<t const> : alphabet<t>
53 {};
54 
55 template <typename t>
56 struct alphabet<t &> : alphabet<t>
57 {};
58 
59 template <typename t>
60 struct alphabet<t const &> : alphabet<t>
61 {};
63 
64 } // namespace seqan3::custom
65 
66 // ============================================================================
67 // to_rank()
68 // ============================================================================
69 
70 namespace seqan3::detail::adl_only
71 {
72 
74 template <typename ...args_t>
75 void to_rank(args_t ...) = delete;
76 
78 struct to_rank_fn
79 {
80 public:
81  SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet<decltype(v)>::to_rank(v)) // explicit customisation
82  SEQAN3_CPO_IMPL(1, to_rank(v) ) // ADL
83  SEQAN3_CPO_IMPL(0, v.to_rank() ) // member
84 
85 public:
87  template <typename alph_t>
89  requires requires (alph_t const a)
90  {
91  { impl(priority_tag<2>{}, a) };
92  requires noexcept(impl(priority_tag<2>{}, a));
93  requires std::integral<decltype(impl(priority_tag<2>{}, a))>;
94  }
96  constexpr auto operator()(alph_t const a) const noexcept
97  {
98  return impl(priority_tag<2>{}, a);
99  }
100 };
101 
102 } // namespace seqan3::detail::adl_only
103 
104 namespace seqan3
105 {
106 
143 inline constexpr auto to_rank = detail::adl_only::to_rank_fn{};
145 
148 template <typename semi_alphabet_type>
150  requires requires { { seqan3::to_rank(std::declval<semi_alphabet_type>()) }; }
152 using alphabet_rank_t = decltype(seqan3::to_rank(std::declval<semi_alphabet_type>()));
153 
154 } // namespace seqan3
155 
156 // ============================================================================
157 // assign_rank_to()
158 // ============================================================================
159 
160 namespace seqan3::detail::adl_only
161 {
162 
164 template <typename ...args_t>
165 void assign_rank_to(args_t ...) = delete;
166 
169 struct assign_rank_to_fn
170 {
171 public:
172  SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::assign_rank_to(args..., v))) // explicit customisation
173  SEQAN3_CPO_IMPL(1, (assign_rank_to(args..., v) )) // ADL
174  SEQAN3_CPO_IMPL(0, (v.assign_rank(args...) )) // member
175 
176 public:
178  template <typename alph_t>
180  requires requires (seqan3::alphabet_rank_t<alph_t> const r, alph_t & a)
181  {
182  { impl(priority_tag<2>{}, a, r) };
183  requires noexcept(impl(priority_tag<2>{}, a, r));
184  requires std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, r))>;
185  }
187  constexpr alph_t operator()(seqan3::alphabet_rank_t<alph_t> const r, alph_t && a) const noexcept
188  {
189  return impl(priority_tag<2>{}, a, r);
190  }
191 };
192 
193 } // namespace seqan3::detail::adl_only
194 
195 namespace seqan3
196 {
197 
239 inline constexpr auto assign_rank_to = detail::adl_only::assign_rank_to_fn{};
241 } // namespace seqan3
242 
243 // ============================================================================
244 // to_char()
245 // ============================================================================
246 
247 namespace seqan3::detail::adl_only
248 {
249 
251 template <typename ...args_t>
252 void to_char(args_t ...) = delete;
253 
255 struct to_char_fn
256 {
257 public:
258  SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet<decltype(v)>::to_char(v)) // explicit customisation
259  SEQAN3_CPO_IMPL(1, to_char(v) ) // ADL
260  SEQAN3_CPO_IMPL(0, v.to_char() ) // member
261 
262 public:
264  template <typename alph_t>
266  requires requires (alph_t const a)
267  {
268  { impl(priority_tag<2>{}, a) };
269  requires noexcept(impl(priority_tag<2>{}, a));
270  requires builtin_character<decltype(impl(priority_tag<2>{}, a))>;
271  }
273  constexpr decltype(auto) operator()(alph_t const a) const noexcept
274  {
275  return impl(priority_tag<2>{}, a);
276  }
277 };
278 
279 } // namespace seqan3::detail::adl_only
280 
281 namespace seqan3
282 {
283 
321 inline constexpr auto to_char = detail::adl_only::to_char_fn{};
323 
326 template <typename alphabet_type>
328  requires requires (alphabet_type const a) { { seqan3::to_char(a) }; }
330 using alphabet_char_t = decltype(seqan3::to_char(std::declval<alphabet_type const>()));
331 
332 } // namespace seqan3
333 
334 // ============================================================================
335 // assign_char_to()
336 // ============================================================================
337 
338 namespace seqan3::detail::adl_only
339 {
340 
342 template <typename ...args_t>
343 void assign_char_to(args_t ...) = delete;
344 
347 struct assign_char_to_fn
348 {
349 public:
350  SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::assign_char_to(args..., v))) // explicit customisation
351  SEQAN3_CPO_IMPL(1, (assign_char_to(args..., v) )) // ADL
352  SEQAN3_CPO_IMPL(0, (v.assign_char(args...) )) // member
353 
354 public:
356  template <typename alph_t>
358  requires requires (seqan3::alphabet_char_t<alph_t> const r, alph_t & a)
359  {
360  { impl(priority_tag<2>{}, a, r) };
361  requires noexcept(impl(priority_tag<2>{}, a, r));
362  requires std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, r))>;
363  }
365  constexpr alph_t operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t && a) const noexcept
366  {
367  return impl(priority_tag<2>{}, a, r);
368  }
369 };
370 
371 } // namespace seqan3::detail::adl_only
372 
373 namespace seqan3
374 {
375 
417 inline constexpr auto assign_char_to = detail::adl_only::assign_char_to_fn{};
419 } // namespace seqan3
420 
421 // ============================================================================
422 // char_is_valid_for()
423 // ============================================================================
424 
425 namespace seqan3::detail::adl_only
426 {
427 
429 template <typename ...args_t>
430 void char_is_valid_for(args_t ...) = delete;
431 
436 template <typename alph_t>
437 struct char_is_valid_for_fn
438 {
439 public:
444 
445  SEQAN3_CPO_IMPL(3, (deferred_type_t<seqan3::custom::alphabet<alph_t>, decltype(v)>::char_is_valid(v))) // expl. cst.
446  SEQAN3_CPO_IMPL(2, (char_is_valid_for(v, s_alph_t{}) )) // ADL
447  SEQAN3_CPO_IMPL(1, (deferred_type_t<std::remove_cvref_t<alph_t>, decltype(v)>::char_is_valid(v) )) // member
448  SEQAN3_CPO_IMPL(0, (seqan3::to_char(seqan3::assign_char_to(v, s_alph_t{})) == v )) // fallback
449 
450 public:
452  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
454  requires requires (alphabet_char_t<alph_t> const a)
455  {
456  { impl(priority_tag<3>{}, a, dummy{}) };
457  requires noexcept(impl(priority_tag<3>{}, a, dummy{}));
458  SEQAN3_RETURN_TYPE_CONSTRAINT(impl(priority_tag<3>{}, a, dummy{}), std::convertible_to, bool);
459  }
461  constexpr bool operator()(alphabet_char_t<alph_t> const a) const noexcept
462  {
463  return impl(priority_tag<3>{}, a);
464  }
465 };
466 
467 } // namespace seqan3::detail::adl_only
468 
469 namespace seqan3
470 {
471 
518 template <typename alph_t>
520  requires requires { { to_char(std::declval<alph_t>()) }; } // to_char() is required by some defs
522 inline constexpr auto char_is_valid_for = detail::adl_only::char_is_valid_for_fn<alph_t>{};
524 } // namespace seqan3
525 
526 // ============================================================================
527 // assign_char_strictly_to()
528 // ============================================================================
529 
530 namespace seqan3::detail::adl_only
531 {
532 
535 struct assign_char_strictly_to_fn
536 {
538  template <typename alph_t>
540  requires requires (alph_t a, seqan3::alphabet_char_t<alph_t> r)
541  {
542  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::assign_char_to(r, a), std::convertible_to, alph_t);
543  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::char_is_valid_for<alph_t>(r), std::same_as, bool);
544  }
546  decltype(auto) operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t & a) const
547  {
548  if (!seqan3::char_is_valid_for<alph_t>(r))
549  throw seqan3::invalid_char_assignment{detail::type_name_as_string<alph_t>, r};
550 
551  return seqan3::assign_char_to(r, a);
552  }
553 
555  template <typename alph_t>
557  requires requires (alph_t a, seqan3::alphabet_char_t<alph_t> r)
558  {
559  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::assign_char_to(r, a), std::convertible_to, alph_t);
560  SEQAN3_RETURN_TYPE_CONSTRAINT(seqan3::char_is_valid_for<alph_t>(r), std::same_as, bool);
561  }
563  auto operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t && a) const
564  {
565  return operator()(r, a); // call above function but return by value
566  }
567 };
568 
569 } // namespace seqan3::detail::adl_only
570 
571 namespace seqan3
572 {
573 
598 inline constexpr auto assign_char_strictly_to = detail::adl_only::assign_char_strictly_to_fn{};
600 } // namespace seqan3
601 
602 // ============================================================================
603 // alphabet_size
604 // ============================================================================
605 
606 namespace seqan3::detail::adl_only
607 {
608 
610 template <typename ...args_t>
611 void alphabet_size(args_t ...) = delete;
612 
617 template <typename alph_t>
618 struct alphabet_size_fn
619 {
620 public:
623  seqan3::is_constexpr_default_constructible_v<std::remove_cvref_t<alph_t>>,
626 
627  SEQAN3_CPO_IMPL(2, (deferred_type_t<seqan3::custom::alphabet<alph_t>, decltype(v)>::alphabet_size)) // expl. cst.
628  SEQAN3_CPO_IMPL(1, (alphabet_size(v) )) // ADL
629  SEQAN3_CPO_IMPL(0, (deferred_type_t<std::remove_cvref_t<alph_t>, decltype(v)>::alphabet_size )) // member
630 
631 public:
633  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
635  requires requires
636  {
637  { impl(priority_tag<2>{}, s_alph_t{}, dummy{}) };
638  requires noexcept(impl(priority_tag<2>{}, s_alph_t{}, dummy{}));
639  requires std::integral<std::remove_cvref_t<decltype(impl(priority_tag<2>{}, s_alph_t{}, dummy{}))>>;
640  }
642  constexpr auto operator()() const noexcept
643  {
644  // The following cannot be added to the list of constraints, because it is not properly deferred
645  // for incomplete types which leads to breakage.
646  static_assert(SEQAN3_IS_CONSTEXPR(impl(priority_tag<2>{}, s_alph_t{})),
647  "Only overloads that are marked constexpr are picked up by seqan3::alphabet_size.");
648  return impl(priority_tag<2>{}, s_alph_t{});
649  }
650 };
651 
653 // required to prevent https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89953
654 template <typename alph_t>
655  requires requires { { alphabet_size_fn<alph_t>{} }; }
656 inline constexpr auto alphabet_size_obj = alphabet_size_fn<alph_t>{};
658 
659 } // namespace seqan3::detail::adl_only
660 
661 namespace seqan3
662 {
663 
702 template <typename alph_t>
704  requires requires { { detail::adl_only::alphabet_size_fn<alph_t>{} }; } &&
705  requires { { detail::adl_only::alphabet_size_obj<alph_t>() }; } // ICE workarounds
707 inline constexpr auto alphabet_size = detail::adl_only::alphabet_size_obj<alph_t>();
708 
709 // ============================================================================
710 // semialphabet
711 // ============================================================================
712 
753 template <typename t>
754 SEQAN3_CONCEPT semialphabet =
755  std::totally_ordered<t> &&
756  std::copy_constructible<t> &&
757  std::is_nothrow_copy_constructible_v<t> &&
758  requires (t v)
759 {
760  { seqan3::alphabet_size<t> };
761  { seqan3::to_rank(v) };
762 };
764 
765 // ============================================================================
766 // writable_semialphabet
767 // ============================================================================
768 
802 template <typename t>
803 SEQAN3_CONCEPT writable_semialphabet = semialphabet<t> && requires (t v, alphabet_rank_t<t> r)
804 {
805  { seqan3::assign_rank_to(r, v) };
806 };
808 
809 // ============================================================================
810 // alphabet
811 // ============================================================================
812 
839 template <typename t>
840 SEQAN3_CONCEPT alphabet = semialphabet<t> && requires (t v)
841 {
842  { seqan3::to_char(v) };
843 };
845 
846 // ============================================================================
847 // writable_alphabet
848 // ============================================================================
849 
886 template <typename t>
887 SEQAN3_CONCEPT writable_alphabet = alphabet<t> && writable_semialphabet<t> && requires (t v, alphabet_char_t<t> c)
888 {
889  { seqan3::assign_char_to(c, v) };
890 
891  { seqan3::char_is_valid_for<t>(c) };
892 };
894 
895 // ============================================================================
896 // serialisation
897 // ============================================================================
898 
918 template <cereal_output_archive archive_t, semialphabet alphabet_t>
919 alphabet_rank_t<alphabet_t> CEREAL_SAVE_MINIMAL_FUNCTION_NAME(archive_t const &, alphabet_t const & l)
920 {
921  return to_rank(l);
922 }
923 
937 template <cereal_input_archive archive_t, typename wrapped_alphabet_t>
938 void CEREAL_LOAD_MINIMAL_FUNCTION_NAME(archive_t const &,
939  wrapped_alphabet_t && l,
940  alphabet_rank_t<detail::strip_cereal_wrapper_t<wrapped_alphabet_t>> const & r)
942 {
943  assign_rank_to(r, static_cast<detail::strip_cereal_wrapper_t<wrapped_alphabet_t> &>(l));
944 }
949 } // namespace seqan3
950 
951 namespace seqan3::detail
952 {
953 // ============================================================================
954 // constexpr_semialphabet
955 // ============================================================================
956 
966 template <typename t>
967 SEQAN3_CONCEPT constexpr_semialphabet = semialphabet<t> && requires
968 {
969  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
971 };
973 
974 // ============================================================================
975 // writable_constexpr_semialphabet
976 // ============================================================================
977 
988 template <typename t>
989 SEQAN3_CONCEPT writable_constexpr_semialphabet = constexpr_semialphabet<t> && writable_semialphabet<t> && requires
990 {
991  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
992  requires SEQAN3_IS_CONSTEXPR(seqan3::assign_rank_to(alphabet_rank_t<t>{}, std::remove_reference_t<t>{}));
993 };
995 
996 // ============================================================================
997 // constexpr_alphabet
998 // ============================================================================
999 
1010 template <typename t>
1011 SEQAN3_CONCEPT constexpr_alphabet = constexpr_semialphabet<t> && alphabet<t> && requires
1012 {
1013  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1015 };
1017 
1018 // ============================================================================
1019 // writable_constexpr_alphabet
1020 // ============================================================================
1021 
1034 template <typename t>
1035 SEQAN3_CONCEPT writable_constexpr_alphabet =
1036  constexpr_alphabet<t> && writable_constexpr_semialphabet<t> && writable_alphabet<t> && requires
1037 {
1038  // currently only tests rvalue interfaces, because we have no constexpr values in this scope to get references to
1039  requires SEQAN3_IS_CONSTEXPR(seqan3::assign_char_to(alphabet_char_t<t>{}, std::remove_reference_t<t>{}));
1040  requires SEQAN3_IS_CONSTEXPR(seqan3::char_is_valid_for<t>(alphabet_char_t<t>{}));
1041 };
1043 
1044 } // namespace seqan3::detail
Exceptions thrown by entities in the alphabet module.
Provides various type traits on generic types.
Adaptions of concepts from the Cereal library.
Provides concepts for core language types and relations that don't have concepts in C++20 (yet).
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
constexpr auto assign_char_to
Assign a character to an alphabet object.
Definition: concept.hpp:417
constexpr auto to_char
Return the char representation of an alphabet object.
Definition: concept.hpp:321
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:152
constexpr auto alphabet_size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:707
constexpr auto assign_rank_to
Assign a rank to an alphabet object.
Definition: concept.hpp:239
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:330
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:522
constexpr auto assign_char_strictly_to
Assign a character to an alphabet object, throw if the character is not valid.
Definition: concept.hpp:598
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:143
#define SEQAN3_IS_CONSTEXPR(...)
Returns true if the expression passed to this macro can be evaluated at compile time,...
Definition: basic.hpp:29
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,...
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
typename remove_cvref< t >::type remove_cvref_t
Return the input type with const, volatile and references removed (transformation_trait shortcut).
Definition: type_traits:56
#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:48
An exception typically thrown by seqan3::alphabet::assign_char_strict.
Definition: exception.hpp:26
The identity transformation (a transformation_trait that returns the input).
Definition: type_traits:73
Provides traits to inspect some information of a type, for example its name.
Provides C++20 additions to the type_traits header.