23namespace bio::ranges::detail
40template <std::ranges::view underlying_range_type>
41 requires(std::ranges::forward_range<underlying_range_type> && std::ranges::common_range<underlying_range_type>)
42class pairwise_combine_view :
public std::ranges::view_interface<pairwise_combine_view<underlying_range_type>>
46 template <
typename range_type2>
54 using iterator = basic_iterator<underlying_range_type>;
56 using const_iterator =
57 meta::transformation_trait_or_t<std::type_identity<basic_iterator<underlying_range_type const>>,
void>;
64 pairwise_combine_view() =
default;
65 pairwise_combine_view(pairwise_combine_view
const &) =
default;
66 pairwise_combine_view(pairwise_combine_view &&) noexcept = default;
67 pairwise_combine_view & operator=(pairwise_combine_view const &) = default;
68 pairwise_combine_view & operator=(pairwise_combine_view &&) noexcept = default;
69 ~pairwise_combine_view() = default;
87 explicit constexpr pairwise_combine_view(underlying_range_type range) : u_range{std::move(range)}
90 if (std::ranges::empty(u_range))
92 back_iterator = std::ranges::end(u_range);
96 if constexpr (std::ranges::bidirectional_range<underlying_range_type>)
98 back_iterator = std::ranges::prev(std::ranges::end(u_range));
103 if constexpr (std::ranges::sized_range<underlying_range_type>)
105 std::ranges::advance(back_iterator, std::ranges::size(u_range) - 1);
109 auto tmp_it = back_iterator;
112 back_iterator = tmp_it;
114 while (++tmp_it != std::ranges::end(u_range));
139 template <meta::different_from<pairwise_combine_view> other_range_t>
140 requires(std::ranges::viewable_range<other_range_t> &&
141 std::constructible_from<underlying_range_type, std::views::all_t<other_range_t>>)
142 explicit constexpr pairwise_combine_view(other_range_t && range) :
143 pairwise_combine_view{std::views::all(std::forward<other_range_t>(range))}
162 constexpr iterator
begin() noexcept
168 constexpr const_iterator
begin() const noexcept
169 requires const_iterable_range<underlying_range_type>
187 constexpr iterator
end() noexcept
193 constexpr const_iterator
end() const noexcept
194 requires const_iterable_range<underlying_range_type>
204 constexpr auto size() const noexcept
205 requires
std::ranges::sized_range<underlying_range_type>
207 return (std::ranges::size(u_range) * (std::ranges::size(u_range) - 1) / 2);
213 underlying_range_type u_range;
215 std::ranges::iterator_t<underlying_range_type> back_iterator;
223template <std::ranges::viewable_range other_range_t>
224pairwise_combine_view(other_range_t && range) -> pairwise_combine_view<std::views::all_t<other_range_t>>;
240template <std::ranges::view underlying_range_type>
241 requires(std::ranges::forward_range<underlying_range_type> && std::ranges::common_range<underlying_range_type>)
242template <typename range_type>
243class pairwise_combine_view<underlying_range_type>::basic_iterator
247 template <
typename range_type2>
248 friend class basic_iterator;
251 using underlying_iterator_type = std::ranges::iterator_t<range_type>;
269 using pointer = void;
271 using iterator_category = detail::iterator_category_tag_t<underlying_iterator_type>;
273 using iterator_concept = detail::iterator_concept_tag_t<underlying_iterator_type>;
279 basic_iterator() =
default;
280 basic_iterator(basic_iterator
const &) =
default;
281 basic_iterator(basic_iterator &&) noexcept = default;
282 basic_iterator & operator=(basic_iterator const &) = default;
283 basic_iterator & operator=(basic_iterator &&) noexcept = default;
284 ~basic_iterator() = default;
298 constexpr basic_iterator(underlying_iterator_type iter,
299 underlying_iterator_type begin_it,
300 underlying_iterator_type end_it) noexcept :
301 first_it{iter}, second_it{std::ranges::next(iter, 1, end_it)}, begin_it{begin_it}, end_it{end_it}
312 template <
typename other_range_type>
313 requires(std::convertible_to<other_range_type, range_type &> &&
315 constexpr basic_iterator(basic_iterator<other_range_type> other) noexcept :
316 basic_iterator{std::move(other.first_it), std::move(other.begin_it), std::move(other.end_it)}
324 constexpr reference operator*() const noexcept(noexcept(*
std::declval<underlying_iterator_type>()))
326 return reference{*first_it, *second_it};
332 constexpr reference operator[](
size_t const index)
const
333 noexcept(
noexcept(std::declval<basic_iterator &>().from_index(1)))
334 requires std::random_access_iterator<underlying_iterator_type>
336 return *(*
this + index);
344 constexpr basic_iterator & operator++() noexcept(
345 noexcept(++
std::declval<underlying_iterator_type &>()))
347 if (++second_it == end_it)
350 second_it = first_it;
357 constexpr basic_iterator operator++(
int )
noexcept(
358 noexcept(std::declval<underlying_iterator_type &>()++))
360 basic_iterator tmp{*
this};
366 constexpr basic_iterator & operator--() noexcept(
367 noexcept(--
std::declval<underlying_iterator_type &>()))
368 requires
std::bidirectional_iterator<underlying_iterator_type>
370 if (--second_it == first_it)
380 constexpr basic_iterator operator--(
int )
noexcept(
381 noexcept(std::declval<underlying_iterator_type &>()--))
382 requires std::bidirectional_iterator<underlying_iterator_type>
384 basic_iterator tmp{*
this};
391 constexpr basic_iterator & operator+=(difference_type
const offset)
noexcept(
392 noexcept(std::declval<basic_iterator &>().from_index(1)))
393 requires std::random_access_iterator<underlying_iterator_type>
395 from_index(to_index() + offset);
401 constexpr basic_iterator operator+(difference_type
const offset)
const
402 noexcept(
noexcept(std::declval<basic_iterator &>() += 1))
403 requires std::random_access_iterator<underlying_iterator_type>
405 basic_iterator tmp{*
this};
406 return (tmp += offset);
411 constexpr friend basic_iterator operator+(difference_type
const offset, basic_iterator iter)
noexcept(
412 noexcept(std::declval<basic_iterator<range_type> &>().from_index(1)))
413 requires std::random_access_iterator<underlying_iterator_type>
415 iter.from_index(iter.to_index() + offset);
421 constexpr basic_iterator & operator-=(difference_type
const offset)
noexcept(
422 noexcept(std::declval<basic_iterator &>().from_index(1)))
423 requires std::random_access_iterator<underlying_iterator_type>
425 from_index(to_index() - offset);
431 constexpr basic_iterator operator-(difference_type
const offset)
const
432 noexcept(
noexcept(std::declval<basic_iterator &>() -= 1))
433 requires std::random_access_iterator<underlying_iterator_type>
435 basic_iterator tmp{*
this};
436 return (tmp -= offset);
441 template <
typename other_range_type>
442 requires(std::random_access_iterator<underlying_iterator_type> &&
444 constexpr difference_type
operator-(basic_iterator<other_range_type>
const & rhs)
const
445 noexcept(
noexcept(std::declval<basic_iterator &>().to_index()))
447 return static_cast<difference_type
>(to_index() - rhs.to_index());
457 constexpr friend bool operator==(basic_iterator
const lhs, basic_iterator
const rhs)
noexcept(
458 noexcept(std::declval<underlying_iterator_type &>() == std::declval<underlying_iterator_type &>()))
460 return std::tie(lhs.first_it, lhs.second_it) ==
std::tie(rhs.first_it, rhs.second_it);
464 constexpr friend auto operator<=>(basic_iterator
const lhs, basic_iterator
const rhs)
noexcept(
465 noexcept(std::declval<underlying_iterator_type &>() < std::declval<underlying_iterator_type &>()))
467 return std::tie(lhs.first_it, lhs.second_it) <=>
std::tie(rhs.first_it, rhs.second_it);
484 constexpr size_t to_index() const
485 noexcept(noexcept(
std::declval<underlying_iterator_type &>() -
std::declval<underlying_iterator_type &>()))
486 requires
std::random_access_iterator<underlying_iterator_type>
488 size_t src_size = end_it - begin_it;
489 size_t index_i = first_it - begin_it;
490 size_t index_j = second_it - begin_it;
491 return (src_size * (src_size - 1) / 2) - (src_size - index_i) * ((src_size - index_i) - 1) / 2 + index_j -
499 constexpr void from_index(
size_t const index)
noexcept(
500 noexcept(std::declval<underlying_iterator_type &>() -
501 std::declval<underlying_iterator_type &>()) &&
noexcept(std::declval<underlying_iterator_type &>() + 1))
502 requires std::random_access_iterator<underlying_iterator_type>
504 size_t src_size = end_it - begin_it;
506 src_size - 2 -
static_cast<size_t>(
std::sqrt(-8 * index + 4 * src_size * (src_size - 1) - 7) / 2.0 - 0.5);
508 index + index_i + 1 - src_size * (src_size - 1) / 2 + (src_size - index_i) * ((src_size - index_i) - 1) / 2;
509 first_it = begin_it + index_i;
510 second_it = begin_it + index_j;
514 underlying_iterator_type first_it{};
516 underlying_iterator_type second_it{};
518 underlying_iterator_type begin_it{};
520 underlying_iterator_type end_it{};
591inline constexpr auto pairwise_combine = detail::adaptor_for_view_without_args<detail::pairwise_combine_view>{};
constexpr auto size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:517
constexpr auto pairwise_combine
A view adaptor that generates all pairwise combinations of the elements of the underlying range.
Definition: pairwise_combine.hpp:591
The BioC++ namespace for views.
Additional non-standard concepts for ranges.
Auxiliary header for the views submodule .