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}