23 namespace seqan3::detail
40 template <std::ranges::view underlying_range_type>
42 requires std::ranges::forward_range<underlying_range_type> && std::ranges::common_range<underlying_range_type>
44 class pairwise_combine_view :
public std::ranges::view_interface<pairwise_combine_view<underlying_range_type>>
49 template <
typename range_type>
56 using iterator = basic_iterator<underlying_range_type>;
59 using const_iterator = transformation_trait_or_t<std::type_identity<basic_iterator<underlying_range_type const>>,
67 pairwise_combine_view() =
default;
68 pairwise_combine_view(pairwise_combine_view
const &) =
default;
69 pairwise_combine_view(pairwise_combine_view &&) =
default;
70 pairwise_combine_view & operator=(pairwise_combine_view
const &) =
default;
71 pairwise_combine_view & operator=(pairwise_combine_view &&) =
default;
72 ~pairwise_combine_view() =
default;
90 explicit constexpr pairwise_combine_view(underlying_range_type range) : u_range{
std::move(range)}
93 if (std::ranges::empty(u_range))
95 back_iterator = std::ranges::end(u_range);
99 if constexpr (std::ranges::bidirectional_range<underlying_range_type>)
101 back_iterator = std::ranges::prev(std::ranges::end(u_range));
106 if constexpr (std::ranges::sized_range<underlying_range_type>)
112 auto tmp_it = back_iterator;
115 back_iterator = tmp_it;
116 }
while (++tmp_it != std::ranges::end(u_range));
141 template <
typename other_range_t>
144 std::ranges::viewable_range<other_range_t> &&
145 std::constructible_from<underlying_range_type,
146 std::ranges::ref_view<std::remove_reference_t<other_range_t>>>
151 explicit constexpr pairwise_combine_view(other_range_t && range) :
152 pairwise_combine_view{std::views::all(std::forward<other_range_t>(range))}
171 constexpr iterator
begin() noexcept
177 constexpr const_iterator
begin() const noexcept
198 constexpr iterator
end() noexcept
204 constexpr const_iterator
end() const noexcept
216 constexpr
auto size() const noexcept
219 requires
std::ranges::sized_range<underlying_range_type>
229 underlying_range_type u_range{};
231 std::ranges::iterator_t<underlying_range_type> back_iterator{};
238 template <std::ranges::viewable_range other_range_t>
240 pairwise_combine_view(other_range_t && range) ->
241 pairwise_combine_view<std::views::all_t<other_range_t>>;
257 template <std::ranges::view underlying_range_type>
259 requires std::ranges::forward_range<underlying_range_type> && std::ranges::common_range<underlying_range_type>
261 template <
typename range_type>
262 class pairwise_combine_view<underlying_range_type>::basic_iterator
267 template <
typename other_range_type>
269 friend class basic_iterator;
272 using underlying_iterator_type = std::ranges::iterator_t<range_type>;
288 using reference = common_tuple<underlying_ref_t, underlying_ref_t>;
290 using pointer = void;
292 using iterator_category = detail::iterator_category_tag_t<underlying_iterator_type>;
294 using iterator_concept = detail::iterator_concept_tag_t<underlying_iterator_type>;
300 basic_iterator() =
default;
301 basic_iterator(basic_iterator
const &) =
default;
302 basic_iterator(basic_iterator &&) =
default;
303 basic_iterator & operator=(basic_iterator
const &) =
default;
304 basic_iterator & operator=(basic_iterator &&) =
default;
305 ~basic_iterator() =
default;
319 constexpr basic_iterator(underlying_iterator_type iter,
320 underlying_iterator_type begin_it,
321 underlying_iterator_type end_it) noexcept :
323 second_it{std::ranges::next(iter, 1, end_it)},
336 template <
typename other_range_type>
338 requires std::convertible_to<other_range_type, range_type &> &&
341 constexpr basic_iterator(basic_iterator<other_range_type> other) noexcept :
349 constexpr reference operator*() const
351 noexcept(noexcept(*
std::declval<underlying_iterator_type>()))
353 return reference{*first_it, *second_it};
359 constexpr reference operator[](
size_t const index)
const
360 noexcept(noexcept(std::declval<basic_iterator &>().from_index(1)))
362 requires
std::random_access_iterator<underlying_iterator_type>
365 return *(*
this + index);
372 constexpr basic_iterator & operator++()
374 noexcept(noexcept(++
std::declval<underlying_iterator_type &>()))
376 if (++second_it == end_it)
379 second_it = first_it;
386 constexpr basic_iterator operator++(
int )
387 noexcept(noexcept(std::declval<underlying_iterator_type &>()++))
389 basic_iterator tmp{*
this};
395 constexpr basic_iterator & operator--()
396 noexcept(noexcept(--
std::declval<underlying_iterator_type &>()))
398 requires
std::bidirectional_iterator<underlying_iterator_type>
401 if (--second_it == first_it)
411 constexpr basic_iterator operator--(
int )
412 noexcept(noexcept(std::declval<underlying_iterator_type &>()--))
414 requires
std::bidirectional_iterator<underlying_iterator_type>
417 basic_iterator tmp{*
this};
424 constexpr basic_iterator & operator+=(difference_type
const offset)
425 noexcept(noexcept(std::declval<basic_iterator &>().from_index(1)))
427 requires
std::random_access_iterator<underlying_iterator_type>
430 from_index(to_index() + offset);
436 constexpr basic_iterator operator+(difference_type
const offset)
const
437 noexcept(noexcept(std::declval<basic_iterator &>() += 1))
439 requires
std::random_access_iterator<underlying_iterator_type>
442 basic_iterator tmp{*
this};
443 return (tmp += offset);
448 constexpr
friend basic_iterator operator+(difference_type
const offset, basic_iterator iter)
449 noexcept(noexcept(
std::declval<basic_iterator<range_type> &>().from_index(1)))
451 requires
std::random_access_iterator<underlying_iterator_type>
454 iter.from_index(iter.to_index() + offset);
460 constexpr basic_iterator & operator-=(difference_type
const offset)
461 noexcept(noexcept(std::declval<basic_iterator &>().from_index(1)))
463 requires
std::random_access_iterator<underlying_iterator_type>
466 from_index(to_index() - offset);
472 constexpr basic_iterator operator-(difference_type
const offset)
const
473 noexcept(noexcept(std::declval<basic_iterator &>() -= 1))
475 requires
std::random_access_iterator<underlying_iterator_type>
478 basic_iterator tmp{*
this};
479 return (tmp -= offset);
484 template <
typename other_range_type>
486 requires std::random_access_iterator<underlying_iterator_type> &&
489 constexpr difference_type operator-(basic_iterator<other_range_type>
const & rhs)
const
490 noexcept(noexcept(std::declval<basic_iterator &>().to_index()))
492 return static_cast<difference_type
>(to_index() - rhs.to_index());
506 template <
typename other_range_type>
508 requires std::equality_comparable_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>> &&
511 constexpr
bool operator==(basic_iterator<other_range_type>
const & rhs)
const
512 noexcept(noexcept(std::declval<underlying_iterator_type &>() == std::declval<underlying_iterator_type &>()))
514 return std::tie(first_it, second_it) ==
std::tie(rhs.first_it, rhs.second_it);
518 template <
typename other_range_type>
520 requires std::equality_comparable_with<underlying_iterator_type, std::ranges::iterator_t<other_range_type>> &&
523 constexpr
bool operator!=(basic_iterator<other_range_type>
const & rhs)
const
524 noexcept(noexcept(std::declval<underlying_iterator_type &>() != std::declval<underlying_iterator_type &>()))
526 return !(*
this == rhs);
530 template <
typename other_range_type>
532 requires std::totally_ordered_with<underlying_iterator_type,
533 std::ranges::iterator_t<other_range_type>> &&
536 constexpr
bool operator<(basic_iterator<other_range_type>
const & rhs)
const
537 noexcept(noexcept(std::declval<underlying_iterator_type &>() < std::declval<underlying_iterator_type &>()))
539 return std::tie(first_it, second_it) <
std::tie(rhs.first_it, rhs.second_it);
543 template <
typename other_range_type>
545 requires std::totally_ordered_with<underlying_iterator_type,
546 std::ranges::iterator_t<other_range_type>> &&
549 constexpr
bool operator>(basic_iterator<other_range_type>
const & rhs)
const
550 noexcept(noexcept(std::declval<underlying_iterator_type &>() > std::declval<underlying_iterator_type &>()))
553 return std::tie(first_it, second_it) >
std::tie(rhs.first_it, rhs.second_it);
557 template <
typename other_range_type>
559 requires std::totally_ordered_with<underlying_iterator_type,
560 std::ranges::iterator_t<other_range_type>> &&
563 constexpr
bool operator<=(basic_iterator<other_range_type>
const & rhs)
const
564 noexcept(noexcept(std::declval<underlying_iterator_type &>() <= std::declval<underlying_iterator_type &>()))
566 return std::tie(first_it, second_it) <=
std::tie(rhs.first_it, rhs.second_it);
570 template <
typename other_range_type>
572 requires std::totally_ordered_with<underlying_iterator_type,
573 std::ranges::iterator_t<other_range_type>> &&
576 constexpr
bool operator>=(basic_iterator<other_range_type>
const & rhs)
const
577 noexcept(noexcept(std::declval<underlying_iterator_type &>() >= std::declval<underlying_iterator_type &>()))
579 return std::tie(first_it, second_it) >=
std::tie(rhs.first_it, rhs.second_it);
597 constexpr
size_t to_index() const
598 noexcept(noexcept(
std::declval<underlying_iterator_type &>() -
std::declval<underlying_iterator_type &>()))
600 requires
std::random_access_iterator<underlying_iterator_type>
603 size_t src_size = end_it - begin_it;
604 size_t index_i = first_it - begin_it;
605 size_t index_j = second_it - begin_it;
606 return (src_size * (src_size - 1)/2) - (src_size - index_i) * ((src_size - index_i) - 1)/2 +
607 index_j - index_i - 1;
614 constexpr
void from_index(
size_t const index)
615 noexcept(noexcept(std::declval<underlying_iterator_type &>() - std::declval<underlying_iterator_type &>()) &&
616 noexcept(std::declval<underlying_iterator_type &>() + 1))
618 requires
std::random_access_iterator<underlying_iterator_type>
621 size_t src_size = end_it - begin_it;
622 size_t index_i = src_size - 2 -
624 size_t index_j = index + index_i + 1 - src_size * (src_size - 1)/2 + (src_size - index_i) *
625 ((src_size - index_i) - 1)/2;
626 first_it = begin_it + index_i;
627 second_it = begin_it + index_j;
631 underlying_iterator_type first_it{};
633 underlying_iterator_type second_it{};
635 underlying_iterator_type begin_it{};
637 underlying_iterator_type end_it{};
708 inline constexpr
auto pairwise_combine = detail::adaptor_for_view_without_args<detail::pairwise_combine_view>{};