BioC++ core-0.7.0
The Modern C++ libraries for Bioinformatics.
 
Loading...
Searching...
No Matches
tuple_base.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2022 deCODE Genetics
3// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
4// Copyright (c) 2016-2021, Knut Reinert & MPI für molekulare Genetik
5// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
6// shipped with this file and also available at: https://github.com/biocpp/biocpp-core/blob/main/LICENSE.md
7// -----------------------------------------------------------------------------------------------------
8
14#pragma once
15
16#include <cassert>
17#include <concepts>
18#include <utility>
19
20#include <bio/alphabet/base.hpp>
28
29namespace bio::alphabet::detail
30{
31
33template <typename tuple_derived_t, typename rhs_t, typename... component_types>
34concept tuple_concept_guard = !meta::one_of<rhs_t, tuple_derived_t, component_types...> &&
35 !meta::list_traits::contains<tuple_derived_t, recursive_required_types_t<rhs_t>>;
36
37} // namespace bio::alphabet::detail
38
39namespace bio::alphabet
40{
41
42// forwards
44template <typename t>
45decltype(auto) get();
46
47template <size_t i>
48decltype(auto) get();
50
89template <typename derived_type, typename... component_types>
90 requires((detail::writable_constexpr_semialphabet<component_types> && ...) &&
91 (std::regular<component_types> && ...))
93 public base<derived_type,
94 (1 * ... * size<component_types>),
95 void> // no char type, because this is only semi_alphabet
96{
97private:
99 using base_t = base<derived_type,
100 (1 * ... * size<component_types>),
101 void>; // no char type, because this is only semi_alphabet
102
104 using component_list = meta::type_list<component_types...>;
105
107 template <typename type>
108 static constexpr bool is_component = meta::list_traits::contains<type, component_list>;
109
111 template <typename type>
112 static constexpr bool is_unique_component = (meta::list_traits::count<type, component_list> == 1);
113
114 // forward declaration: see implementation below
115 template <typename alphabet_type, size_t index>
116 class component_proxy;
117
121 constexpr tuple_base() noexcept = default;
122 constexpr tuple_base(tuple_base const &) = default;
123 constexpr tuple_base(tuple_base &&) noexcept = default;
124 constexpr tuple_base & operator=(tuple_base const &) = default;
125 constexpr tuple_base & operator=(tuple_base &&) noexcept = default;
126 ~tuple_base() = default;
127
128 using base_t::base_t;
130
133 friend derived_type;
134
135 // Import from base:
136 using typename base_t::rank_type;
137
138public:
139 // Import from base:
140 using base_t::alphabet_size;
141 using base_t::assign_rank;
142 using base_t::to_rank;
143
149 using biocpp_recursive_required_types = meta::list_traits::concat<
154 static constexpr bool biocpp_alphabet_tuple_like = true;
155
163 constexpr tuple_base(component_types... components) noexcept
164 {
165 assign_rank(rank_sum_helper(components..., std::make_index_sequence<sizeof...(component_types)>{}));
166 }
167
179 template <typename component_type>
180 requires((!std::is_base_of_v<tuple_base, component_type>) && is_unique_component<component_type>)
181 constexpr explicit tuple_base(component_type const alph) noexcept : tuple_base{}
182 {
183 get<component_type>(*this) = alph;
184 }
185
202 template <typename indirect_component_type>
203 requires(detail::tuple_concept_guard<derived_type, indirect_component_type, component_types...> &&
204 (std::is_convertible_v<indirect_component_type, component_types> || ...))
205 constexpr explicit tuple_base(indirect_component_type const alph) noexcept : tuple_base{}
206 {
207 using component_predicate = detail::implicitly_convertible_from<indirect_component_type>;
208 constexpr auto component_position =
209 meta::list_traits::find_if<component_predicate::template invoke, component_list>;
211 component_type tmp(alph); // delegate construction
212 get<component_type>(*this) = tmp;
213 }
214
216 template <typename indirect_component_type>
217 requires(detail::tuple_concept_guard<derived_type, indirect_component_type, component_types...> &&
218 (!(std::is_convertible_v<indirect_component_type, component_types> || ...)) &&
219 (std::is_constructible_v<component_types, indirect_component_type> || ...))
220 constexpr explicit tuple_base(indirect_component_type const alph) noexcept : tuple_base{}
221 {
222 using component_predicate = detail::constructible_from<indirect_component_type>;
223 constexpr auto component_position =
224 meta::list_traits::find_if<component_predicate::template invoke, component_list>;
225 using component_type = meta::list_traits::at<component_position, component_list>;
226 component_type tmp(alph); // delegate construction
227 get<component_type>(*this) = tmp;
228 }
230
242 template <typename component_type>
243 requires((!std::derived_from<component_type, tuple_base>) && is_unique_component<component_type>)
244 constexpr derived_type & operator=(component_type const alph) noexcept
245 {
246 get<component_type>(*this) = alph;
247 return static_cast<derived_type &>(*this);
248 }
249
262 template <typename indirect_component_type>
263 requires((!std::derived_from<indirect_component_type, tuple_base>) &&
264 (!is_unique_component<indirect_component_type>) &&
265 (std::assignable_from<component_types, indirect_component_type> || ...))
266 constexpr derived_type & operator=(indirect_component_type const alph) noexcept
267 {
268 using component_predicate = detail::assignable_from<indirect_component_type>;
269 constexpr auto component_position =
270 meta::list_traits::find_if<component_predicate::template invoke, component_list>;
272 get<component_type>(*this) = alph; // delegate assignment
273 return static_cast<derived_type &>(*this);
274 }
276 // If not assignable but implicit convertible, convert first and assign afterwards
277 template <typename indirect_component_type>
278 requires((!std::derived_from<indirect_component_type, tuple_base>) &&
279 (!is_unique_component<indirect_component_type>) &&
280 (!(std::assignable_from<component_types, indirect_component_type> || ...)) &&
281 (std::convertible_to<indirect_component_type, component_types> || ...))
282 constexpr derived_type & operator=(indirect_component_type const alph) noexcept
283 {
284 using component_predicate = detail::implicitly_convertible_from<indirect_component_type>;
285 constexpr auto component_position =
286 meta::list_traits::find_if<component_predicate::template invoke, component_list>;
288 component_type tmp(alph);
289 get<component_type>(*this) = tmp;
290 return static_cast<derived_type &>(*this);
291 }
292
293 template <typename indirect_component_type>
294 requires((!std::derived_from<indirect_component_type, tuple_base>) &&
295 (!is_unique_component<indirect_component_type>) &&
296 (!(std::assignable_from<component_types, indirect_component_type> || ...)) &&
297 (!(std::convertible_to<indirect_component_type, component_types> || ...)) &&
298 (std::constructible_from<component_types, indirect_component_type> || ...))
299 constexpr derived_type & operator=(indirect_component_type const alph) noexcept
300 {
301 using component_predicate = detail::constructible_from<indirect_component_type>;
302 constexpr auto component_position =
303 meta::list_traits::find_if<component_predicate::template invoke, component_list>;
305 component_type tmp(alph); // delegate construction
306 get<component_type>(*this) = tmp;
307 return static_cast<derived_type &>(*this);
308 }
311
321 template <size_t index>
322 friend constexpr auto get(tuple_base & l) noexcept
323 {
324 static_assert(index < sizeof...(component_types), "Index out of range.");
325
327 t val{};
328
329 bio::alphabet::assign_rank_to(l.to_component_rank<index>(), val);
330
331 return component_proxy<t, index>{l};
332 }
333
339 template <typename type>
340 friend constexpr auto get(tuple_base & l) noexcept
341 requires is_unique_component<type>
342 {
343 return get<meta::list_traits::find<type, component_list>>(l);
344 }
345
351 template <size_t index>
352 friend constexpr auto get(tuple_base const & l) noexcept
353 {
354 static_assert(index < sizeof...(component_types), "Index out of range.");
355
357
358 return bio::alphabet::assign_rank_to(l.to_component_rank<index>(), t{});
359 }
360
366 template <typename type>
367 friend constexpr type get(tuple_base const & l) noexcept
368 requires is_unique_component<type>
369 {
370 return get<meta::list_traits::find<type, component_list>>(l);
371 }
372
376 template <typename type>
377 constexpr operator type() const noexcept
378 requires is_unique_component<type>
379 {
380 return get<type>(*this);
381 }
383
400 template <std::same_as<derived_type> derived_type_t, typename indirect_component_type>
401 requires(detail::tuple_concept_guard<derived_type, indirect_component_type, component_types...> &&
403 friend constexpr bool operator==(derived_type_t const lhs, indirect_component_type const rhs) noexcept
404 {
405 using component_predicate = detail::weakly_equality_comparable_with_<indirect_component_type>;
406 constexpr auto component_position =
407 meta::list_traits::find_if<component_predicate::template invoke, component_list>;
409 return get<component_type>(lhs) == rhs;
410 }
411
413 template <std::same_as<derived_type> derived_type_t, typename indirect_component_type>
414 requires(detail::tuple_concept_guard<derived_type, indirect_component_type, component_types...> &&
416 friend constexpr auto operator<=>(derived_type_t const lhs, indirect_component_type const rhs) noexcept
417 {
418 using component_predicate = detail::weakly_ordered_with_<indirect_component_type>;
419 constexpr auto component_position =
420 meta::list_traits::find_if<component_predicate::template invoke, component_list>;
422 return get<component_type>(lhs) <=> rhs;
423 }
425
426private:
428 template <size_t index>
429 constexpr rank_type to_component_rank() const noexcept
430 {
431 if constexpr (alphabet_size < 1024) // computation is cached for small alphabets
432 {
433 return rank_to_component_rank[index][to_rank()];
434 }
435 else
436 {
437 return (to_rank() / cummulative_alph_sizes[index]) %
438 bio::alphabet::size<meta::detail::pack_traits::at<index, component_types...>>;
439 }
440 }
441
443 template <size_t index>
444 constexpr void assign_component_rank(ptrdiff_t const r) noexcept
445 {
446 assign_rank(static_cast<ptrdiff_t>(to_rank()) + ((r - static_cast<ptrdiff_t>(to_component_rank<index>())) *
447 static_cast<ptrdiff_t>(cummulative_alph_sizes[index])));
448 }
449
451 static constexpr std::array<rank_type, component_list::size()> cummulative_alph_sizes = []() constexpr
452 {
453 // create array (1, |sigma1|, |sigma1|*|sigma2|, ... , |sigma1|*...*|sigmaN|)
454 std::array<rank_type, component_list::size() + 1> ret{};
455 ret[0] = 1;
456 size_t count = 1;
457 using reverse_list_t = decltype(meta::list_traits::detail::reverse(component_list{}));
458 bio::meta::detail::for_each<reverse_list_t>(
459 [&](auto alphabet_type_identity) constexpr
460 {
461 using alphabet_t = typename decltype(alphabet_type_identity)::type;
462 ret[count] = static_cast<rank_type>(bio::alphabet::size<alphabet_t> * ret[count - 1]);
463 ++count;
464 });
465
466 // reverse and strip one: (|sigma1|*...*|sigmaN-1|, ... |sigma1|*|sigma2|, |sigma1|, 1)
467 // reverse order guarantees that the first alphabet is the most significant rank contributer
468 // resulting in element-wise alphabetical ordering on comparison
469 std::array<rank_type, component_list::size()> ret2{};
470 for (size_t i = 0; i < component_list::size(); ++i)
471 ret2[i] = ret[component_list::size() - i - 1];
472
473 return ret2;
474 }();
475
477 template <std::size_t... idx>
478 static constexpr rank_type rank_sum_helper(component_types... components,
479 std::index_sequence<idx...> const &) noexcept
480 {
481 return ((bio::alphabet::to_rank(components) * cummulative_alph_sizes[idx]) + ...);
482 }
483
485 static constexpr std::array < std::array<rank_type,
486 alphabet_size<1024 ? alphabet_size : 0>, // not for big alphs
487 meta::list_traits::size<component_list>>
488 rank_to_component_rank = []() constexpr
489 {
490 std::array < std::array<rank_type,
491 alphabet_size<1024 ? alphabet_size : 0>, // not for big alphs
492 meta::list_traits::size<component_list>>
493 ret{};
494
495 if constexpr (alphabet_size < 1024)
496 {
497 std::array<size_t, alphabet_size> alph_sizes{bio::alphabet::size<component_types>...};
498
499 for (size_t i = 0; i < meta::list_traits::size<component_list>; ++i)
500 for (size_t j = 0; j < static_cast<size_t>(alphabet_size); ++j)
501 ret[i][j] = (j / cummulative_alph_sizes[i]) % alph_sizes[i];
502 }
503
504 return ret;
505 }();
506};
507
513template <typename derived_type, typename... component_types>
514 requires((detail::writable_constexpr_semialphabet<component_types> && ...) &&
515 (std::regular<component_types> && ...))
516template <typename alphabet_type, size_t index>
517class tuple_base<derived_type, component_types...>::component_proxy :
518 public proxy_base<component_proxy<alphabet_type, index>, alphabet_type>
519{
520private:
522 using base_t = proxy_base<component_proxy<alphabet_type, index>, alphabet_type>;
524 friend base_t;
525
527 tuple_base * parent;
528
529public:
530 //Import from base type:
531 using base_t::operator=;
532
537 component_proxy() = delete;
538 constexpr component_proxy(component_proxy const &) noexcept = default;
539 constexpr component_proxy(component_proxy &&) noexcept = default;
540 ~component_proxy() noexcept = default;
541
543 constexpr component_proxy(tuple_base & p) : parent{&p} {}
544
546 constexpr component_proxy & operator=(component_proxy const & rhs) // NOLINT(bugprone-unhandled-self-assignment)
547 {
548 return assign_rank(rhs.to_rank());
549 }
550
552 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
553 constexpr component_proxy const & operator=(component_proxy const & rhs) const
554 {
555 return assign_rank(rhs.to_rank());
556 }
558
560 constexpr alphabet::rank_t<alphabet_type> to_rank() const noexcept { return parent->to_component_rank<index>(); }
561
563 constexpr component_proxy & assign_rank(alphabet::rank_t<alphabet_type> const r) noexcept
564 {
565 parent->assign_component_rank<index>(r);
566 return *this;
567 }
568
570 constexpr component_proxy const & assign_rank(alphabet::rank_t<alphabet_type> const r) const noexcept
571 {
572 parent->assign_component_rank<index>(r);
573 return *this;
574 }
575
585 friend constexpr bool operator==(derived_type const lhs, component_proxy const rhs) noexcept
586 {
587 return get<index>(lhs) == static_cast<alphabet_type>(rhs);
588 }
589
591 friend constexpr auto operator<=>(derived_type const lhs, component_proxy const rhs) noexcept
592 {
593 return get<index>(lhs) <=> static_cast<alphabet_type>(rhs);
594 }
596};
597
598} // namespace bio::alphabet
599
600namespace std
601{
602
609template <std::size_t i, bio::alphabet::detail::alphabet_tuple_like tuple_t>
610struct tuple_element<i, tuple_t>
611{
614};
615
622template <bio::alphabet::detail::alphabet_tuple_like tuple_t>
623struct tuple_size<tuple_t> :
624 public std::integral_constant<size_t, bio::meta::list_traits::size<typename tuple_t::biocpp_required_types>>
625{};
626
627} // namespace std
Provides implementation detail for bio::alphabet::variant and bio::alphabet::tuple_base.
Core alphabet concept and free function/type trait wrappers.
Provides bio::alphabet::base.
A CRTP-base that makes defining a custom alphabet easier.
Definition: base.hpp:55
The CRTP base for a combined alphabet that contains multiple values of different alphabets at the sam...
Definition: tuple_base.hpp:96
constexpr tuple_base(indirect_component_type const alph) noexcept
Construction via a value of a subtype that is assignable to one of the components.
Definition: tuple_base.hpp:205
friend constexpr auto get(tuple_base &l) noexcept
Tuple-like access to the contained components.
Definition: tuple_base.hpp:322
constexpr tuple_base(component_type const alph) noexcept
Construction via a value of one of the components.
Definition: tuple_base.hpp:181
friend constexpr auto get(tuple_base const &l) noexcept
Tuple-like access to the contained components.
Definition: tuple_base.hpp:352
constexpr tuple_base(component_types... components) noexcept
Construction from initialiser-list.
Definition: tuple_base.hpp:163
friend constexpr type get(tuple_base const &l) noexcept
Tuple-like access to the contained components.
Definition: tuple_base.hpp:367
friend constexpr auto get(tuple_base &l) noexcept
Tuple-like access to the contained components.
Definition: tuple_base.hpp:340
constexpr derived_type & operator=(component_type const alph) noexcept
Assignment via a value of one of the components.
Definition: tuple_base.hpp:244
Requires the two operands to be comparable with == and != in both directions.
Definition: core_language.hpp:33
Requires the two operands to be comparable with <, <=, > and >= in both directions.
Definition: core_language.hpp:46
Provides algorithms for meta programming, parameter packs and bio::meta::type_list.
constexpr auto size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:517
constexpr auto to_rank
Return the rank representation of a (semi-)alphabet object.
Definition: concept.hpp:70
constexpr auto assign_rank_to
Assign a rank to an alphabet object.
Definition: concept.hpp:138
decltype(detail::concat(lists_t{}...)) concat
Join two meta::type_list s into one.
Definition: traits.hpp:372
typename decltype(detail::at< idx >(list_t{}))::type at
Return the type at given index from the type list.
Definition: traits.hpp:309
typename transformation_trait_or< type_t, default_t >::type transformation_trait_or_t
Helper type of bio::meta::transformation_trait_or (transformation_trait shortcut).
Definition: transformation_trait_or.hpp:53
The alphabet module's namespace.
Definition: aa10li.hpp:23
Provides bio::alphabet::proxy_base.
Type that contains multiple types.
Definition: type_list.hpp:30
bio::meta::list_traits::at< i, typename tuple_t::biocpp_required_types > type
Element type.
Definition: tuple_base.hpp:613
Provides various traits to inspect templates.
Provides traits for meta::type_list.
Provides bio::meta::type_list.