24namespace seqan3::detail
41template <std::ranges::view underlying_range_type>
42 requires std::ranges::forward_range<underlying_range_type> && std::ranges::common_range<underlying_range_type>
43class pairwise_combine_view :
public std::ranges::view_interface<pairwise_combine_view<underlying_range_type>>
47 template <
typename range_type>
55 using iterator = basic_iterator<underlying_range_type>;
57 using const_iterator =
58 transformation_trait_or_t<std::type_identity<basic_iterator<underlying_range_type const>>,
void>;
65 pairwise_combine_view() =
default;
66 pairwise_combine_view(pairwise_combine_view
const &) =
default;
67 pairwise_combine_view(pairwise_combine_view &&) =
default;
68 pairwise_combine_view & operator=(pairwise_combine_view
const &) =
default;
69 pairwise_combine_view & operator=(pairwise_combine_view &&) =
default;
70 ~pairwise_combine_view() =
default;
88 explicit constexpr pairwise_combine_view(underlying_range_type range) : u_range{
std::move(range)}
91 if (std::ranges::empty(u_range))
93 back_iterator = std::ranges::end(u_range);
97 if constexpr (std::ranges::bidirectional_range<underlying_range_type>)
99 back_iterator = std::ranges::prev(std::ranges::end(u_range));
104 if constexpr (std::ranges::sized_range<underlying_range_type>)
110 auto tmp_it = back_iterator;
113 back_iterator = tmp_it;
115 while (++tmp_it != std::ranges::end(u_range));
140 template <
typename other_range_t>
141 requires (!std::same_as<std::remove_cvref_t<other_range_t>, pairwise_combine_view>)
142 && std::ranges::viewable_range<other_range_t>
144 std::constructible_from<underlying_range_type,
149 explicit constexpr pairwise_combine_view(other_range_t && range) :
150 pairwise_combine_view{std::views::all(std::forward<other_range_t>(range))}
169 constexpr iterator
begin() noexcept
175 constexpr const_iterator
begin() const noexcept
194 constexpr iterator
end() noexcept
200 constexpr const_iterator
end() const noexcept
211#if SEQAN3_WORKAROUND_GCC_NON_TEMPLATE_REQUIRES
212 template <
typename = underlying_range_type>
214 constexpr auto size() const noexcept
215 requires
std::ranges::sized_range<underlying_range_type>
224 underlying_range_type u_range{};
226 std::ranges::iterator_t<underlying_range_type> back_iterator{};
234template <std::ranges::viewable_range other_range_t>
235pairwise_combine_view(other_range_t && range) -> pairwise_combine_view<std::views::all_t<other_range_t>>;
251template <std::ranges::view underlying_range_type>
252 requires std::ranges::forward_range<underlying_range_type> && std::ranges::common_range<underlying_range_type>
253template <
typename range_type>
254class pairwise_combine_view<underlying_range_type>::basic_iterator :
255 public maybe_iterator_category<std::ranges::iterator_t<range_type>>
259 template <
typename other_range_type>
261#if !SEQAN3_WORKAROUND_FURTHER_CONSTRAIN_FRIEND_DECLARATION
265 friend class basic_iterator;
268 using underlying_iterator_type = std::ranges::iterator_t<range_type>;
284 using reference = common_tuple<underlying_ref_t, underlying_ref_t>;
286 using pointer = void;
288 using iterator_concept = detail::iterator_concept_tag_t<underlying_iterator_type>;
294 basic_iterator() =
default;
295 basic_iterator(basic_iterator
const &) =
default;
296 basic_iterator(basic_iterator &&) =
default;
297 basic_iterator & operator=(basic_iterator
const &) =
default;
298 basic_iterator & operator=(basic_iterator &&) =
default;
299 ~basic_iterator() =
default;
313 constexpr basic_iterator(underlying_iterator_type iter,
314 underlying_iterator_type begin_it,
315 underlying_iterator_type end_it) noexcept :
317 second_it{std::ranges::next(iter, 1, end_it)},
330 template <
typename other_range_type>
331 requires std::convertible_to<other_range_type, range_type &>
333 constexpr basic_iterator(basic_iterator<other_range_type> other) noexcept :
334 basic_iterator{std::move(other.first_it), std::move(other.begin_it), std::move(other.end_it)}
342 constexpr reference operator*() const noexcept(noexcept(*
std::declval<underlying_iterator_type>()))
344 return reference{*first_it, *second_it};
350 constexpr reference operator[](
size_t const index)
const
351 noexcept(
noexcept(std::declval<basic_iterator &>().from_index(1)))
352 requires std::random_access_iterator<underlying_iterator_type>
354 return *(*
this + index);
362 constexpr basic_iterator &
363 operator++() noexcept(noexcept(++
std::declval<underlying_iterator_type &>()))
365 if (++second_it == end_it)
368 second_it = first_it;
375 constexpr basic_iterator
376 operator++(
int )
noexcept(
noexcept(std::declval<underlying_iterator_type &>()++))
378 basic_iterator tmp{*
this};
384 constexpr basic_iterator &
385 operator--() noexcept(noexcept(--
std::declval<underlying_iterator_type &>()))
386 requires
std::bidirectional_iterator<underlying_iterator_type>
388 if (--second_it == first_it)
398 constexpr basic_iterator
399 operator--(
int )
noexcept(
noexcept(std::declval<underlying_iterator_type &>()--))
400 requires std::bidirectional_iterator<underlying_iterator_type>
402 basic_iterator tmp{*
this};
409 constexpr basic_iterator &
410 operator+=(difference_type
const offset)
noexcept(
noexcept(std::declval<basic_iterator &>().from_index(1)))
411 requires std::random_access_iterator<underlying_iterator_type>
413 from_index(to_index() + offset);
419 constexpr basic_iterator operator+(difference_type
const offset)
const
420 noexcept(
noexcept(std::declval<basic_iterator &>() += 1))
421 requires std::random_access_iterator<underlying_iterator_type>
423 basic_iterator tmp{*
this};
424 return (tmp += offset);
429 constexpr friend basic_iterator
430 operator+(difference_type
const offset,
431 basic_iterator iter)
noexcept(
noexcept(std::declval<basic_iterator<range_type> &>().from_index(1)))
432 requires std::random_access_iterator<underlying_iterator_type>
434 iter.from_index(iter.to_index() +
offset);
440 constexpr basic_iterator &
441 operator-=(difference_type
const offset)
noexcept(
noexcept(std::declval<basic_iterator &>().from_index(1)))
442 requires std::random_access_iterator<underlying_iterator_type>
444 from_index(to_index() - offset);
450 constexpr basic_iterator operator-(difference_type
const offset)
const
451 noexcept(
noexcept(std::declval<basic_iterator &>() -= 1))
452 requires std::random_access_iterator<underlying_iterator_type>
454 basic_iterator tmp{*
this};
455 return (tmp -= offset);
460 template <
typename other_range_type>
461 requires std::random_access_iterator<underlying_iterator_type>
463 constexpr difference_type operator-(basic_iterator<other_range_type>
const & rhs)
const
464 noexcept(
noexcept(std::declval<basic_iterator &>().to_index()))
466 return static_cast<difference_type
>(to_index() - rhs.to_index());
480 template <
typename other_range_type>
481 requires std::equality_comparable_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>>
483 constexpr bool operator==(basic_iterator<other_range_type>
const & rhs)
const
484 noexcept(
noexcept(std::declval<underlying_iterator_type &>() == std::declval<underlying_iterator_type &>()))
486 return std::tie(first_it, second_it) ==
std::tie(rhs.first_it, rhs.second_it);
490 template <
typename other_range_type>
491 requires std::equality_comparable_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>>
493 constexpr bool operator!=(basic_iterator<other_range_type>
const & rhs)
const
494 noexcept(
noexcept(std::declval<underlying_iterator_type &>() != std::declval<underlying_iterator_type &>()))
496 return !(*
this == rhs);
500 template <
typename other_range_type>
501 requires std::totally_ordered_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>>
503 constexpr bool operator<(basic_iterator<other_range_type>
const & rhs)
const
504 noexcept(
noexcept(std::declval<underlying_iterator_type &>() < std::declval<underlying_iterator_type &>()))
506 return std::tie(first_it, second_it) <
std::tie(rhs.first_it, rhs.second_it);
510 template <
typename other_range_type>
511 requires std::totally_ordered_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>>
513 constexpr bool operator>(basic_iterator<other_range_type>
const & rhs)
const
514 noexcept(
noexcept(std::declval<underlying_iterator_type &>() > std::declval<underlying_iterator_type &>()))
517 return std::tie(first_it, second_it) >
std::tie(rhs.first_it, rhs.second_it);
521 template <
typename other_range_type>
522 requires std::totally_ordered_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>>
524 constexpr bool operator<=(basic_iterator<other_range_type>
const & rhs)
const
525 noexcept(
noexcept(std::declval<underlying_iterator_type &>() <= std::declval<underlying_iterator_type &>()))
527 return std::tie(first_it, second_it) <=
std::tie(rhs.first_it, rhs.second_it);
531 template <
typename other_range_type>
532 requires std::totally_ordered_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>>
534 constexpr bool operator>=(basic_iterator<other_range_type>
const & rhs)
const
535 noexcept(
noexcept(std::declval<underlying_iterator_type &>() >= std::declval<underlying_iterator_type &>()))
537 return std::tie(first_it, second_it) >=
std::tie(rhs.first_it, rhs.second_it);
554 constexpr size_t to_index() const
555 noexcept(noexcept(
std::declval<underlying_iterator_type &>() -
std::declval<underlying_iterator_type &>()))
556 requires
std::random_access_iterator<underlying_iterator_type>
558 size_t src_size = end_it - begin_it;
559 size_t index_i = first_it - begin_it;
560 size_t index_j = second_it - begin_it;
561 return (src_size * (src_size - 1) / 2) - (src_size - index_i) * ((src_size - index_i) - 1) / 2 + index_j
569 constexpr void from_index(
size_t const index)
noexcept(
noexcept(
570 std::declval<underlying_iterator_type &>()
571 - std::declval<underlying_iterator_type &>()) &&
noexcept(std::declval<underlying_iterator_type &>() + 1))
572 requires std::random_access_iterator<underlying_iterator_type>
574 size_t src_size = end_it - begin_it;
576 src_size - 2 -
std::floor(
std::sqrt(-8 * index + 4 * src_size * (src_size - 1) - 7) / 2.0 - 0.5);
578 index + index_i + 1 - src_size * (src_size - 1) / 2 + (src_size - index_i) * ((src_size - index_i) - 1) / 2;
579 first_it = begin_it + index_i;
580 second_it = begin_it + index_j;
584 underlying_iterator_type first_it{};
586 underlying_iterator_type second_it{};
588 underlying_iterator_type begin_it{};
590 underlying_iterator_type end_it{};
659inline constexpr auto pairwise_combine = detail::adaptor_for_view_without_args<detail::pairwise_combine_view>{};
Provides seqan3::detail::adaptor_for_view_without_args.
Provides seqan3::common_tuple.
@ offset
Sequence (seqan3::field::seq) relative start position (0-based), unsigned value.
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:146
constexpr auto pairwise_combine
A view adaptor that generates all pairwise combinations of the elements of the underlying range.
Definition: pairwise_combine.hpp:659
Specifies requirements of an input range type for which the const version of that type satisfies the ...
Provides various transformation traits for use on iterators.
The SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
SeqAn specific customisations in the standard namespace.
The <ranges> header from C++20's standard library.
Additional non-standard concepts for ranges.