range_set_blaze/merge.rs
1use core::{iter::FusedIterator, ops::RangeInclusive};
2
3use itertools::{Itertools, KMergeBy, MergeBy};
4
5use crate::{Integer, SortedDisjoint, SortedStarts};
6
7/// Works with [`UnionIter`] to turn any number of [`SortedDisjoint`] iterators into a [`SortedDisjoint`] iterator of their union,
8/// i.e., all the integers in any input iterator, as sorted & disjoint ranges.
9///
10/// Also see [`KMerge`].
11///
12/// [`SortedDisjoint`]: crate::SortedDisjoint
13/// [`UnionIter`]: crate::UnionIter
14///
15/// # Examples
16///
17/// ```
18/// use itertools::Itertools;
19/// use range_set_blaze::{UnionIter, Merge, SortedDisjoint, CheckSortedDisjoint};
20///
21/// let a = CheckSortedDisjoint::new(vec![1..=2, 5..=100]);
22/// let b = CheckSortedDisjoint::from([2..=6]);
23/// let union = UnionIter::new(Merge::new(a, b));
24/// assert_eq!(union.to_string(), "1..=100");
25///
26/// // Or, equivalently:
27/// let a = CheckSortedDisjoint::new(vec![1..=2, 5..=100]);
28/// let b = CheckSortedDisjoint::from([2..=6]);
29/// let c = a | b;
30/// assert_eq!(c.to_string(), "1..=100")
31/// ```
32#[derive(Clone, Debug)]
33#[must_use = "iterators are lazy and do nothing unless consumed"]
34pub struct Merge<T, L, R>
35where
36 T: Integer,
37 L: SortedDisjoint<T>,
38 R: SortedDisjoint<T>,
39{
40 #[allow(clippy::type_complexity)]
41 iter: MergeBy<L, R, fn(&RangeInclusive<T>, &RangeInclusive<T>) -> bool>,
42}
43
44impl<T, L, R> Merge<T, L, R>
45where
46 T: Integer,
47 L: SortedDisjoint<T>,
48 R: SortedDisjoint<T>,
49{
50 /// Creates a new [`Merge`] iterator from two [`SortedDisjoint`] iterators. See [`Merge`] for more details and examples.
51 pub fn new(left: L, right: R) -> Self {
52 Self {
53 iter: left.merge_by(right, |a, b| a.start() < b.start()),
54 }
55 }
56}
57
58impl<T, L, R> FusedIterator for Merge<T, L, R>
59where
60 T: Integer,
61 L: SortedDisjoint<T>,
62 R: SortedDisjoint<T>,
63{
64}
65
66impl<T, L, R> Iterator for Merge<T, L, R>
67where
68 T: Integer,
69 L: SortedDisjoint<T>,
70 R: SortedDisjoint<T>,
71{
72 type Item = RangeInclusive<T>;
73
74 fn next(&mut self) -> Option<Self::Item> {
75 self.iter.next()
76 }
77
78 fn size_hint(&self) -> (usize, Option<usize>) {
79 self.iter.size_hint()
80 }
81}
82
83impl<T, L, R> SortedStarts<T> for Merge<T, L, R>
84where
85 T: Integer,
86 L: SortedDisjoint<T>,
87 R: SortedDisjoint<T>,
88{
89}
90
91/// Works with [`UnionIter`] to turn two [`SortedDisjoint`] iterators into a [`SortedDisjoint`] iterator of their union,
92/// i.e., all the integers in any input iterator, as sorted & disjoint ranges.
93///
94/// Also see [`Merge`].
95///
96/// [`SortedDisjoint`]: crate::SortedDisjoint
97/// [`UnionIter`]: crate::UnionIter
98///
99/// # Examples
100///
101/// ```
102/// use itertools::Itertools;
103/// use range_set_blaze::{UnionIter, KMerge, MultiwaySortedDisjoint, SortedDisjoint, CheckSortedDisjoint};
104///
105/// let a = CheckSortedDisjoint::new(vec![1..=2, 5..=100]);
106/// let b = CheckSortedDisjoint::new(vec![2..=6]);
107/// let c = CheckSortedDisjoint::new(vec![-1..=-1]);
108/// let union = UnionIter::new(KMerge::new([a, b, c]));
109/// assert_eq!(union.to_string(), "-1..=-1, 1..=100");
110///
111/// // Or, equivalently:
112/// let a = CheckSortedDisjoint::new(vec![1..=2, 5..=100]);
113/// let b = CheckSortedDisjoint::new(vec![2..=6]);
114/// let c = CheckSortedDisjoint::new(vec![-1..=-1]);
115/// let union = [a, b, c].union();
116/// assert_eq!(union.to_string(), "-1..=-1, 1..=100");
117/// ```
118#[derive(Clone, Debug)]
119#[must_use = "iterators are lazy and do nothing unless consumed"]
120pub struct KMerge<T, I>
121where
122 T: Integer,
123 I: SortedDisjoint<T>,
124{
125 #[allow(clippy::type_complexity)]
126 iter: KMergeBy<I, fn(&RangeInclusive<T>, &RangeInclusive<T>) -> bool>,
127}
128
129impl<T, I> KMerge<T, I>
130where
131 T: Integer,
132 I: SortedDisjoint<T>,
133{
134 /// Creates a new [`KMerge`] iterator from zero or more [`SortedDisjoint`] iterators. See [`KMerge`] for more details and examples.
135 pub fn new<J>(iter: J) -> Self
136 where
137 J: IntoIterator<Item = I>,
138 {
139 Self {
140 iter: iter.into_iter().kmerge_by(|a, b| a.start() < b.start()),
141 }
142 }
143}
144
145impl<T, I> FusedIterator for KMerge<T, I>
146where
147 T: Integer,
148 I: SortedDisjoint<T>,
149{
150}
151
152impl<T, I> Iterator for KMerge<T, I>
153where
154 T: Integer,
155 I: SortedDisjoint<T>,
156{
157 type Item = RangeInclusive<T>;
158
159 fn next(&mut self) -> Option<Self::Item> {
160 self.iter.next()
161 }
162
163 fn size_hint(&self) -> (usize, Option<usize>) {
164 self.iter.size_hint()
165 }
166}
167
168impl<T, I> SortedStarts<T> for KMerge<T, I>
169where
170 T: Integer,
171 I: SortedDisjoint<T>,
172{
173}