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:
442  remove_cvref_t<alph_t>,
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<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  {
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  {
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<remove_cvref_t<alph_t>>,
624  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<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<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 
752 template <typename t>
754 SEQAN3_CONCEPT semialphabet =
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 
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:45
seqan3::assign_rank_to
constexpr auto assign_rank_to
Assign a rank to an alphabet object.
Definition: concept.hpp:239
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:47
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:598
basic.hpp
Provides various type traits on generic types.
seqan3::to_char
constexpr auto to_char
Return the char representation of an alphabet object.
Definition: concept.hpp:321
seqan3::to_rank
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:143
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:152
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:330
seqan3
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:28
SEQAN3_RETURN_TYPE_CONSTRAINT
#define SEQAN3_RETURN_TYPE_CONSTRAINT(expression, concept_name,...)
Same as writing {expression} -> concept_name<type1[, ...]> in a concept definition.
Definition: platform.hpp:57
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: basic.hpp:28
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:417
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:707
seqan3::custom
A namespace for third party and standard library specialisations of SeqAn customisation points.
Definition: char.hpp:43
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:522