range_set_blaze/
rog.rs

1#![cfg(feature = "rog-experimental")]
2#![deprecated(
3    note = "The rog ('range or gap') module is experimental and may be changed or removed in future versions.
4    Changes may not be reflected in the semantic versioning."
5)]
6
7use alloc::collections::btree_map;
8use alloc::vec::Vec;
9use core::ops::{Bound, RangeBounds, RangeInclusive};
10
11use crate::{Integer, RangeSetBlaze};
12
13/// Experimental: An iterator over [`Rog`]s (ranges or gaps) in a [`RangeSetBlaze`].
14///
15/// See [`RangeSetBlaze::rogs_range`] for more information.
16pub struct RogsIter<'a, T: Integer> {
17    end_in: T,
18    next_rog: Option<Rog<T>>,
19    final_gap_start: Option<T>,
20    btree_map_iter: btree_map::Range<'a, T, T>,
21}
22
23impl<T: Integer> Iterator for RogsIter<'_, T> {
24    type Item = Rog<T>;
25
26    fn next(&mut self) -> Option<Self::Item> {
27        if let Some(rog) = self.next_rog.take() {
28            return Some(rog);
29        };
30
31        if let Some((start_el, end_el)) = self.btree_map_iter.next() {
32            if self.end_in < *start_el {
33                self.btree_map_iter = btree_map::Range::default();
34            } else {
35                debug_assert!(self.final_gap_start.is_some()); // final_gap_start should be Some if we're in this branch
36                debug_assert!(self.final_gap_start.unwrap() < *start_el); // so -1 is safe
37                let result = Rog::Gap(self.final_gap_start.unwrap()..=*start_el - T::one());
38                if end_el < &self.end_in {
39                    self.next_rog = Some(Rog::Range(*start_el..=*end_el));
40                    debug_assert!(end_el < &self.end_in); // so +1 is safe
41                    self.final_gap_start = Some(*end_el + T::one());
42                } else {
43                    self.next_rog = Some(Rog::Range(*start_el..=self.end_in));
44                    self.final_gap_start = None;
45                }
46                return Some(result);
47            }
48        };
49
50        if let Some(gap_start) = self.final_gap_start.take() {
51            return Some(Rog::Gap(gap_start..=self.end_in));
52        };
53
54        None
55    }
56}
57
58/// Experimental: Represents an range or gap in a [`RangeSetBlaze`].
59///
60/// See [`RangeSetBlaze::rogs_range`] and [`RangeSetBlaze::rogs_get`] for more information.
61///
62/// # Example
63///
64/// ```
65/// use range_set_blaze::{RangeSetBlaze, Rog};
66///
67/// let range_set_blaze = RangeSetBlaze::from([1, 2, 3]);
68/// assert_eq!(range_set_blaze.rogs_get(2), Rog::Range(1..=3));
69/// assert_eq!(range_set_blaze.rogs_get(4), Rog::Gap(4..=2_147_483_647));
70/// ```
71
72#[derive(Debug, PartialEq)]
73pub enum Rog<T: Integer> {
74    /// A range of integers in a [`RangeSetBlaze`].
75    Range(RangeInclusive<T>),
76    /// A gap between integers in a [`RangeSetBlaze`].
77    Gap(RangeInclusive<T>),
78}
79
80impl<T: Integer> Rog<T> {
81    /// Returns the start of a [`Rog`] (range or gap).
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// use range_set_blaze::Rog;
87    /// assert_eq!(Rog::Gap(1..=3).start(), 1);
88    /// ```
89    pub fn start(&self) -> T {
90        match self {
91            Rog::Range(r) => *r.start(),
92            Rog::Gap(r) => *r.start(),
93        }
94    }
95
96    /// Returns the inclusive end of a [`Rog`] (range or gap).
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use range_set_blaze::Rog;
102    /// assert_eq!(Rog::Gap(1..=3).end(), 3);
103    /// ```
104    pub fn end(&self) -> T {
105        match self {
106            Rog::Range(r) => *r.end(),
107            Rog::Gap(r) => *r.end(),
108        }
109    }
110
111    /// Returns `true` if the [`Rog`] (range or gap) contains the given integer.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use range_set_blaze::Rog;
117    /// assert!(Rog::Gap(1..=3).contains(2));
118    /// assert!(!Rog::Gap(1..=3).contains(4));
119    /// ```
120    pub fn contains(&self, value: T) -> bool {
121        match self {
122            Rog::Range(r) => r.contains(&value),
123            Rog::Gap(r) => r.contains(&value),
124        }
125    }
126}
127
128impl<T: Integer> RangeSetBlaze<T> {
129    /// Experimental: Returns the [`Rog`] (range or gap) containing the given integer. If the
130    /// [`RangeSetBlaze`] contains the integer, returns a [`Rog::Range`]. If the
131    /// [`RangeSetBlaze`] does not contain the integer, returns a [`Rog::Gap`].
132    ///
133    /// # Panics
134    ///
135    /// Panics if the `value > T::safe_max_value()`.
136    ///
137    /// # Enabling
138    ///
139    /// This method is experimental and must be enabled with the `rog-experimental` feature.
140    /// ```bash
141    /// cargo add range-set-blaze --features "rog-experimental"
142    /// ```
143    ///
144    /// # Examples
145    ///
146    /// ```
147    /// use range_set_blaze::{RangeSetBlaze, Rog};
148    ///
149    /// let range_set_blaze = RangeSetBlaze::from([1, 2, 3]);
150    /// assert_eq!(range_set_blaze.rogs_get(2), Rog::Range(1..=3));
151    /// assert_eq!(range_set_blaze.rogs_get(4), Rog::Gap(4..=2_147_483_647));
152    /// ```
153    pub fn rogs_get(&self, value: T) -> Rog<T> {
154        assert!(
155            value <= T::safe_max_value(),
156            "value must be <= T::safe_max_value()"
157        );
158        let mut before = self.btree_map.range(..=value).rev();
159        if let Some((start_before, end_before)) = before.next() {
160            if end_before < &value {
161                // case 1: range doesn't touch the before range
162                let start_out = *end_before + T::one();
163                if let Some((start_next, _)) = self.btree_map.range(value..).next() {
164                    debug_assert!(start_before < start_next); // so -1 is safe
165                    Rog::Gap(start_out..=*start_next - T::one())
166                } else {
167                    Rog::Gap(start_out..=T::safe_max_value())
168                }
169            } else {
170                // case 2&3: the range touches the before range
171                Rog::Range(*start_before..=*end_before)
172            }
173        } else {
174            // case 4: there is no before range
175            if let Some((start_next, _)) = self.btree_map.range(value..).next() {
176                debug_assert!(value < *start_next); // so -1 is safe
177                Rog::Gap(T::min_value()..=*start_next - T::one())
178            } else {
179                Rog::Gap(T::min_value()..=T::safe_max_value())
180            }
181        }
182    }
183
184    /// Experimental: Constructs an iterator over a sub-range of [`Rog`]'s (ranges and gaps) in the [`RangeSetBlaze`].
185    /// The simplest way is to use the range syntax `min..=max`, thus `range(min..=max)` will
186    /// yield elements from min (inclusive) to max (inclusive).
187    /// The range may also be entered as `(Bound<T>, Bound<T>)`, so for example
188    /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive
189    /// range from 4 to 10.
190    ///
191    /// # Panics
192    ///
193    /// Panics if range `start > end`.
194    ///
195    /// Panics if range `start == end` and both bounds are `Excluded`.
196    ///
197    /// Panics if range `end > T::safe_max_value()`.
198    ///
199    /// # Enabling
200    ///
201    /// This method is experimental and must be enabled with the `rog-experimental` feature.
202    /// ```bash
203    /// cargo add range-set-blaze --features "rog-experimental"
204    /// ```
205
206    ///
207    /// # Examples
208    ///
209    /// ```rangesetblaze::new()//
210    /// use range_set_blaze::{RangeSetBlaze, Rog;};
211    /// use core::ops::Bound::Included;
212    ///
213    /// let mut set = RangeSetBlaze::new();
214    /// set.insert(3);
215    /// set.insert(5);
216    /// set.insert(6);
217    /// for rog in set.rogs_range((Included(4), Included(8))) {
218    ///     println!("{rog:?}");
219    /// } // prints: Gap(4..=4)\nRange(5..=6)\nGap(7..=8)
220    ///
221    /// assert_eq!(Some(Rog::Gap(4..=4)), set.rogs_range(4..).next());
222    ///
223    /// let a = RangeSetBlaze::from_iter([1..=6, 11..=15]);
224    /// assert_eq!(
225    ///     a.rogs_range(-5..=8).collect::<Vec<_>>(),
226    ///     vec![Rog::Gap(-5..=0), Rog::Range(1..=6), Rog::Gap(7..=8)]
227    /// );
228    ///
229    /// let empty = RangeSetBlaze::<u8>::new();
230    /// assert_eq!(
231    ///     empty.rogs_range(..).collect::<Vec<_>>(),
232    ///     vec![Rog::Gap(0..=255)]
233    /// );
234    /// ```
235    pub fn rogs_range<R>(&self, range: R) -> RogsIter<T>
236    where
237        R: RangeBounds<T>,
238    {
239        let (start_in, end_in) = extract_range(range);
240
241        let mut before = self.btree_map.range(..=start_in).rev();
242        if let Some((_, end_before)) = before.next() {
243            if end_before < &start_in {
244                // case 1: range doesn't touch the before range
245                RogsIter {
246                    end_in,
247                    next_rog: None,
248                    final_gap_start: Some(start_in),
249                    btree_map_iter: self.btree_map.range(start_in..),
250                }
251            } else if end_before < &end_in {
252                // case 2: the range touches and extends beyond the before range
253                debug_assert!(*end_before < end_in); // so +1 is safe
254                debug_assert!(start_in <= *end_before); // so +1 is safe
255                RogsIter {
256                    end_in,
257                    next_rog: Some(Rog::Range(start_in..=*end_before)),
258                    final_gap_start: Some(*end_before + T::one()),
259                    btree_map_iter: self.btree_map.range(start_in + T::one()..),
260                }
261            } else {
262                // case 3 the range is completely contained in the before range
263                RogsIter {
264                    end_in,
265                    next_rog: Some(Rog::Range(start_in..=end_in)),
266                    final_gap_start: None,
267                    btree_map_iter: btree_map::Range::default(),
268                }
269            }
270        } else {
271            // case 4: there is no before range
272            RogsIter {
273                end_in,
274                next_rog: None,
275                final_gap_start: Some(start_in),
276                btree_map_iter: self.btree_map.range(start_in..),
277            }
278        }
279    }
280
281    /// Used internally to test `rogs_range`.
282    #[doc(hidden)]
283    pub fn _rogs_range_slow<R>(&self, range: R) -> Vec<Rog<T>>
284    where
285        R: RangeBounds<T>,
286    {
287        let (start_in, end_in) = extract_range(range);
288        let rsb_in = RangeSetBlaze::from_iter([start_in..=end_in]);
289        let ranges = &rsb_in & self;
290        let gaps = rsb_in - self;
291        let ranges = ranges.ranges().map(|r| Rog::Range(r));
292        let gaps = gaps.ranges().map(|r| Rog::Gap(r));
293        let mut result = ranges.chain(gaps).collect::<Vec<Rog<T>>>();
294        result.sort_by_key(|a| a.start());
295        result
296    }
297
298    /// Used internally to test `rogs_get`.
299    #[doc(hidden)]
300    pub fn rogs_get_slow(&self, value: T) -> Rog<T> {
301        assert!(
302            value <= T::safe_max_value(),
303            "value must be <= T::safe_max_value()"
304        );
305        let all_rogs = self._rogs_range_slow(..);
306        for rog in all_rogs {
307            if rog.contains(value) {
308                return rog;
309            }
310        }
311        unreachable!("value must be in something");
312    }
313}
314
315fn extract_range<T: Integer, R>(range: R) -> (T, T)
316where
317    R: RangeBounds<T>,
318{
319    let start = match range.start_bound() {
320        Bound::Included(n) => *n,
321        Bound::Excluded(n) => {
322            assert!(
323                *n < T::safe_max_value(),
324                "inclusive start must be <= T::max_safe_value()"
325            );
326            *n + T::one()
327        }
328        Bound::Unbounded => T::min_value(),
329    };
330    let end = match range.end_bound() {
331        Bound::Included(n) => *n,
332        Bound::Excluded(n) => {
333            assert!(
334                *n > T::min_value(),
335                "inclusive end must be >= T::min_value()"
336            );
337            *n - T::one()
338        }
339        Bound::Unbounded => T::safe_max_value(),
340    };
341    assert!(start <= end, "start must be <= end");
342    assert!(
343        end <= T::safe_max_value(),
344        "end must be <= T::safe_max_value()"
345    );
346
347    (start, end)
348}