28 namespace seqan3::detail
32 template <
typename other_t,
typename... alternative_types>
33 inline constexpr
bool variant_general_guard =
34 (!std::same_as<other_t, alphabet_variant<alternative_types...>>)&&(
36 other_t>)&&(!(std::same_as<other_t, alternative_types> || ...))
37 && (!
list_traits::contains<alphabet_variant<alternative_types...>, recursive_required_types_t<other_t>>);
40 template <
typename lhs_t,
typename rhs_t,
bool lhs_rhs_switched,
typename... alternative_types>
41 inline constexpr
bool variant_comparison_guard =
43 lazy<weakly_equality_comparable_with_trait, rhs_t, alternative_types>,
44 (std::same_as<lhs_t, alphabet_variant<alternative_types...>>)&&(
45 variant_general_guard<rhs_t, alternative_types...>)&&!(lhs_rhs_switched
46 && is_type_specialisation_of_v<rhs_t,
113 template <
typename... alternative_types>
114 requires (detail::writable_constexpr_alphabet<alternative_types> && ...) && (std::regular<alternative_types> && ...)
115 && (
sizeof...(alternative_types) >= 2)
116 class alphabet_variant :
117 public alphabet_base<alphabet_variant<alternative_types...>,
118 (static_cast<size_t>(alphabet_size<alternative_types>) + ...),
123 using base_t = alphabet_base<alphabet_variant<alternative_types...>,
124 (
static_cast<size_t>(alphabet_size<alternative_types>) + ...),
127 static_assert((
std::is_same_v<alphabet_char_t<alternative_types>,
char> && ...),
128 "The alphabet_variant is currently only tested for alphabets with char_type char. "
129 "Contact us on GitHub if you have a different use case: https://github.com/seqan/seqan3 .");
137 static_assert(((seqan3::list_traits::count<alternative_types, alternatives> == 1) && ... &&
true),
138 "All types in a alphabet_variant must be distinct.");
140 using typename base_t::char_type;
141 using typename base_t::rank_type;
144 using base_t::alphabet_size;
145 using base_t::assign_rank;
154 using seqan3_required_types = type_list<alternative_types...>;
160 using seqan3_recursive_required_types = list_traits::concat<
161 seqan3_required_types,
162 detail::transformation_trait_or_t<detail::recursive_required_types<alternative_types>, type_list<>>...>;
171 template <
typename alternative_t>
172 static constexpr
bool is_alternative() noexcept
180 constexpr alphabet_variant() noexcept = default;
181 constexpr alphabet_variant(alphabet_variant const &) noexcept = default;
182 constexpr alphabet_variant(alphabet_variant &&) noexcept = default;
183 constexpr alphabet_variant & operator=(alphabet_variant const &) noexcept = default;
184 constexpr alphabet_variant & operator=(alphabet_variant &&) noexcept = default;
185 ~alphabet_variant() noexcept = default;
195 template <typename alternative_t>
196 requires (!
std::same_as<alternative_t, alphabet_variant>)
197 && (!
std::is_base_of_v<alphabet_variant, alternative_t>)
200 detail::transformation_trait_or_t<detail::recursive_required_types<alternative_t>, type_list<>>>)
201 && (is_alternative<alternative_t>())
202 constexpr alphabet_variant(alternative_t const alternative) noexcept
204 assign_rank(rank_by_type_(alternative));
225 template <
typename indirect_alternative_t>
227 (detail::instantiate_if_v<detail::lazy<std::is_convertible, indirect_alternative_t, alternative_types>,
228 detail::variant_general_guard<indirect_alternative_t, alternative_types...>>
230 constexpr alphabet_variant(indirect_alternative_t const rhs) noexcept
232 using alternative_predicate = detail::implicitly_convertible_from<indirect_alternative_t>;
233 constexpr
auto alternative_position =
234 seqan3::list_traits::find_if<alternative_predicate::template invoke, alternatives>;
235 using alternative_t = seqan3::list_traits::at<alternative_position, alternatives>;
236 assign_rank(rank_by_type_(alternative_t(rhs)));
255 template <
typename indirect_alternative_t>
257 (!(detail::instantiate_if_v<detail::lazy<std::is_convertible, indirect_alternative_t, alternative_types>,
258 detail::variant_general_guard<indirect_alternative_t, alternative_types...>>
260 && (detail::instantiate_if_v<detail::lazy<std::is_constructible, alternative_types, indirect_alternative_t>,
261 detail::variant_general_guard<indirect_alternative_t, alternative_types...>>
263 constexpr explicit alphabet_variant(indirect_alternative_t const rhs) noexcept
265 using alternative_predicate = detail::constructible_from<indirect_alternative_t>;
266 constexpr
auto alternative_position =
267 seqan3::list_traits::find_if<alternative_predicate::template invoke, alternatives>;
268 using alternative_t = seqan3::list_traits::at<alternative_position, alternatives>;
269 assign_rank(rank_by_type_(alternative_t(rhs)));
283 template <
typename indirect_alternative_t>
284 requires (detail::variant_general_guard<indirect_alternative_t, alternative_types...>
286 constexpr alphabet_variant & operator=(indirect_alternative_t const & rhs) noexcept
288 using alternative_predicate = detail::assignable_from<indirect_alternative_t>;
289 constexpr
auto alternative_position =
290 seqan3::list_traits::find_if<alternative_predicate::template invoke, alternatives>;
291 using alternative_t = seqan3::list_traits::at<alternative_position, alternatives>;
292 alternative_t alternative{};
294 assign_rank(rank_by_type_(alternative));
308 template <
size_t index>
311 static_assert(index < alphabet_size,
"The alphabet_variant contains less alternatives than you are checking.");
312 return (
to_rank() >= partial_sum_sizes[index]) && (
to_rank() < partial_sum_sizes[index + 1]);
321 template <
size_t index>
322 constexpr
auto convert_to()
const
324 return convert_impl<index, true>();
332 template <
size_t index>
333 constexpr
auto convert_unsafely_to() const noexcept
335 return convert_impl<index, false>();
347 template <
typename alternative_t>
349 requires (is_alternative<alternative_t>())
351 constexpr
size_t index = seqan3::list_traits::find<alternative_t, alternatives>;
352 return holds_alternative<index>();
361 template <
typename alternative_t>
362 constexpr alternative_t convert_to() const
363 requires (is_alternative<alternative_t>())
365 constexpr
size_t index = seqan3::list_traits::find<alternative_t, alternatives>;
366 return convert_impl<index, true>();
374 template <
typename alternative_t>
375 constexpr alternative_t convert_unsafely_to() const noexcept
376 requires (is_alternative<alternative_t>())
378 constexpr
size_t index = seqan3::list_traits::find<alternative_t, alternatives>;
379 return convert_impl<index, false>();
405 template <
typename alphabet_variant_t,
typename indirect_alternative_type>
406 friend constexpr
auto
407 operator==(alphabet_variant_t
const lhs, indirect_alternative_type
const rhs) noexcept ->
std::enable_if_t<
408 detail::variant_comparison_guard<alphabet_variant_t, indirect_alternative_type,
false, alternative_types...>,
411 using alternative_predicate = detail::weakly_equality_comparable_with_<indirect_alternative_type>;
412 constexpr
auto alternative_position =
413 seqan3::list_traits::find_if<alternative_predicate::template invoke, alternatives>;
414 using alternative_t = seqan3::list_traits::at<alternative_position, alternatives>;
415 return lhs.template holds_alternative<alternative_t>()
416 && (lhs.template convert_unsafely_to<alternative_t>() == rhs);
420 template <
typename alphabet_variant_t,
typename indirect_alternative_type>
421 friend constexpr
auto
423 detail::variant_comparison_guard<alphabet_variant_t, indirect_alternative_type,
false, alternative_types...>,
426 return !(lhs == rhs);
430 template <
typename alphabet_variant_t,
typename indirect_alternative_type,
typename =
void>
431 friend constexpr
auto operator==(indirect_alternative_type
const lhs, alphabet_variant_t
const rhs) noexcept
433 detail::variant_comparison_guard<alphabet_variant_t, indirect_alternative_type,
true, alternative_types...>,
440 template <
typename alphabet_variant_t,
typename indirect_alternative_type,
typename =
void>
441 friend constexpr
auto operator!=(indirect_alternative_type
const lhs, alphabet_variant_t
const rhs) noexcept
443 detail::variant_comparison_guard<alphabet_variant_t, indirect_alternative_type,
true, alternative_types...>,
454 static constexpr
bool char_is_valid(char_type
const chr) noexcept
457 return first_valid_char_table[
static_cast<index_t
>(chr)] <
sizeof...(alternative_types);
467 template <
size_t index,
bool throws>
468 constexpr
auto convert_impl() const noexcept(!throws) ->
seqan3::list_traits::at<index, alternatives>
470 static_assert(index < alphabet_size,
"The alphabet_variant contains less alternatives than you are checking.");
471 using alternative_t = seqan3::list_traits::at<index, alternatives>;
473 if constexpr (
throws)
475 if (!holds_alternative<index>())
491 static constexpr
std::array<rank_type,
sizeof...(alternative_types) + 1> partial_sum_sizes = []() constexpr
493 constexpr
size_t N =
sizeof...(alternative_types) + 1;
496 for (
size_t i = 1u; i < N; ++i)
497 partial_sum[i] += partial_sum[i - 1];
509 auto assign_rank_to_char = [](
auto alternative,
size_t rank) constexpr
514 auto assign_value_to_char = [assign_rank_to_char](
auto alternative,
515 auto & value_to_char,
516 auto & value) constexpr
518 using alternative_t =
std::decay_t<decltype(alternative)>;
519 for (
size_t i = 0u; i < seqan3::alphabet_size<alternative_t>; ++i, ++value)
520 value_to_char[value] = assign_rank_to_char(alternative, i);
530 ((assign_value_to_char(alternative_types{}, value_to_char, value)), ...);
532 return value_to_char;
540 template <
size_t index,
typename alternative_t>
541 requires (is_alternative<alternative_t>())
542 static constexpr rank_type rank_by_index_(alternative_t const & alternative) noexcept
544 return partial_sum_sizes[index] +
static_cast<rank_type
>(
seqan3::to_rank(alternative));
551 template <
typename alternative_t>
552 requires (is_alternative<alternative_t>())
553 static constexpr rank_type rank_by_type_(alternative_t const & alternative) noexcept
555 constexpr
size_t index = seqan3::list_traits::find<alternative_t, alternatives>;
556 return rank_by_index_<index>(alternative);
562 static constexpr
auto first_valid_char_table{
563 []() constexpr {constexpr
size_t alternative_size =
sizeof...(alternative_types);
564 constexpr
size_t table_size = detail::size_in_values_v<char_type>;
565 using first_alphabet_t = detail::min_viable_uint_t<alternative_size>;
569 for (
size_t i = 0u; i < table_size; ++i)
571 char_type chr =
static_cast<char_type
>(i);
575 #if defined(__cpp_lib_constexpr_algorithms) && __cpp_lib_constexpr_algorithms >= 201806L
577 auto found_it =
std::find(valid_chars.begin(), valid_chars.end(),
true);
578 lookup_table[i] = found_it - valid_chars.begin();
580 size_t found_index = 0u;
581 for (; found_index < valid_chars.size() && !valid_chars[found_index]; ++found_index)
583 lookup_table[i] = found_index;
594 constexpr
size_t alternative_size =
sizeof...(alternative_types);
595 constexpr
size_t table_size = detail::size_in_values_v<char_type>;
599 for (
size_t i = 0u; i < table_size; ++i)
601 char_type chr =
static_cast<char_type
>(i);
606 char_to_rank[i] = first_valid_char_table[i] < alternative_size ? ranks[first_valid_char_table[i]] : 0;
619 static constexpr char_type rank_to_char(rank_type
const rank)
621 return rank_to_char_table[rank];
630 static constexpr rank_type char_to_rank(char_type
const chr)
633 return char_to_rank_table[
static_cast<index_t
>(chr)];
Provides seqan3::alphabet_base.
constexpr auto assign_char_to
Assign a character to an alphabet object.
Definition: alphabet/concept.hpp:524
constexpr auto to_char
Return the char representation of an alphabet object.
Definition: alphabet/concept.hpp:386
constexpr auto assign_rank_to
Assign a rank to an alphabet object.
Definition: alphabet/concept.hpp:293
requires requires
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank....
Definition: alphabet/concept.hpp:164
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: alphabet/concept.hpp:155
requires constexpr seqan3::detail::template_specialisation_of< list_t, seqan3::type_list > bool contains
Whether a type occurs in a type list or not.
Definition: type_list/traits.hpp:252
constexpr bool contains
Whether a type occurs in a pack or not.
Definition: type_pack/traits.hpp:223
T holds_alternative(T... args)
Resolves to std::is_assignable_v<t>.
Provides lazy template instantiation traits.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
SeqAn specific customisations in the standard namespace.
Type that contains multiple types.
Definition: type_list.hpp:29
Provides traits for seqan3::type_list.