range_set_blaze/
rog.rs

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