closed_interval_set/
intersection.rs

1use crate::slice_sequence::Sequence;
2use crate::ClosedRange;
3use crate::ClosedRangeVal;
4use crate::Endpoint;
5use crate::NormalizedRangeIter;
6use crate::Pair;
7use crate::RangeVec;
8
9/// The core [`IntersectorImpl`] works over [`Sequence`] rather than
10/// raw slices because the standard slice interface is full of hidden
11/// panics; the [`Sequence`] trait is small enough to audit, and
12/// doesn't itself hide panics in its interface.
13///
14/// The underlying [`Sequence`] must come from a normalized `RangeVec`.
15struct IntersectorImpl<Seq: Sequence> {
16    seq: Seq,
17    search_cursor: Seq,
18    intersect_cursor: Seq,
19}
20
21impl<Seq: Sequence> IntersectorImpl<Seq> {
22    #[inline(always)]
23    fn new(seq: Seq) -> Self {
24        Self {
25            seq,
26            search_cursor: seq,
27            intersect_cursor: seq,
28        }
29    }
30
31    #[inline(always)]
32    fn start_search(&mut self, start: Seq::EndT) {
33        self.search_cursor = self.seq.skip_to((start, start), self.search_cursor);
34        self.intersect_cursor = self.search_cursor;
35    }
36
37    fn pump(&mut self, needle: Pair<Seq::EndT>) -> Option<Pair<Seq::EndT>> {
38        // Safe to compare because `seq` and its cursors are normalized.
39        use core::cmp::Ordering;
40
41        let (x_start, x_stop) = needle;
42
43        while let Some(((y_start, y_stop), rest)) = self.intersect_cursor.uncons() {
44            self.intersect_cursor = rest;
45
46            if y_start.cmp_end(x_stop) == Ordering::Greater {
47                return None;
48            }
49
50            let start = x_start.top_end(y_start);
51            let stop = x_stop.bot_end(y_stop);
52
53            if start.cmp_end(stop) <= Ordering::Equal {
54                return Some((start, stop));
55            }
56        }
57
58        None
59    }
60}
61
62#[repr(transparent)]
63pub struct Intersector<'a, T: Endpoint>(IntersectorImpl<&'a [(T, T)]>);
64
65impl<'a, T: Endpoint> Intersector<'a, T> {
66    #[inline(always)]
67    fn new(seq: &'a [(T, T)]) -> Self {
68        Self(IntersectorImpl::new(seq))
69    }
70
71    #[inline(always)]
72    fn start_search(&mut self, start: T) {
73        self.0.start_search(start)
74    }
75
76    #[inline(always)]
77    fn pump(&mut self, needle: (T, T)) -> Option<(T, T)> {
78        self.0.pump(needle)
79    }
80}
81
82pub struct IntersectionIterator<'a, Xs: NormalizedRangeIter> {
83    // No need to fuse: we only call `next` after `None` when
84    // we're called after returning `None`
85    xs: Xs,
86    intersector: Intersector<'a, <<Xs as Iterator>::Item as ClosedRange>::EndT>,
87    curr: Option<ClosedRangeVal<<Xs as Iterator>::Item>>,
88}
89
90impl<'a, Xs: NormalizedRangeIter> IntersectionIterator<'a, Xs> {
91    #[inline(always)]
92    fn new(xs: Xs, ys: &'a [ClosedRangeVal<<Xs as Iterator>::Item>]) -> Self {
93        Self {
94            xs,
95            intersector: Intersector::new(ys),
96            curr: None,
97        }
98    }
99}
100
101impl<Xs: NormalizedRangeIter> Iterator for IntersectionIterator<'_, Xs> {
102    type Item = ClosedRangeVal<<Xs as Iterator>::Item>;
103
104    fn next(&mut self) -> Option<Self::Item> {
105        loop {
106            let curr = match self.curr {
107                Some(curr) => curr,
108                None => {
109                    let next = self.xs.next()?.get();
110                    self.intersector.start_search(next.0);
111                    self.curr = Some(next);
112                    next
113                }
114            };
115
116            if let Some(ret) = self.intersector.pump(curr) {
117                return Some(ret);
118            }
119
120            self.curr = None;
121        }
122    }
123
124    #[inline]
125    fn size_hint(&self) -> (usize, Option<usize>) {
126        // The intersection can always be empty, but each output range
127        // consumed (at least) one input range.
128        let (_, x_max) = self.xs.size_hint();
129        let y_max = self.intersector.0.search_cursor.len();
130
131        if (x_max == Some(0)) | (y_max == 0) {
132            (0, Some(0))
133        } else {
134            (0, x_max.unwrap_or(usize::MAX).checked_add(y_max))
135        }
136    }
137}
138
139impl<Xs: NormalizedRangeIter> crate::private::Sealed for IntersectionIterator<'_, Xs> {}
140
141impl<Xs: NormalizedRangeIter> crate::NormalizedRangeIter for IntersectionIterator<'_, Xs> {}
142
143impl<Xs: NormalizedRangeIter + core::iter::FusedIterator> core::iter::FusedIterator
144    for IntersectionIterator<'_, Xs>
145{
146}
147
148/// This internal implementation assumes `ys` is normalised.
149#[inline(always)]
150pub(crate) unsafe fn intersect<Xs: NormalizedRangeIter>(
151    xs: Xs,
152    ys: &[ClosedRangeVal<<Xs as Iterator>::Item>],
153) -> IntersectionIterator<'_, Xs> {
154    IntersectionIterator::new(xs, ys)
155}
156
157impl<T: Endpoint> RangeVec<T> {
158    /// Constructs the intersection of this [`RangeVec`] and another
159    /// [`RangeVec`].
160    ///
161    /// This operation takes at most \\(\mathcal{O}(\min(m + n, m \log n))\\)
162    /// time, where \\(m\\) is the size of `self`, and \\(n\\) that of `other`.
163    #[inline(always)]
164    pub fn intersect_vec<'a>(&'a self, other: &'a RangeVec<T>) -> Self {
165        intersect_vec(self, other)
166    }
167}
168/// Constructs the intersection of two normalized vectors of ranges.
169///
170/// Since both arguments are guaranteed to be normalized, we can
171/// iterate over the shorter one and binary search over the longer
172/// one, which is usually a good idea.
173///
174/// This operation takes at most \\(\mathcal{O}(\min(m + n, m \log n))\\)
175/// time, where \\(m\\) is the size of the shorter [`RangeVec`], and
176/// \\(n\\) that of the longer [`RangeVec`].
177#[inline(never)]
178pub fn intersect_vec<'a, T: Endpoint>(
179    mut xs: &'a RangeVec<T>,
180    mut ys: &'a RangeVec<T>,
181) -> RangeVec<T> {
182    #[cfg(feature = "internal_checks")]
183    let expected = (
184        xs.iter().intersect(ys.iter()).collect_range_vec(),
185        ys.iter().intersect(xs.iter()).collect_range_vec(),
186        xs.iter().intersect_vec(ys).collect_range_vec(),
187        ys.iter().intersect_vec(xs).collect_range_vec(),
188    );
189
190    if xs.len() > ys.len() {
191        core::mem::swap(&mut xs, &mut ys);
192    }
193
194    debug_assert!(xs.len() <= ys.len());
195    let intersection = xs.iter().intersect_vec(ys);
196    let size_hint = intersection.size_hint();
197
198    let ret = intersection.collect_range_vec();
199
200    // If any input is empty -> we know the intersection is empty.
201    debug_assert!((!(xs.is_empty() | ys.is_empty())) | (size_hint == (0, Some(0))));
202    debug_assert!(size_hint.0 <= ret.len());
203    debug_assert!(ret.len() <= size_hint.1.unwrap());
204
205    #[cfg(feature = "internal_checks")]
206    {
207        assert!(&expected.0.eqv(&ret));
208        assert!(&expected.1.eqv(&ret));
209        assert!(&expected.2.eqv(&ret));
210        assert!(&expected.3.eqv(&ret));
211    }
212
213    ret
214}
215
216#[cfg(test)]
217#[cfg_attr(coverage_nightly, coverage(off))]
218mod test {
219    use super::*;
220    use alloc::vec;
221    use alloc::vec::Vec;
222
223    #[test]
224    fn test_smoke() {
225        // intersection of two empty sets -> empty set
226        assert!(crate::normalize_vec(Vec::<(u8, u8)>::new())
227            .iter()
228            .intersect_vec(&crate::normalize_vec(Vec::<(u8, u8)>::new()))
229            .collect_range_vec()
230            .is_empty());
231
232        let xs = crate::normalize_vec(vec![(1u8, 1u8), (3u8, 4u8), (10u8, 20u8), (30u8, 100u8)]);
233        let ys = crate::normalize_vec(vec![
234            (0u8, 6u8),
235            (8u8, 15u8),
236            (17u8, 18u8),
237            (20u8, 22u8),
238            (200u8, 200u8),
239        ]);
240
241        // intersection of anything with empty set -> empty set
242        assert!(crate::normalize_vec(Vec::<(u8, u8)>::new())
243            .iter()
244            .intersect_vec(&xs)
245            .collect_range_vec()
246            .is_empty());
247        assert!(ys
248            .clone()
249            .intersect(&crate::normalize_vec(Vec::<(u8, u8)>::new()))
250            .is_empty());
251
252        assert_eq!(
253            xs.clone().intersect(&ys).into_vec(),
254            vec![
255                (1u8, 1u8),
256                (3u8, 4u8),
257                (10u8, 15u8),
258                (17u8, 18u8),
259                (20u8, 20u8)
260            ]
261        );
262
263        assert_eq!(
264            xs.intersect_vec(&ys).into_vec(),
265            vec![
266                (1u8, 1u8),
267                (3u8, 4u8),
268                (10u8, 15u8),
269                (17u8, 18u8),
270                (20u8, 20u8)
271            ]
272        );
273
274        assert_eq!(
275            intersect_vec(&ys, &xs).into_vec(),
276            vec![
277                (1u8, 1u8),
278                (3u8, 4u8),
279                (10u8, 15u8),
280                (17u8, 18u8),
281                (20u8, 20u8)
282            ]
283        );
284
285        assert_eq!(
286            xs.iter().intersect_vec(&ys).collect::<Vec<_>>(),
287            vec![
288                (1u8, 1u8),
289                (3u8, 4u8),
290                (10u8, 15u8),
291                (17u8, 18u8),
292                (20u8, 20u8)
293            ]
294        );
295
296        assert_eq!(
297            ys.iter().intersect_vec(&xs).collect::<Vec<_>>(),
298            vec![
299                (1u8, 1u8),
300                (3u8, 4u8),
301                (10u8, 15u8),
302                (17u8, 18u8),
303                (20u8, 20u8)
304            ]
305        );
306
307        assert_eq!(
308            intersect_vec(
309                &crate::normalize_vec(xs[..0].to_vec()),
310                &crate::normalize_vec(vec![])
311            )
312            .into_vec(),
313            vec![]
314        );
315
316        {
317            let empty = crate::normalize_vec(xs[..0].to_vec());
318
319            assert_eq!(
320                unsafe { intersect(empty.iter(), &[]) }
321                    .collect_range_vec()
322                    .into_vec(),
323                vec![]
324            );
325        }
326
327        assert_eq!(
328            intersect_vec(
329                &crate::normalize_vec(xs[1..2].to_vec()),
330                &crate::normalize_vec(vec![(0u8, 0u8)])
331            )
332            .into_vec(),
333            vec![]
334        );
335    }
336
337    proptest::proptest! {
338        #[test]
339        fn test_intersection(xs: Vec<(u8, u8)>, ys: Vec<(u8, u8)>)
340        {
341            use crate::ranges_to_bits;
342
343            let bits = {
344                let x_bits = ranges_to_bits(&xs);
345                let y_bits = ranges_to_bits(&ys);
346
347                x_bits.into_iter().zip(y_bits.into_iter()).map(|(x, y)| x & y).collect::<Vec<bool>>()
348            };
349
350            {
351                let out = intersect_vec(&RangeVec::from_vec(xs.clone()),
352                                        &RangeVec::from_vec(ys.clone()));
353                assert_eq!(&bits, &ranges_to_bits(&out));
354            }
355
356            {
357                let out = RangeVec::from_vec(ys.clone()).intersect(&RangeVec::from_vec(xs.clone()));
358                assert_eq!(&bits, &ranges_to_bits(&out));
359            }
360
361            {
362                let out = RangeVec::from_vec(xs.clone()).into_iter().intersect_vec(&RangeVec::from_vec(ys.clone())).collect_range_vec();
363                assert_eq!(&bits, &ranges_to_bits(&out));
364            }
365
366            {
367                let out = RangeVec::from_vec(ys.clone()).into_iter().intersect_vec(&RangeVec::from_vec(xs.clone())).collect_range_vec();
368                assert_eq!(&bits, &ranges_to_bits(&out));
369            }
370        }
371
372        #[test]
373        fn test_intersection_identity(xs: Vec<(u8, u8)>, ys: Vec<(u8, u8)>)
374        {
375            // Increase interesting coverage with valid ranges
376            let xs = RangeVec::from_vec(xs.into_iter().map(|(a, b)| (a.min(b), a.max(b))).collect::<Vec<_>>());
377            let ys = RangeVec::from_vec(ys.into_iter().map(|(a, b)| (a.min(b), a.max(b))).collect::<Vec<_>>());
378
379            //  (X & Y) = -(-x | -y),
380            // or
381            // -(X & Y) =  (-x | -y).
382
383            // Try that with iterators.
384            {
385                let not_and = xs.iter().intersect_vec(&ys).complement().collect_range_vec();
386                let or_not = crate::union_vec(xs.iter().complement().collect_range_vec(),
387                                              ys.iter().complement());
388
389                assert_eq!(not_and, or_not);
390            }
391
392            {
393                let and = xs.iter().intersect_vec(&ys).collect_range_vec();
394                let not_or_not = crate::union_vec(xs.iter().complement().collect_range_vec(),
395                                                  ys.iter().complement()).iter().complement().collect_range_vec();
396
397                assert_eq!(and, not_or_not);
398            }
399
400            // Now work with RangeVec as much as possible.
401            {
402                let not_and = intersect_vec(&xs, &ys).into_complement();
403                let or_not = crate::union_vec(xs.clone().into_complement(),
404                                              ys.clone().into_complement());
405
406                assert_eq!(not_and, or_not);
407            }
408
409            {
410                let not_and = intersect_vec(&xs, &ys).into_complement();
411                let or_not = xs.clone().into_complement().union(
412                    ys.clone().into_complement());
413
414                assert_eq!(not_and, or_not);
415            }
416
417            {
418                let and = intersect_vec(&xs, &ys);
419                let not_or_not = xs.clone().into_complement()
420                    .union(ys.clone().into_complement())
421                    .into_complement();
422
423                assert_eq!(and, not_or_not);
424            }
425        }
426    }
427}