closed_interval_set/
complement.rs

1use crate::Backing;
2use crate::ClosedRange;
3use crate::ClosedRangeEnd;
4use crate::ClosedRangeVal;
5use crate::Endpoint;
6use crate::NormalizedRangeIter;
7use crate::RangeCase;
8use crate::RangeVec;
9
10// Not an actual rust generator, but one day...
11#[repr(transparent)]
12struct ComplementGenerator<T: Endpoint> {
13    next_start: T,
14}
15
16impl<T: Endpoint> ComplementGenerator<T> {
17    #[inline(always)]
18    fn new() -> Self {
19        Self {
20            next_start: T::min_value(),
21        }
22    }
23
24    #[inline(always)]
25    fn next(self, range: (T, T)) -> (Option<Self>, Option<(T, T)>) {
26        let next_start = self.next_start;
27        let (start, stop) = range;
28        // next_start <= start <= stop
29        //     |           [        ]
30        //     ^.........^
31        //     [         ]
32        //     gap interval
33        // Generate the next item if we can find a gap between `next_start` and `start`
34        let gap = start
35            .decrease_toward(next_start)
36            .map(|prev| (next_start, prev));
37
38        let next_self = stop.next_after().map(|next_start| Self { next_start });
39
40        (next_self, gap)
41    }
42
43    #[inline(always)]
44    fn end(self) -> (T, T) {
45        (self.next_start, T::max_value())
46    }
47}
48
49pub struct ComplementIterator<Ranges>
50where
51    // No need to keep this fused: we reset `state = None` when the iterator stops.
52    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>,
53{
54    state: Option<(
55        ComplementGenerator<ClosedRangeEnd<<Ranges as Iterator>::Item>>,
56        Ranges,
57    )>,
58}
59
60impl<Ranges> ComplementIterator<Ranges>
61where
62    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>,
63{
64    #[inline(always)]
65    pub fn new(ranges: Ranges) -> Self {
66        Self {
67            state: Some((ComplementGenerator::new(), ranges)),
68        }
69    }
70}
71
72impl<Ranges> Iterator for ComplementIterator<Ranges>
73where
74    Ranges: Sized + NormalizedRangeIter + Iterator<Item: ClosedRange>,
75{
76    type Item = ClosedRangeVal<<Ranges as Iterator>::Item>;
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)]
189#[must_use]
190pub fn complement_vec<T: Endpoint>(intervals: impl Into<RangeCase<T>>) -> RangeVec<T> {
191    crate::normalize_vec(intervals).into_complement()
192}
193
194impl<T: Endpoint> RangeVec<T> {
195    /// Constructs the complement of [`RangeVec`] in a fresh vector.
196    ///
197    /// This operation takes linear time and allocates the result at
198    /// most in linear space.
199    #[inline(always)]
200    #[must_use]
201    pub fn complement(&self) -> RangeVec<T> {
202        self.iter().complement().collect_range_vec()
203    }
204
205    /// Complements this [`RangeVec`] in place.
206    ///
207    /// This operation is in place and takes linear time.
208    #[inline(always)]
209    #[must_use]
210    pub fn into_complement(self) -> RangeVec<T> {
211        #[cfg(feature = "internal_checks")]
212        let expected = self.complement();
213
214        let ret = complement_impl(self.into_inner());
215        #[cfg(feature = "internal_checks")]
216        assert!(&expected.eqv(&ret));
217
218        ret
219    }
220}
221
222#[cfg(test)]
223#[cfg_attr(coverage_nightly, coverage(off))]
224mod test {
225    use super::*;
226    use alloc::vec;
227    use alloc::vec::Vec;
228    use smallvec::smallvec;
229
230    #[test]
231    fn test_complement_smoke() {
232        use crate::normalize_vec;
233        use crate::IntoNormalizedRangeIter;
234
235        fn complement(
236            x: impl IntoNormalizedRangeIter<Item = (u8, u8)>,
237        ) -> impl NormalizedRangeIter<Item = (u8, u8)> {
238            x.into_iter().complement()
239        }
240
241        let empty: &[(u8, u8)] = &[];
242        assert_eq!(
243            complement_vec(empty.to_vec()).into_vec(),
244            vec![(0u8, 255u8)]
245        );
246        assert_eq!(
247            normalize_vec(empty.to_vec()).into_complement().into_vec(),
248            vec![(0u8, 255u8)]
249        );
250
251        assert_eq!(
252            normalize_vec(empty.to_vec()).complement().into_vec(),
253            vec![(0u8, 255u8)]
254        );
255
256        {
257            let mut universe = normalize_vec(empty.to_vec()).into_iter().complement();
258
259            assert_eq!(universe.next(), Some((0u8, 255u8)));
260            assert_eq!(universe.next(), None); // Then we keep being done.
261            assert_eq!(universe.next(), None);
262        }
263
264        {
265            let (min, max) = complement(normalize_vec(empty.to_vec())).size_hint();
266
267            assert!(min <= 1);
268            assert!(max.expect("should have max") >= 1);
269        }
270
271        {
272            let (min, max) = complement(normalize_vec(vec![(1u8, 10u8), (11u8, 11u8)])).size_hint();
273
274            assert!(min <= 2);
275            assert!(max.expect("should have max") >= 2);
276        }
277
278        let smallvec: smallvec::SmallVec<[_; crate::INLINE_SIZE]> =
279            smallvec![(1u8, 10u8), (11u8, 11u8)];
280        assert_eq!(
281            complement_vec(smallvec).into_vec(),
282            vec![(0u8, 0u8), (12u8, 255u8)]
283        );
284        assert_eq!(
285            complement(&normalize_vec(vec![(1u8, 10u8), (11u8, 11u8)]))
286                .collect_range_vec()
287                .into_vec(),
288            vec![(0u8, 0u8), (12u8, 255u8)]
289        );
290
291        let largervec: smallvec::SmallVec<[_; crate::INLINE_SIZE + 1]> = smallvec![(1u8, 255u8)];
292        assert_eq!(complement_vec(largervec).into_vec(), vec![(0u8, 0u8)]);
293
294        let smallervec: smallvec::SmallVec<[_; crate::INLINE_SIZE.saturating_sub(1)]> =
295            smallvec![(1u8, 255u8)];
296        assert_eq!(
297            complement(&normalize_vec(smallervec))
298                .collect_range_vec()
299                .into_vec(),
300            vec![(0u8, 0u8)]
301        );
302
303        assert_eq!(
304            complement_vec(vec![(1u8, 254u8)]).into_vec(),
305            vec![(0u8, 0u8), (255u8, 255u8)]
306        );
307        assert_eq!(
308            complement(&normalize_vec(vec![(1u8, 254u8)]))
309                .collect_range_vec()
310                .into_vec(),
311            vec![(0u8, 0u8), (255u8, 255u8)]
312        );
313        assert_eq!(
314            complement(normalize_vec(vec![(1u8, 254u8)]))
315                .collect_range_vec()
316                .into_vec(),
317            vec![(0u8, 0u8), (255u8, 255u8)]
318        );
319
320        assert_eq!(complement_vec(vec![(0u8, 255u8)]).into_vec(), vec![]);
321        assert_eq!(
322            complement(normalize_vec(vec![(0u8, 255u8)]))
323                .collect_range_vec()
324                .into_vec(),
325            vec![]
326        );
327
328        assert_eq!(
329            complement_vec(vec![(0u8, 254u8)]).into_vec(),
330            vec![(255u8, 255u8)]
331        );
332        assert_eq!(
333            complement(normalize_vec(vec![(0u8, 254u8)])).collect::<Vec<_>>(),
334            vec![(255u8, 255u8)]
335        );
336
337        assert_eq!(
338            complement(&normalize_vec(vec![(0u8, 254u8)]))
339                .collect_range_vec()
340                .into_vec(),
341            vec![(255u8, 255u8)]
342        );
343    }
344
345    proptest::proptest! {
346        #[test]
347        fn test_increase(ranges: Vec<(u8, u8)>) {
348            use crate::ranges_to_bits;
349
350            let marks = ranges_to_bits(&ranges).into_iter().map(|x| !x).collect::<Vec<bool>>();
351
352            assert_eq!(&ranges_to_bits(&complement_vec(ranges.clone())), &marks);
353
354            let ranges = RangeVec::from_vec(ranges);
355            assert_eq!(&ranges_to_bits(&complement_vec(ranges.clone())), &marks);
356
357            assert_eq!(&ranges_to_bits(&ranges.clone().complement()), &marks);
358            assert_eq!(&ranges_to_bits(&ranges.clone().into_complement()), &marks);
359
360            assert_eq!(&ranges_to_bits(&ranges.iter().complement().collect_range_vec()), &marks);
361        }
362
363        #[test]
364        fn test_self_inverse_f32(ranges: Vec<(f32, f32)>) {
365            let ranges = RangeVec::from_vec(ranges);
366            let complement = ranges.complement();
367            let double_complement = complement.into_complement();
368
369            assert_eq!(ranges, double_complement);
370        }
371
372        #[test]
373        fn test_self_inverse_f64(ranges: Vec<(f64, f64)>) {
374            let ranges = RangeVec::from_vec(ranges);
375            let complement = ranges.complement();
376            let double_complement = complement.into_complement();
377
378            assert_eq!(ranges, double_complement);
379        }
380    }
381}