SeqAn3  3.0.1
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 
20 #include <seqan3/std/type_traits>
21 
22 // ============================================================================
23 // forwards
24 // ============================================================================
25 
26 namespace seqan3::custom
27 {
28 
45 template <typename t>
46 struct alphabet
47 {};
48 
50 template <typename t>
51 struct alphabet<t const> : alphabet<t>
52 {};
53 
54 template <typename t>
55 struct alphabet<t &> : alphabet<t>
56 {};
57 
58 template <typename t>
59 struct alphabet<t const &> : alphabet<t>
60 {};
62 
63 } // namespace seqan3::custom
64 
65 // ============================================================================
66 // to_rank()
67 // ============================================================================
68 
69 namespace seqan3::detail::adl_only
70 {
71 
73 template <typename ...args_t>
74 void to_rank(args_t ...) = delete;
75 
77 struct to_rank_fn
78 {
79 public:
80  SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet<decltype(v)>::to_rank(v)) // explicit customisation
81  SEQAN3_CPO_IMPL(1, to_rank(v) ) // ADL
82  SEQAN3_CPO_IMPL(0, v.to_rank() ) // member
83 
84 public:
86  template <typename alph_t>
88  requires requires (alph_t const a)
89  {
90  { impl(priority_tag<2>{}, a) };
91  requires noexcept(impl(priority_tag<2>{}, a));
92  requires std::integral<decltype(impl(priority_tag<2>{}, a))>;
93  }
95  constexpr auto operator()(alph_t const a) const noexcept
96  {
97  return impl(priority_tag<2>{}, a);
98  }
99 };
100 
101 } // namespace seqan3::detail::adl_only
102 
103 namespace seqan3
104 {
105 
142 inline constexpr auto to_rank = detail::adl_only::to_rank_fn{};
144 
147 template <typename semi_alphabet_type>
149  requires requires { { seqan3::to_rank(std::declval<semi_alphabet_type>()) }; }
151 using alphabet_rank_t = decltype(seqan3::to_rank(std::declval<semi_alphabet_type>()));
152 
153 } // namespace seqan3
154 
155 // ============================================================================
156 // assign_rank_to()
157 // ============================================================================
158 
159 namespace seqan3::detail::adl_only
160 {
161 
163 template <typename ...args_t>
164 void assign_rank_to(args_t ...) = delete;
165 
168 struct assign_rank_to_fn
169 {
170 public:
171  SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::assign_rank_to(args..., v))) // explicit customisation
172  SEQAN3_CPO_IMPL(1, (assign_rank_to(args..., v) )) // ADL
173  SEQAN3_CPO_IMPL(0, (v.assign_rank(args...) )) // member
174 
175 public:
177  template <typename alph_t>
179  requires requires (seqan3::alphabet_rank_t<alph_t> const r, alph_t & a)
180  {
181  { impl(priority_tag<2>{}, a, r) };
182  requires noexcept(impl(priority_tag<2>{}, a, r));
183  requires std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, r))>;
184  }
186  constexpr alph_t operator()(seqan3::alphabet_rank_t<alph_t> const r, alph_t && a) const noexcept
187  {
188  return impl(priority_tag<2>{}, a, r);
189  }
190 };
191 
192 } // namespace seqan3::detail::adl_only
193 
194 namespace seqan3
195 {
196 
238 inline constexpr auto assign_rank_to = detail::adl_only::assign_rank_to_fn{};
240 } // namespace seqan3
241 
242 // ============================================================================
243 // to_char()
244 // ============================================================================
245 
246 namespace seqan3::detail::adl_only
247 {
248 
250 template <typename ...args_t>
251 void to_char(args_t ...) = delete;
252 
254 struct to_char_fn
255 {
256 public:
257  SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet<decltype(v)>::to_char(v)) // explicit customisation
258  SEQAN3_CPO_IMPL(1, to_char(v) ) // ADL
259  SEQAN3_CPO_IMPL(0, v.to_char() ) // member
260 
261 public:
263  template <typename alph_t>
265  requires requires (alph_t const a)
266  {
267  { impl(priority_tag<2>{}, a) };
268  requires noexcept(impl(priority_tag<2>{}, a));
269  requires builtin_character<decltype(impl(priority_tag<2>{}, a))>;
270  }
272  constexpr decltype(auto) operator()(alph_t const a) const noexcept
273  {
274  return impl(priority_tag<2>{}, a);
275  }
276 };
277 
278 } // namespace seqan3::detail::adl_only
279 
280 namespace seqan3
281 {
282 
320 inline constexpr auto to_char = detail::adl_only::to_char_fn{};
322 
325 template <typename alphabet_type>
327  requires requires (alphabet_type const a) { { seqan3::to_char(a) }; }
329 using alphabet_char_t = decltype(seqan3::to_char(std::declval<alphabet_type const>()));
330 
331 } // namespace seqan3
332 
333 // ============================================================================
334 // assign_char_to()
335 // ============================================================================
336 
337 namespace seqan3::detail::adl_only
338 {
339 
341 template <typename ...args_t>
342 void assign_char_to(args_t ...) = delete;
343 
346 struct assign_char_to_fn
347 {
348 public:
349  SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::assign_char_to(args..., v))) // explicit customisation
350  SEQAN3_CPO_IMPL(1, (assign_char_to(args..., v) )) // ADL
351  SEQAN3_CPO_IMPL(0, (v.assign_char(args...) )) // member
352 
353 public:
355  template <typename alph_t>
357  requires requires (seqan3::alphabet_char_t<alph_t> const r, alph_t & a)
358  {
359  { impl(priority_tag<2>{}, a, r) };
360  requires noexcept(impl(priority_tag<2>{}, a, r));
361  requires std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, r))>;
362  }
364  constexpr alph_t operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t && a) const noexcept
365  {
366  return impl(priority_tag<2>{}, a, r);
367  }
368 };
369 
370 } // namespace seqan3::detail::adl_only
371 
372 namespace seqan3
373 {
374 
416 inline constexpr auto assign_char_to = detail::adl_only::assign_char_to_fn{};
418 } // namespace seqan3
419 
420 // ============================================================================
421 // char_is_valid_for()
422 // ============================================================================
423 
424 namespace seqan3::detail::adl_only
425 {
426 
428 template <typename ...args_t>
429 void char_is_valid_for(args_t ...) = delete;
430 
435 template <typename alph_t>
436 struct char_is_valid_for_fn
437 {
438 public:
441  remove_cvref_t<alph_t>,
443 
444  SEQAN3_CPO_IMPL(3, (deferred_type_t<seqan3::custom::alphabet<alph_t>, decltype(v)>::char_is_valid(v))) // expl. cst.
445  SEQAN3_CPO_IMPL(2, (char_is_valid_for(v, s_alph_t{}) )) // ADL
446  SEQAN3_CPO_IMPL(1, (deferred_type_t<remove_cvref_t<alph_t>, decltype(v)>::char_is_valid(v) )) // member
447  SEQAN3_CPO_IMPL(0, (seqan3::to_char(seqan3::assign_char_to(v, s_alph_t{})) == v )) // fallback
448 
449 public:
451  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
453  requires requires (alphabet_char_t<alph_t> const a)
454  {
455  { impl(priority_tag<3>{}, a, dummy{}) };
456  requires noexcept(impl(priority_tag<3>{}, a));
457  requires std::convertible_to<decltype(impl(priority_tag<3>{}, a)), bool>;
458  }
460  constexpr bool operator()(alphabet_char_t<alph_t> const a) const noexcept
461  {
462  return impl(priority_tag<3>{}, a);
463  }
464 };
465 
466 } // namespace seqan3::detail::adl_only
467 
468 namespace seqan3
469 {
470 
517 template <typename alph_t>
519  requires requires { { to_char(std::declval<alph_t>()) }; } // to_char() is required by some defs
521 inline constexpr auto char_is_valid_for = detail::adl_only::char_is_valid_for_fn<alph_t>{};
523 } // namespace seqan3
524 
525 // ============================================================================
526 // assign_char_strictly_to()
527 // ============================================================================
528 
529 namespace seqan3::detail::adl_only
530 {
531 
534 struct assign_char_strictly_to_fn
535 {
537  template <typename alph_t>
539  requires requires (alph_t a, seqan3::alphabet_char_t<alph_t> r)
540  {
541  { seqan3::assign_char_to(r, a) } -> alph_t;
542  { seqan3::char_is_valid_for<alph_t>(r) } -> bool;
543  }
545  decltype(auto) operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t & a) const
546  {
547  if (!seqan3::char_is_valid_for<alph_t>(r))
548  throw seqan3::invalid_char_assignment{detail::type_name_as_string<alph_t>, r};
549 
550  return seqan3::assign_char_to(r, a);
551  }
552 
554  template <typename alph_t>
556  requires requires (alph_t a, seqan3::alphabet_char_t<alph_t> r)
557  {
558  { seqan3::assign_char_to(r, a) } -> alph_t;
559  { seqan3::char_is_valid_for<alph_t>(r) } -> bool;
560  }
562  auto operator()(seqan3::alphabet_char_t<alph_t> const r, alph_t && a) const
563  {
564  return operator()(r, a); // call above function but return by value
565  }
566 };
567 
568 } // namespace seqan3::detail::adl_only
569 
570 namespace seqan3
571 {
572 
597 inline constexpr auto assign_char_strictly_to = detail::adl_only::assign_char_strictly_to_fn{};
599 } // namespace seqan3
600 
601 // ============================================================================
602 // alphabet_size
603 // ============================================================================
604 
605 namespace seqan3::detail::adl_only
606 {
607 
609 template <typename ...args_t>
610 void alphabet_size(args_t ...) = delete;
611 
616 template <typename alph_t>
617 struct alphabet_size_fn
618 {
619 public:
622  seqan3::is_constexpr_default_constructible_v<remove_cvref_t<alph_t>>,
623  remove_cvref_t<alph_t>,
625 
626  SEQAN3_CPO_IMPL(2, (deferred_type_t<seqan3::custom::alphabet<alph_t>, decltype(v)>::alphabet_size)) // expl. cst.
627  SEQAN3_CPO_IMPL(1, (alphabet_size(v) )) // ADL
628  SEQAN3_CPO_IMPL(0, (deferred_type_t<remove_cvref_t<alph_t>, decltype(v)>::alphabet_size )) // member
629 
630 public:
632  template <typename dummy = int> // need to make this a template to enforce deferred instantiation
634  requires requires
635  {
636  { impl(priority_tag<2>{}, s_alph_t{}, dummy{}) };
637  requires noexcept(impl(priority_tag<2>{}, s_alph_t{}, dummy{}));
638  requires std::integral<remove_cvref_t<decltype(impl(priority_tag<2>{}, s_alph_t{}, dummy{}))>>;
639  }
641  constexpr auto operator()() const noexcept
642  {
643  // The following cannot be added to the list of constraints, because it is not properly deferred
644  // for incomplete types which leads to breakage.
645  static_assert(SEQAN3_IS_CONSTEXPR(impl(priority_tag<2>{}, s_alph_t{})),
646  "Only overloads that are marked constexpr are picked up by seqan3::alphabet_size.");
647  return impl(priority_tag<2>{}, s_alph_t{});
648  }
649 };
650 
652 // required to prevent https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89953
653 template <typename alph_t>
654  requires requires { { alphabet_size_fn<alph_t>{} }; }
655 inline constexpr auto alphabet_size_obj = alphabet_size_fn<alph_t>{};
657 
658 } // namespace seqan3::detail::adl_only
659 
660 namespace seqan3
661 {
662 
701 template <typename alph_t>
703  requires requires { { detail::adl_only::alphabet_size_fn<alph_t>{} }; } &&
704  requires { { detail::adl_only::alphabet_size_obj<alph_t>() }; } // ICE workarounds
706 inline constexpr auto alphabet_size = detail::adl_only::alphabet_size_obj<alph_t>();
707 
708 // ============================================================================
709 // semialphabet
710 // ============================================================================
711 
751 template <typename t>
753 SEQAN3_CONCEPT semialphabet =
756  std::is_nothrow_copy_constructible_v<t> &&
757  requires (t v)
758 {
759  requires seqan3::alphabet_size<t> >= 0;
760 
761  { seqan3::to_rank(v) };
762 };
764 
765 // ============================================================================
766 // writable_semialphabet
767 // ============================================================================
768 
801 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 
838 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 
885 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 
965 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 
987 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 
1009 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 
1033 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
writable_semialphabet
A refinement of seqan3::semialphabet that adds assignability.
seqan3::remove_cvref_t
std::remove_cv_t< std::remove_reference_t< t > > remove_cvref_t
Return the input type with const, volatile and references removed (type trait).
Definition: basic.hpp:35
seqan3::assign_rank_to
constexpr auto assign_rank_to
Assign a rank to an alphabet object.
Definition: concept.hpp:238
type_traits
Provides C++20 additions to the type_traits header.
seqan3::custom::alphabet
A type that can be specialised to provide customisation point implementations so that third party typ...
Definition: concept.hpp:46
SEQAN3_CPO_IMPL
#define SEQAN3_CPO_IMPL(PRIO, TERM)
A macro that helps defining the overload set of a customisation point.
Definition: customisation_point.hpp:45
seqan3::assign_char_strictly_to
constexpr auto assign_char_strictly_to
Assign a character to an alphabet object, throw if the character is not valid.
Definition: concept.hpp:597
seqan3::to_char
constexpr auto to_char
Return the char representation of an alphabet object.
Definition: concept.hpp:320
seqan3::to_rank
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:142
totally_ordered
Requires std::equality_comparable and all remaing comparison operators (<, <=, >, >=).
same_as
The concept std::same_as<T, U> is satisfied if and only if T and U denote the same type.
seqan3::alphabet_rank_t
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:151
builtin_character
This concept encompasses exactly the types char, signed char, unsigned char, wchar_t,...
core_language.hpp
Provides concepts for core language types and relations that don't have concepts in C++20 (yet).
seqan3::invalid_char_assignment
An exception typically thrown by seqan3::alphabet::assign_char_strict.
Definition: exception.hpp:25
seqan3::alphabet_char_t
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:329
seqan3
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:36
convertible_to
The concept std::convertible_to<From, To> specifies that an expression of the type and value category...
SEQAN3_IS_CONSTEXPR
#define SEQAN3_IS_CONSTEXPR(...)
Returns true if the expression passed to this macro can be evaluated at compile time,...
Definition: function.hpp:25
copy_constructible
The concept std::copy_constructible is satisfied if T is an lvalue reference type,...
std::remove_reference_t
std::type_identity
The identity transformation (a transformation_trait that returns the input).
Definition: type_traits:31
alphabet
The generic alphabet concept that covers most data types used in ranges.
exception.hpp
Exceptions thrown by entities in the alphabet module.
type_inspection.hpp
Provides traits to inspect some information of a type, for example its name.
seqan3::assign_char_to
constexpr auto assign_char_to
Assign a character to an alphabet object.
Definition: concept.hpp:416
cereal.hpp
Adaptions of concepts from the Cereal library.
std::conditional_t
integral
The concept integral is satisfied if and only if T is an integral type.
semialphabet
The basis for seqan3::alphabet, but requires only rank interface (not char).
writable_alphabet
Refines seqan3::alphabet and adds assignability.
seqan3::alphabet_size
constexpr auto alphabet_size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:706
seqan3::custom
A namespace for third party and standard library specialisations of SeqAn customisation points.
Definition: char.hpp:42
customisation_point.hpp
Helper utilities for defining customisation point objects.
seqan3::char_is_valid_for
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:521