1use crate::ClosedRange;
3use crate::Endpoint;
4use crate::IntoNormalizedRangeIter;
5use crate::NormalizedRangeIter;
6use crate::RangeVec;
7
8use core::iter::Peekable;
9
10pub struct UnionIterator<T, X, Y>
11where
12 T: Endpoint,
13 X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
14 Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
15{
16 accumulator: Option<(T, T)>,
17 left: Peekable<X>,
18 right: Peekable<Y>,
19}
20
21impl<T, X, Y> UnionIterator<T, X, Y>
22where
23 T: Endpoint,
24 X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
25 Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
26{
27 pub fn new(left: X, right: Y) -> Self {
28 Self {
29 accumulator: None,
30 left: left.peekable(),
31 right: right.peekable(),
32 }
33 }
34}
35
36impl<T, X, Y> Iterator for UnionIterator<T, X, Y>
37where
38 T: Endpoint,
39 X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
40 Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
41{
42 type Item = (T, T);
43
44 fn next(&mut self) -> Option<(T, T)> {
45 use core::cmp::Ordering; loop {
48 let next;
49
50 match (
51 self.left.peek().map(|x| x.get()),
52 self.right.peek().map(|x| x.get()),
53 ) {
54 (Some(left), Some(right)) if T::cmp_range(left, right) <= Ordering::Equal => {
55 next = left;
56 self.left.next();
57 }
58 (Some(_), Some(right)) => {
59 next = right;
60 self.right.next();
61 }
62 (Some(x), None) => {
63 next = x;
64 self.left.next();
65 }
66 (None, Some(x)) => {
67 next = x;
68 self.right.next();
69 }
70 (None, None) => return self.accumulator.take(),
71 };
72
73 let (next_start, next_stop) = next;
74 let Some((acc_start, acc_stop)) = self.accumulator.take() else {
75 self.accumulator = Some(next);
76 continue;
77 };
78
79 if let Some(min_start) = acc_stop.increase_toward(next_start) {
81 if next_start.cmp_end(min_start) > Ordering::Equal {
83 self.accumulator = Some(next);
84 return Some((acc_start, acc_stop));
85 }
86 }
87
88 self.accumulator = Some((acc_start, acc_stop.top_end(next_stop)));
89 }
90 }
91
92 #[inline]
93 fn size_hint(&self) -> (usize, Option<usize>) {
94 let (left_min, left_max) = self.left.size_hint();
95 let (right_min, right_max) = self.right.size_hint();
96
97 let max = left_max
98 .unwrap_or(usize::MAX)
99 .checked_add(right_max.unwrap_or(usize::MAX));
100 let min = ((left_min != 0) | (right_min != 0)) as usize;
103 (min, max)
104 }
105}
106
107impl<T, X, Y> crate::private::Sealed for UnionIterator<T, X, Y>
108where
109 T: Endpoint,
110 X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
111 Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
112{
113}
114
115impl<T, X, Y> NormalizedRangeIter for UnionIterator<T, X, Y>
116where
117 T: Endpoint,
118 X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
119 Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
120{
121}
122
123impl<T, X, Y> core::iter::FusedIterator for UnionIterator<T, X, Y>
125where
126 T: Endpoint,
127 X: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
128 Y: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange<EndT = T>>,
129{
130}
131
132impl<T: Endpoint> RangeVec<T> {
133 #[inline(always)]
144 pub fn union(&self, other: impl IntoNormalizedRangeIter<Item: ClosedRange<EndT = T>>) -> Self {
145 #[inline(never)]
146 fn doit<T: Endpoint>(
147 this: &RangeVec<T>,
148 other: impl NormalizedRangeIter<Item: ClosedRange<EndT = T>>,
149 ) -> RangeVec<T> {
150 this.iter().union(other).collect_range_vec()
151 }
152
153 doit(self, other.into_iter())
154 }
155}
156
157#[cfg(test)]
158#[cfg_attr(coverage_nightly, coverage(off))]
159mod test {
160 use super::*;
161 use alloc::vec;
162 use alloc::vec::Vec;
163
164 #[test]
165 fn test_union_iterator_smoke() {
166 use crate::NormalizedRangeIter;
167
168 let acc = vec![(1u8, 4u8), (5u8, 1u8), (5u8, 10u8)];
169 let src = [(0u8, 2u8), (11u8, 15u8)];
170
171 assert_eq!(
172 crate::normalize_vec(acc.clone())
173 .iter()
174 .union(crate::normalize_vec(src.to_vec()).into_iter())
175 .collect_range_vec()
176 .into_vec(),
177 vec![(0u8, 15u8)]
178 );
179
180 assert_eq!(
181 crate::normalize_vec(src.to_vec())
182 .iter()
183 .union(crate::normalize_vec(vec![]))
184 .collect_range_vec()
185 .into_vec(),
186 src.to_vec()
187 );
188
189 {
190 let empty = Vec::<(u8, u8)>::new();
191 let mut union = crate::normalize_vec(empty.clone())
192 .into_iter()
193 .union(crate::normalize_vec(empty).into_iter());
194
195 assert_eq!(union.next(), None);
196 assert_eq!(union.next(), None);
198 }
199 }
200
201 proptest::proptest! {
202 #[test]
203 fn test_union_iterator(xs: Vec<(u8, u8)>, ys: Vec<(u8, u8)>)
204 {
205 use crate::RangeVec;
206 use crate::ranges_to_bits;
207
208 let bits = {
209 let mut all_ranges = xs.clone();
210 all_ranges.extend(&ys);
211 ranges_to_bits(&all_ranges)
212 };
213
214 let xs = RangeVec::from_vec(xs);
215 let ys = RangeVec::from_vec(ys);
216
217 {
218 let union = xs.iter().union(ys.iter());
219
220 let (min_size, max_size) = union.size_hint();
221 if !xs.is_empty() || !ys.is_empty() {
222 assert!(min_size > 0);
223 } else {
224 assert!(min_size == 0);
225 }
226
227 let max_size = max_size.expect("should have limits");
228 assert!(max_size == xs.len() + ys.len());
229
230 let union = union.collect_range_vec();
231 assert_eq!(bits, ranges_to_bits(&union));
232 }
233
234 {
235 let union = ys.iter().union(xs).collect_range_vec();
236 assert_eq!(bits, ranges_to_bits(&union));
237 }
238 }
239
240 #[test]
241 fn test_union_iterator_identities(xs: Vec<(u8, u8)>)
242 {
243 let xs = RangeVec::from_vec(xs);
244
245 {
247 let xxs = xs.iter().union(xs.iter()).collect_range_vec();
248 assert_eq!(&xxs, &xs);
249 }
250
251 let universe = xs.iter().union(xs.iter().complement()).collect_range_vec();
253 assert_eq!(universe.inner(), &[(0, 255u8)]);
254 }
255 }
256}