closed_interval_set/
complement.rs

1use crate::Backing;
2use crate::ClosedRange;
3use crate::Endpoint;
4use crate::NormalizedRangeIter;
5use crate::RangeCase;
6use crate::RangeVec;
7
8// Not an actual rust generator, but one day...
9#[repr(transparent)]
10struct ComplementGenerator<T: Endpoint> {
11    next_start: T,
12}
13
14impl<T: Endpoint> ComplementGenerator<T> {
15    #[inline(always)]
16    fn new() -> Self {
17        Self {
18            next_start: T::min_value(),
19        }
20    }
21
22    #[inline(always)]
23    fn next(self, range: (T, T)) -> (Option<Self>, Option<(T, T)>) {
24        let next_start = self.next_start;
25        let (start, stop) = range;
26        // next_start <= start <= stop
27        //     |           [        ]
28        //     ^.........^
29        //     [         ]
30        //     gap interval
31        // Generate the next item if we can find a gap between `next_start` and `start`
32        let gap = start
33            .decrease_toward(next_start)
34            .map(|prev| (next_start, prev));
35
36        let next_self = stop.next_after().map(|next_start| Self { next_start });
37
38        (next_self, gap)
39    }
40
41    #[inline(always)]
42    fn end(self) -> (T, T) {
43        (self.next_start, T::max_value())
44    }
45}
46
47pub struct ComplementIterator<Ranges>
48where
49    // No need to keep this fused: we reset `state = None` when the iterator stops.
50    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>,
51{
52    state: Option<(
53        ComplementGenerator<<<Ranges as Iterator>::Item as ClosedRange>::EndT>,
54        Ranges,
55    )>,
56}
57
58impl<Ranges> ComplementIterator<Ranges>
59where
60    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>,
61{
62    #[inline(always)]
63    pub fn new(ranges: Ranges) -> Self {
64        Self {
65            state: Some((ComplementGenerator::new(), ranges)),
66        }
67    }
68}
69
70type Pair<T> = (T, T);
71
72impl<Ranges> Iterator for ComplementIterator<Ranges>
73where
74    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>,
75{
76    type Item = Pair<<<Ranges as Iterator>::Item as ClosedRange>::EndT>;
77
78    fn next(&mut self) -> Option<Self::Item> {
79        loop {
80            let (self_cg, ranges) = self.state.as_mut()?;
81            let mut cg = ComplementGenerator::new();
82            core::mem::swap(&mut cg, self_cg);
83
84            let Some(range) = ranges.next() else {
85                self.state = None;
86                return Some(cg.end());
87            };
88
89            let (cg, ret) = cg.next(range.get());
90            match cg {
91                None => {
92                    self.state = None;
93                    return ret;
94                }
95                Some(cg) => {
96                    *self_cg = cg;
97                }
98            }
99
100            if ret.is_some() {
101                return ret;
102            }
103        }
104    }
105
106    #[inline]
107    fn size_hint(&self) -> (usize, Option<usize>) {
108        let (min, max) = match self.state.as_ref() {
109            Some((_, ranges)) => ranges.size_hint(),
110            None => (0, None),
111        };
112
113        // we know there is one gap between each entry in ranges, so
114        // so we'll generate at least n - 1 gaps.
115        //
116        // In the worst case, we can also add two gaps on both ends.
117        (min.saturating_sub(1), max.map(|max| max.saturating_add(2)))
118    }
119}
120
121impl<Ranges> crate::private::Sealed for ComplementIterator<Ranges> where
122    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>
123{
124}
125
126impl<Ranges> NormalizedRangeIter for ComplementIterator<Ranges> where
127    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>
128{
129}
130
131// We explicitly clear our state when get to the end, so we reliably
132// keep returning `None`.
133impl<Ranges> core::iter::FusedIterator for ComplementIterator<Ranges> where
134    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>
135{
136}
137
138#[inline(never)]
139fn complement_impl<T: Endpoint>(normalized_intervals: Backing<T>) -> RangeVec<T> {
140    // safe to compare ranges because they're normalized.
141    use core::cmp::Ordering;
142
143    let mut intervals = normalized_intervals;
144    let mut prefix_len = 0;
145
146    'out: {
147        let mut cg = ComplementGenerator::new();
148
149        for i in 0..intervals.len() {
150            assert!(prefix_len <= i);
151            let (start, stop) = intervals[i];
152
153            // The input is normalized, so intervals are valid.
154            debug_assert!(start.cmp_end(stop) <= Ordering::Equal);
155
156            let (next_cg, gap) = cg.next(intervals[i]);
157            if let Some(gap) = gap {
158                intervals[prefix_len] = gap;
159                prefix_len += 1;
160            }
161
162            match next_cg {
163                Some(next_cg) => cg = next_cg,
164                None => {
165                    intervals.truncate(prefix_len);
166                    break 'out;
167                }
168            }
169        }
170
171        let final_interval = cg.end();
172        if prefix_len < intervals.len() {
173            intervals[prefix_len] = final_interval;
174            intervals.truncate(prefix_len + 1);
175        } else {
176            intervals.push(final_interval);
177        }
178    }
179
180    unsafe { RangeVec::new_unchecked(intervals) }
181}
182
183/// Returns the complement of a vector of closed `intervals`.
184///
185/// This operation is in-place and takes time linear in the input if
186/// it is already normalized, and \\(\mathcal{O}(n \log n)\\) time
187/// otherwise.
188#[inline(always)]
189pub fn complement_vec<T: Endpoint>(intervals: impl Into<RangeCase<T>>) -> RangeVec<T> {
190    crate::normalize_vec(intervals).into_complement()
191}
192
193impl<T: Endpoint> RangeVec<T> {
194    /// Constructs the complement of [`RangeVec`] in a fresh vector.
195    ///
196    /// This operation takes linear time and allocates the result at
197    /// most in linear space.
198    #[inline(always)]
199    pub fn complement(&self) -> RangeVec<T> {
200        self.iter().complement().collect_range_vec()
201    }
202
203    /// Complements this [`RangeVec`] in place.
204    ///
205    /// This operation is in place and takes linear time.
206    #[inline(always)]
207    pub fn into_complement(self) -> RangeVec<T> {
208        #[cfg(feature = "internal_checks")]
209        let expected = self.complement();
210
211        let ret = complement_impl(self.into_inner());
212        #[cfg(feature = "internal_checks")]
213        assert!(&expected.eqv(&ret));
214
215        ret
216    }
217}
218
219#[cfg(test)]
220#[cfg_attr(coverage_nightly, coverage(off))]
221mod test {
222    use super::*;
223    use alloc::vec;
224    use alloc::vec::Vec;
225    use smallvec::smallvec;
226
227    #[test]
228    fn test_complement_smoke() {
229        use crate::normalize_vec;
230        use crate::IntoNormalizedRangeIter;
231
232        fn complement(
233            x: impl IntoNormalizedRangeIter<Item = (u8, u8)>,
234        ) -> impl NormalizedRangeIter<Item = (u8, u8)> {
235            x.into_iter().complement()
236        }
237
238        let empty: &[(u8, u8)] = &[];
239        assert_eq!(
240            complement_vec(empty.to_vec()).into_vec(),
241            vec![(0u8, 255u8)]
242        );
243        assert_eq!(
244            normalize_vec(empty.to_vec()).into_complement().into_vec(),
245            vec![(0u8, 255u8)]
246        );
247
248        assert_eq!(
249            normalize_vec(empty.to_vec()).complement().into_vec(),
250            vec![(0u8, 255u8)]
251        );
252
253        {
254            let mut universe = normalize_vec(empty.to_vec()).into_iter().complement();
255
256            assert_eq!(universe.next(), Some((0u8, 255u8)));
257            assert_eq!(universe.next(), None); // Then we keep being done.
258            assert_eq!(universe.next(), None);
259        }
260
261        {
262            let (min, max) = complement(normalize_vec(empty.to_vec())).size_hint();
263
264            assert!(min <= 1);
265            assert!(max.expect("should have max") >= 1);
266        }
267
268        {
269            let (min, max) = complement(normalize_vec(vec![(1u8, 10u8), (11u8, 11u8)])).size_hint();
270
271            assert!(min <= 2);
272            assert!(max.expect("should have max") >= 2);
273        }
274
275        let smallvec: smallvec::SmallVec<[_; crate::INLINE_SIZE]> =
276            smallvec![(1u8, 10u8), (11u8, 11u8)];
277        assert_eq!(
278            complement_vec(smallvec).into_vec(),
279            vec![(0u8, 0u8), (12u8, 255u8)]
280        );
281        assert_eq!(
282            complement(&normalize_vec(vec![(1u8, 10u8), (11u8, 11u8)]))
283                .collect_range_vec()
284                .into_vec(),
285            vec![(0u8, 0u8), (12u8, 255u8)]
286        );
287
288        let largervec: smallvec::SmallVec<[_; crate::INLINE_SIZE + 1]> = smallvec![(1u8, 255u8)];
289        assert_eq!(complement_vec(largervec).into_vec(), vec![(0u8, 0u8)]);
290
291        let smallervec: smallvec::SmallVec<[_; crate::INLINE_SIZE.saturating_sub(1)]> =
292            smallvec![(1u8, 255u8)];
293        assert_eq!(
294            complement(&normalize_vec(smallervec))
295                .collect_range_vec()
296                .into_vec(),
297            vec![(0u8, 0u8)]
298        );
299
300        assert_eq!(
301            complement_vec(vec![(1u8, 254u8)]).into_vec(),
302            vec![(0u8, 0u8), (255u8, 255u8)]
303        );
304        assert_eq!(
305            complement(&normalize_vec(vec![(1u8, 254u8)]))
306                .collect_range_vec()
307                .into_vec(),
308            vec![(0u8, 0u8), (255u8, 255u8)]
309        );
310        assert_eq!(
311            complement(normalize_vec(vec![(1u8, 254u8)]))
312                .collect_range_vec()
313                .into_vec(),
314            vec![(0u8, 0u8), (255u8, 255u8)]
315        );
316
317        assert_eq!(complement_vec(vec![(0u8, 255u8)]).into_vec(), vec![]);
318        assert_eq!(
319            complement(normalize_vec(vec![(0u8, 255u8)]))
320                .collect_range_vec()
321                .into_vec(),
322            vec![]
323        );
324
325        assert_eq!(
326            complement_vec(vec![(0u8, 254u8)]).into_vec(),
327            vec![(255u8, 255u8)]
328        );
329        assert_eq!(
330            complement(normalize_vec(vec![(0u8, 254u8)])).collect::<Vec<_>>(),
331            vec![(255u8, 255u8)]
332        );
333
334        assert_eq!(
335            complement(&normalize_vec(vec![(0u8, 254u8)]))
336                .collect_range_vec()
337                .into_vec(),
338            vec![(255u8, 255u8)]
339        );
340    }
341
342    proptest::proptest! {
343        #[test]
344        fn test_increase(ranges: Vec<(u8, u8)>) {
345            use crate::ranges_to_bits;
346
347            let marks = ranges_to_bits(&ranges).into_iter().map(|x| !x).collect::<Vec<bool>>();
348
349            assert_eq!(&ranges_to_bits(&complement_vec(ranges.clone())), &marks);
350
351            let ranges = RangeVec::from_vec(ranges);
352            assert_eq!(&ranges_to_bits(&complement_vec(ranges.clone())), &marks);
353
354            assert_eq!(&ranges_to_bits(&ranges.clone().complement()), &marks);
355            assert_eq!(&ranges_to_bits(&ranges.clone().into_complement()), &marks);
356
357            assert_eq!(&ranges_to_bits(&ranges.iter().complement().collect_range_vec()), &marks);
358        }
359
360        #[test]
361        fn test_self_inverse_f32(ranges: Vec<(f32, f32)>) {
362            let ranges = RangeVec::from_vec(ranges);
363            let complement = ranges.complement();
364            let double_complement = complement.into_complement();
365
366            assert_eq!(ranges, double_complement);
367        }
368
369        #[test]
370        fn test_self_inverse_f64(ranges: Vec<(f64, f64)>) {
371            let ranges = RangeVec::from_vec(ranges);
372            let complement = ranges.complement();
373            let double_complement = complement.into_complement();
374
375            assert_eq!(ranges, double_complement);
376        }
377    }
378}