guanaqo 1.0.0-alpha.25
Utilities for scientific software
Loading...
Searching...
No Matches
set-intersection.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// @ingroup ranges
5/// View for iterating the intersection of two sorted ranges.
6
7#include <algorithm>
8#include <functional>
9#include <iterator>
10#include <ranges>
11
12namespace guanaqo {
13
14/// @ingroup ranges
15template <std::ranges::input_range R1, std::ranges::input_range R2,
16 class Comp = std::ranges::less, class Proj1 = std::identity,
17 class Proj2 = std::identity>
18 requires(std::ranges::view<R1> && std::ranges::view<R2>)
20 : std::ranges::view_interface<
21 set_intersection_iterable<R1, R2, Comp, Proj1, Proj2>> {
22
25 Comp comp;
26 Proj1 proj1;
27 Proj2 proj2;
28
29 // P2325R3: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2325r3.html
32 Proj1 &&proj1, Proj2 &&proj2)
33 : range1{std::forward<R1>(range1)}, range2{std::forward<R2>(range2)},
34 comp{std::forward<Comp>(comp)}, proj1{std::forward<Proj1>(proj1)},
35 proj2{std::forward<Proj2>(proj2)} {}
36
37 struct sentinel_t {};
38 template <std::input_iterator I1, std::sentinel_for<I1> S1,
39 std::input_iterator I2, std::sentinel_for<I2> S2>
40 struct iter_t {
41 // P2325R3: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2325r3.html
42 iter_t() = default;
43 iter_t(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp, Proj1 proj1,
44 Proj2 proj2)
45 : first1{std::move(first1)}, last1{std::move(last1)},
46 first2{std::move(first2)}, last2{std::move(last2)},
47 comp{std::move(comp)}, proj1{std::move(proj1)},
48 proj2{std::move(proj2)} {}
53 Comp comp;
54 Proj1 proj1;
55 Proj2 proj2;
56
57 using difference_type = std::ptrdiff_t; // TODO
58 using value_type = std::tuple<decltype(*first1), decltype(*first2)>;
59
60 bool operator!=(sentinel_t) const {
61 return first1 != last1 && first2 != last2;
62 }
63 bool operator==(sentinel_t s) const { return !(*this != s); }
64 // TODO: For Clang bug
65 friend bool operator!=(sentinel_t s, const iter_t &i) { return i != s; }
66 friend bool operator==(sentinel_t s, const iter_t &i) { return i == s; }
67
69 ++first1, ++first2;
70 advance();
71 return *this;
72 }
74 auto tmp = *this;
75 ++*this;
76 return tmp;
77 }
78 value_type operator*() const { return {*first1, *first2}; }
79 void advance() {
80 while (*this != sentinel_t{}) {
81 if (std::invoke(comp, std::invoke(proj1, *first1),
82 std::invoke(proj2, *first2)))
83 ++first1;
84 else if (std::invoke(comp, std::invoke(proj2, *first2),
85 std::invoke(proj1, *first1)))
86 ++first2;
87 else
88 break;
89 }
90 }
91 };
92
93 private:
94 template <class I1, class S1, class I2, class S2>
95 iter_t<I1, S1, I2, S2> iter(I1 first1, S1 last1, I2 first2,
96 S2 last2) const {
97 return {first1, last1, first2, last2, comp, proj1, proj2};
98 }
99
100 public:
101 [[nodiscard]] auto begin() const -> std::input_or_output_iterator auto {
102 auto it = iter(std::ranges::begin(range1), std::ranges::end(range1),
103 std::ranges::begin(range2), std::ranges::end(range2));
104 it.advance();
105 return it;
106 }
107 [[nodiscard]] auto end() const
108 // -> std::sentinel_for< decltype(std::declval<set_intersection_iterable>().begin())> auto
109 {
110 return sentinel_t{};
111 }
112};
113
114/// @ingroup ranges
115template <std::ranges::viewable_range R1, std::ranges::viewable_range R2,
116 class Comp = std::ranges::less, class Proj1 = std::identity,
117 class Proj2 = std::identity>
118set_intersection_iterable<std::ranges::views::all_t<R1>,
119 std::ranges::views::all_t<R2>, Comp, Proj1, Proj2>
120iter_set_intersection(R1 &&r1, R2 &&r2, Comp comp = {}, Proj1 proj1 = {},
121 Proj2 proj2 = {}) {
122 static_assert(
124 std::ranges::views::all_t<R2>, Comp,
125 Proj1, Proj2>
126 s) {
127 { s.end() } -> std::sentinel_for<decltype(s.begin())>;
128 });
129 return {
130 std::forward<R1>(r1), std::forward<R2>(r2), std::move(comp),
131 std::move(proj1), std::move(proj2),
132 };
133}
134
135} // namespace guanaqo
set_intersection_iterable< std::ranges::views::all_t< R1 >, std::ranges::views::all_t< R2 >, Comp, Proj1, Proj2 > iter_set_intersection(R1 &&r1, R2 &&r2, Comp comp={}, Proj1 proj1={}, Proj2 proj2={})
friend bool operator==(sentinel_t s, const iter_t &i)
friend bool operator!=(sentinel_t s, const iter_t &i)
std::tuple< decltype(*first1), decltype(*first2)> value_type
iter_t(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp, Proj1 proj1, Proj2 proj2)
set_intersection_iterable(R1 &&range1, R2 &&range2, Comp &&comp, Proj1 &&proj1, Proj2 &&proj2)
auto begin() const -> std::input_or_output_iterator auto
iter_t< I1, S1, I2, S2 > iter(I1 first1, S1 last1, I2 first2, S2 last2) const