22 namespace seqan3::detail
39 template <std::ranges::view underlying_range_type>
41 requires std::ranges::forward_range<underlying_range_type> && std::ranges::common_range<underlying_range_type>
43 class pairwise_combine_view :
public std::ranges::view_interface<pairwise_combine_view<underlying_range_type>>
60 template <
typename range_type>
66 template <
typename other_range_type>
68 friend class iterator_type;
71 using underlying_iterator_type = std::ranges::iterator_t<range_type>;
87 using reference = common_tuple<underlying_ref_t, underlying_ref_t>;
91 using iterator_category = iterator_tag_t<underlying_iterator_type>;
97 constexpr iterator_type() noexcept = default;
98 constexpr iterator_type(iterator_type const &) noexcept = default;
99 constexpr iterator_type(iterator_type &&) noexcept = default;
100 constexpr iterator_type & operator=(iterator_type const &) noexcept = default;
101 constexpr iterator_type & operator=(iterator_type &&) noexcept = default;
102 ~iterator_type() noexcept = default;
116 constexpr iterator_type(underlying_iterator_type iter,
117 underlying_iterator_type begin_it,
118 underlying_iterator_type end_it) noexcept :
133 template <
typename other_range_type>
138 constexpr iterator_type(iterator_type<other_range_type> other) noexcept :
146 constexpr reference operator*() const
148 noexcept(noexcept(*
std::declval<underlying_iterator_type>()))
150 return reference{*first_it, *second_it};
156 constexpr reference operator[](
size_t const index)
157 noexcept(noexcept(std::declval<iterator_type &>().from_index(1)))
159 requires
std::random_access_iterator<underlying_iterator_type>
170 constexpr iterator_type & operator++()
172 noexcept(noexcept(++
std::declval<underlying_iterator_type &>()))
174 if (++second_it == end_it)
177 second_it = first_it;
184 constexpr iterator_type operator++(
int )
185 noexcept(noexcept(std::declval<underlying_iterator_type &>()++))
187 iterator_type tmp{*
this};
193 constexpr iterator_type & operator--()
194 noexcept(noexcept(--
std::declval<underlying_iterator_type &>()))
196 requires
std::bidirectional_iterator<underlying_iterator_type>
199 if (--second_it == first_it)
209 constexpr iterator_type operator--(
int )
210 noexcept(noexcept(std::declval<underlying_iterator_type &>()--))
212 requires
std::bidirectional_iterator<underlying_iterator_type>
215 iterator_type tmp{*
this};
222 constexpr iterator_type & operator+=(difference_type
const offset)
223 noexcept(noexcept(std::declval<iterator_type &>().from_index(1)))
225 requires
std::random_access_iterator<underlying_iterator_type>
228 from_index(to_index() +
offset);
234 constexpr iterator_type operator+(difference_type
const offset)
235 noexcept(noexcept(std::declval<iterator_type &>() += 1))
237 requires
std::random_access_iterator<underlying_iterator_type>
240 iterator_type tmp{*
this};
246 constexpr
friend iterator_type operator+(difference_type
const offset, iterator_type iter)
247 noexcept(noexcept(
std::declval<iterator_type<range_type> &>().from_index(1)))
249 requires
std::random_access_iterator<underlying_iterator_type>
252 iter.from_index(iter.to_index() +
offset);
258 constexpr iterator_type & operator-=(difference_type
const offset)
259 noexcept(noexcept(std::declval<iterator_type &>().from_index(1)))
261 requires
std::random_access_iterator<underlying_iterator_type>
264 from_index(to_index() -
offset);
270 constexpr iterator_type operator-(difference_type
const offset)
271 noexcept(noexcept(std::declval<iterator_type &>() -= 1))
273 requires
std::random_access_iterator<underlying_iterator_type>
276 iterator_type tmp{*
this};
282 template <
typename other_range_type>
284 requires std::random_access_iterator<underlying_iterator_type> &&
287 constexpr difference_type operator-(iterator_type<other_range_type>
const & rhs)
const
288 noexcept(noexcept(std::declval<iterator_type &>().to_index()))
290 return static_cast<difference_type>(to_index() - rhs.to_index());
304 template <
typename other_range_type>
309 constexpr
bool operator==(iterator_type<other_range_type>
const & rhs)
const
310 noexcept(noexcept(std::declval<underlying_iterator_type &>() == std::declval<underlying_iterator_type &>()))
312 return std::tie(first_it, second_it) ==
std::tie(rhs.first_it, rhs.second_it);
316 template <
typename other_range_type>
321 constexpr
bool operator!=(iterator_type<other_range_type>
const & rhs)
const
322 noexcept(noexcept(std::declval<underlying_iterator_type &>() != std::declval<underlying_iterator_type &>()))
324 return !(*
this == rhs);
328 template <
typename other_range_type>
331 std::ranges::iterator_t<other_range_type>> &&
334 constexpr
bool operator<(iterator_type<other_range_type>
const & rhs)
const
335 noexcept(noexcept(std::declval<underlying_iterator_type &>() < std::declval<underlying_iterator_type &>()))
337 return std::tie(first_it, second_it) <
std::tie(rhs.first_it, rhs.second_it);
341 template <
typename other_range_type>
344 std::ranges::iterator_t<other_range_type>> &&
347 constexpr
bool operator>(iterator_type<other_range_type>
const & rhs)
const
348 noexcept(noexcept(std::declval<underlying_iterator_type &>() > std::declval<underlying_iterator_type &>()))
351 return std::tie(first_it, second_it) >
std::tie(rhs.first_it, rhs.second_it);
355 template <
typename other_range_type>
358 std::ranges::iterator_t<other_range_type>> &&
361 constexpr
bool operator<=(iterator_type<other_range_type>
const & rhs)
const
362 noexcept(noexcept(std::declval<underlying_iterator_type &>() <= std::declval<underlying_iterator_type &>()))
364 return std::tie(first_it, second_it) <=
std::tie(rhs.first_it, rhs.second_it);
368 template <
typename other_range_type>
371 std::ranges::iterator_t<other_range_type>> &&
374 constexpr
bool operator>=(iterator_type<other_range_type>
const & rhs)
const
375 noexcept(noexcept(std::declval<underlying_iterator_type &>() >= std::declval<underlying_iterator_type &>()))
377 return std::tie(first_it, second_it) >=
std::tie(rhs.first_it, rhs.second_it);
395 constexpr
size_t to_index() const
396 noexcept(noexcept(
std::declval<underlying_iterator_type &>() -
std::declval<underlying_iterator_type &>()))
398 requires
std::random_access_iterator<underlying_iterator_type>
401 size_t src_size = end_it - begin_it;
402 size_t index_i = first_it - begin_it;
403 size_t index_j = second_it - begin_it;
404 return (src_size * (src_size - 1)/2) - (src_size - index_i) * ((src_size - index_i) - 1)/2 +
405 index_j - index_i - 1;
412 constexpr
void from_index(
size_t const index)
413 noexcept(noexcept(std::declval<underlying_iterator_type &>() - std::declval<underlying_iterator_type &>()) &&
414 noexcept(std::declval<underlying_iterator_type &>() + 1))
416 requires
std::random_access_iterator<underlying_iterator_type>
419 size_t src_size = end_it - begin_it;
420 size_t index_i = src_size - 2 -
422 size_t index_j = index + index_i + 1 - src_size * (src_size - 1)/2 + (src_size - index_i) *
423 ((src_size - index_i) - 1)/2;
424 first_it = begin_it + index_i;
425 second_it = begin_it + index_j;
429 underlying_iterator_type first_it{};
431 underlying_iterator_type second_it{};
433 underlying_iterator_type begin_it{};
435 underlying_iterator_type end_it{};
444 using iterator = iterator_type<underlying_range_type>;
447 using const_iterator = transformation_trait_or_t<std::type_identity<iterator_type<underlying_range_type const>>,
450 using reference =
typename iterator::reference;
452 using const_reference = reference;
454 using value_type =
typename iterator::value_type;
456 using size_type = detail::transformation_trait_or_t<seqan3::size_type<underlying_range_type>,
void>;
458 using difference_type = difference_type_t<iterator>;
464 constexpr pairwise_combine_view() =
default;
467 constexpr pairwise_combine_view(pairwise_combine_view
const &) =
default;
469 constexpr pairwise_combine_view(pairwise_combine_view &&) =
default;
471 constexpr pairwise_combine_view & operator=(pairwise_combine_view
const &) =
default;
473 constexpr pairwise_combine_view & operator=(pairwise_combine_view &&) =
default;
475 ~pairwise_combine_view() =
default;
493 explicit constexpr pairwise_combine_view(underlying_range_type range) : u_range{
std::move(range)}
496 if (std::ranges::empty(u_range))
498 back_iterator = std::ranges::end(u_range);
502 if constexpr (std::ranges::bidirectional_range<underlying_range_type>)
504 back_iterator = std::ranges::prev(std::ranges::end(u_range));
509 if constexpr (std::ranges::sized_range<underlying_range_type>)
515 auto tmp_it = back_iterator;
518 back_iterator = tmp_it;
519 }
while (++tmp_it != std::ranges::end(u_range));
544 template <
typename other_range_t>
547 std::ranges::viewable_range<other_range_t> &&
553 explicit constexpr pairwise_combine_view(other_range_t && range) :
554 pairwise_combine_view{
std::views::all(std::forward<other_range_t>(range))}
573 constexpr iterator
begin() noexcept
579 constexpr const_iterator
begin() const noexcept
588 constexpr const_iterator
cbegin() const noexcept
609 constexpr iterator
end() noexcept
615 constexpr const_iterator
end() const noexcept
624 constexpr const_iterator
cend() const noexcept
636 constexpr size_type
size() const noexcept
639 requires
std::ranges::sized_range<underlying_range_type>
649 underlying_range_type u_range{};
651 std::ranges::iterator_t<underlying_range_type> back_iterator{};
658 template <std::ranges::viewable_range other_range_t>
660 pairwise_combine_view(other_range_t && range) ->
661 pairwise_combine_view<std::ranges::all_view<other_range_t>>;
732 inline constexpr
auto pairwise_combine = detail::adaptor_for_view_without_args<detail::pairwise_combine_view>{};