range_set_blaze/gaps.rs
1//! # Ranges and gaps
2//!
3//! [`RangeSetBlaze`][crate::RangeSetBlaze] and [`RangeMapBlaze`][crate::RangeMapBlaze] store integers as a sorted list
4//! of ranges instead of individual integers, and they always merge
5//! neighboring or overlapping ranges as you insert. So a `RangeSetBlaze`
6//! built from `1..=3` and `7..=10` holds exactly those two ranges — no more,
7//! no fewer. Everything else — `4..=6`, and everything below `1` or above
8//! `10` — is a gap: a run of integers not covered by any range.
9//!
10//! # Table of Contents
11//! * [`RangeSetBlaze`](#rangesetblaze)
12//! * [`range_at`: only present ranges](#range_at-only-present-ranges)
13//! * [`range_or_gap_at`: present range or gap](#range_or_gap_at-present-range-or-gap)
14//! * [`fill_gaps`: fill gaps with `false`](#fill_gaps-fill-gaps-with-false)
15//! * [Streaming `fill_gaps` for `RangeSetBlaze`](#streaming-fill_gaps-for-rangesetblaze)
16//! * [`RangeMapBlaze`](#rangemapblaze)
17//! * [`range_at`: only mapped ranges](#range_at-only-mapped-ranges)
18//! * [`range_or_gap_at`: mapped range or gap](#range_or_gap_at-mapped-range-or-gap)
19//! * [`fill_gaps`: fill gaps with `None`](#fill_gaps-fill-gaps-with-none)
20//! * [Streaming `fill_gaps` for `RangeMapBlaze`](#streaming-fill_gaps-for-rangemapblaze)
21//! * [A filled map has an entry for every integer](#a-filled-map-has-an-entry-for-every-integer)
22//!
23//! ## `RangeSetBlaze`
24//!
25//! ### `range_at`: only present ranges
26//!
27//! Suppose you want to find which range a value belongs to.
28//! [`RangeSetBlaze::range_at`][crate::RangeSetBlaze::range_at] returns the maximal range
29//! containing `value`:
30//!
31//! ```
32//! use range_set_blaze::RangeSetBlaze;
33//!
34//! let set = RangeSetBlaze::from_iter([1_i8..=3, 7..=10]);
35//! assert_eq!(set.range_at(2), Some(1..=3));
36//! ```
37//!
38//! What if the value isn't in any range? `range_at` returns `None`:
39//!
40//! ```
41//! use range_set_blaze::RangeSetBlaze;
42//!
43//! let set = RangeSetBlaze::from_iter([1_i8..=3, 7..=10]);
44//! assert_eq!(set.range_at(5), None); // 5 is in the gap between the two ranges
45//! ```
46//!
47//! ### `range_or_gap_at`: present range or gap
48//!
49//! What if you want the gap itself, instead of `None`?
50//! [`RangeSetBlaze::range_or_gap_at`][crate::RangeSetBlaze::range_or_gap_at] always returns the maximal
51//! range containing `value`, as `(range, bool)` where `true` means present:
52//!
53//! ```
54//! use range_set_blaze::RangeSetBlaze;
55//!
56//! let set = RangeSetBlaze::from_iter([1_i8..=3, 7..=10]);
57//! assert_eq!(set.range_or_gap_at(5), (4..=6, false)); // the gap between the two ranges
58//! ```
59//!
60//! A gap also extends to the domain's own bounds, so a query below the first
61//! range or above the last one returns the leading or trailing gap:
62//!
63//! ```
64//! use range_set_blaze::RangeSetBlaze;
65//!
66//! let set = RangeSetBlaze::from_iter([1_i8..=3, 7..=10]);
67//! assert_eq!(set.range_or_gap_at(i8::MIN), (i8::MIN..=0, false));
68//! assert_eq!(set.range_or_gap_at(i8::MAX), (11..=i8::MAX, false));
69//! ```
70//!
71//! ### `fill_gaps`: fill gaps with `false`
72//!
73//! [`RangeSetBlaze::fill_gaps`][crate::RangeSetBlaze::fill_gaps] builds a new `RangeMapBlaze<T, bool>`
74//! with an entry for every integer, not just the ones in the original set:
75//! `true` for values that were present, `false` for values that were in a
76//! gap.
77//!
78//! ```
79//! use range_set_blaze::{RangeMapBlaze, RangeSetBlaze};
80//!
81//! let set = RangeSetBlaze::from_iter([1_i8..=3, 7..=10]);
82//! let filled_set = set.fill_gaps();
83//! assert_eq!(
84//! filled_set,
85//! RangeMapBlaze::from_iter([
86//! (i8::MIN..=0, false),
87//! (1..=3, true),
88//! (4..=6, false),
89//! (7..=10, true),
90//! (11..=i8::MAX, false),
91//! ])
92//! );
93//! ```
94//!
95//! ### Streaming `fill_gaps` for `RangeSetBlaze`
96//!
97//! If the whole materialized `RangeMapBlaze` is not needed, [`SortedDisjoint::fill_gaps`]
98//! streams the same result lazily from a set stream such as `set.ranges()`,
99//! yielding `(range, bool)` and including the leading and trailing gaps:
100//!
101//! ```
102//! use range_set_blaze::{RangeSetBlaze, SortedDisjoint};
103//!
104//! let set = RangeSetBlaze::from_iter([1_i8..=3, 7..=10]);
105//! let mut set_stream = set.ranges().fill_gaps();
106//! assert_eq!(set_stream.next(), Some((i8::MIN..=0, false)));
107//! assert_eq!(set_stream.next(), Some((1..=3, true)));
108//! assert_eq!(set_stream.next(), Some((4..=6, false)));
109//! assert_eq!(set_stream.next(), Some((7..=10, true)));
110//! assert_eq!(set_stream.next(), Some((11..=i8::MAX, false)));
111//! assert_eq!(set_stream.next(), None);
112//! ```
113//!
114//! ## `RangeMapBlaze`
115//!
116//! ### `range_at`: only mapped ranges
117//!
118//! What if this is a map instead of a set? [`RangeMapBlaze::range_at`][crate::RangeMapBlaze::range_at]
119//! works the same way, returning the maximal range and its value:
120//!
121//! ```
122//! use range_set_blaze::RangeMapBlaze;
123//!
124//! let map = RangeMapBlaze::from_iter([(1_i8..=3, "red"), (7..=10, "blue")]);
125//! assert_eq!(map.range_at(2), Some((1..=3, &"red")));
126//! assert_eq!(map.range_at(5), None); // 5 is in the gap between the two ranges
127//! ```
128//!
129//! ### `range_or_gap_at`: mapped range or gap
130//!
131//! [`RangeMapBlaze::range_or_gap_at`][crate::RangeMapBlaze::range_or_gap_at] is the map counterpart of
132//! `range_or_gap_at` above: it always returns the maximal range containing
133//! `key`, as `(range, Option<&V>)` where `Some` means mapped:
134//!
135//! ```
136//! use range_set_blaze::RangeMapBlaze;
137//!
138//! let map = RangeMapBlaze::from_iter([(1_i8..=3, "red"), (7..=10, "blue")]);
139//! assert_eq!(map.range_or_gap_at(5), (4..=6, None)); // the gap between the two ranges
140//! assert_eq!(map.range_or_gap_at(8), (7..=10, Some(&"blue")));
141//! ```
142//!
143//! ### `fill_gaps`: fill gaps with `None`
144//!
145//! [`RangeMapBlaze::fill_gaps`][crate::RangeMapBlaze::fill_gaps] builds a new
146//! `RangeMapBlaze<T, Option<V>>` with an entry for every integer, not just
147//! the ones in the original map: `Some(value)` for keys that were mapped,
148//! `None` for keys that were in a gap.
149//!
150//! ```
151//! use range_set_blaze::RangeMapBlaze;
152//!
153//! let map = RangeMapBlaze::from_iter([(1_i8..=3, "red"), (7..=10, "blue")]);
154//! let filled_map = map.fill_gaps();
155//! assert_eq!(
156//! filled_map,
157//! RangeMapBlaze::from_iter([
158//! (i8::MIN..=0, None),
159//! (1..=3, Some("red")),
160//! (4..=6, None),
161//! (7..=10, Some("blue")),
162//! (11..=i8::MAX, None),
163//! ])
164//! );
165//! ```
166//!
167//! ### Streaming `fill_gaps` for `RangeMapBlaze`
168//!
169//! If the whole materialized `RangeMapBlaze` is not needed, [`SortedDisjointMap::fill_gaps`]
170//! streams the same result lazily from a map stream such as
171//! `map.range_values()`, yielding `(range, Option<&V>)` and borrowing the
172//! original values instead of cloning them:
173//!
174//! ```
175//! use range_set_blaze::{RangeMapBlaze, SortedDisjointMap};
176//!
177//! let map = RangeMapBlaze::from_iter([(1_i8..=3, "red"), (7..=10, "blue")]);
178//! let mut map_stream = map.range_values().fill_gaps();
179//! assert_eq!(map_stream.next(), Some((i8::MIN..=0, None)));
180//! assert_eq!(map_stream.next(), Some((1..=3, Some(&"red"))));
181//! assert_eq!(map_stream.next(), Some((4..=6, None)));
182//! assert_eq!(map_stream.next(), Some((7..=10, Some(&"blue"))));
183//! assert_eq!(map_stream.next(), Some((11..=i8::MAX, None)));
184//! assert_eq!(map_stream.next(), None);
185//! ```
186//!
187//! ## A filled map has an entry for every integer
188//!
189//! After `fill_gaps`, `false`/`None` are just ordinary values sitting in the
190//! map — the map itself now has a key for every integer, with no gaps left
191//! at all. This matters if you then apply the `!` (complement) operator,
192//! since `!` on a `RangeMapBlaze` means "the keys *not* in this map," not
193//! "flip each `bool`/`Option` value." Because a filled map already has every
194//! key, its complement is always empty — it does **not** flip `true` to
195//! `false`:
196//!
197//! ```
198//! use range_set_blaze::RangeSetBlaze;
199//!
200//! let set = RangeSetBlaze::from_iter([1_i8..=3, 7..=10]);
201//! let filled_set = set.fill_gaps();
202//! assert!((!filled_set).is_empty()); // not the Boolean negation you might expect
203//! ```
204
205use core::{iter::FusedIterator, ops::RangeInclusive};
206
207use crate::{Integer, SortedDisjoint, SortedDisjointMap, map::ValueCarrier};
208
209/// An iterator that fills the gaps in a sorted, disjoint set stream.
210///
211/// Present ranges are returned with `true`, and missing portions of the
212/// integer domain are returned with `false`. The output covers the complete
213/// domain from [`Integer::min_value`] through [`Integer::max_value`].
214/// In other words, this is a total Boolean-valued map stream: `true` means
215/// membership in the input set and `false` means a gap. The `false` values
216/// are ordinary map values, so the resulting map's key domain is universal.
217///
218/// This iterator is created by [`SortedDisjoint::fill_gaps`], typically from a
219/// set stream such as [`RangeSetBlaze::ranges`]. To materialize the result
220/// instead of streaming it, use [`RangeSetBlaze::fill_gaps`].
221///
222/// The iterator implements [`SortedDisjointMap<T, bool>`], so it supports the
223/// sorted-disjoint map operations and can be collected into a
224/// [`RangeMapBlaze<T, bool>`].
225///
226/// Because `true` and `false` are ordinary map values, map operators act on the
227/// stream's key ranges; for example, `!filled` is empty rather than Boolean
228/// negation.
229///
230/// [`SortedDisjointMap<T, bool>`]: crate::SortedDisjointMap
231/// [`RangeMapBlaze<T, bool>`]: crate::RangeMapBlaze
232/// [`RangeSetBlaze::ranges`]: crate::RangeSetBlaze::ranges
233/// [`RangeSetBlaze::fill_gaps`]: crate::RangeSetBlaze::fill_gaps
234///
235/// For the set and map APIs together, see the [Ranges and gaps guide][crate::gaps].
236///
237/// # Example
238///
239/// ```
240/// use range_set_blaze::{
241/// CheckSortedDisjoint, RangeMapBlaze, RangeSetBlaze, SortedDisjoint, SortedDisjointMap,
242/// };
243///
244/// // From the streaming layer directly.
245/// let input = CheckSortedDisjoint::new([1..=3, 7..=10]);
246/// let output = input.fill_gaps().collect::<Vec<_>>();
247/// assert_eq!(output[0], (i32::MIN..=0, false));
248/// assert_eq!(output[1], (1..=3, true));
249/// assert_eq!(output[2], (4..=6, false));
250/// assert_eq!(output[3], (7..=10, true));
251/// assert_eq!(output[4], (11..=i32::MAX, false));
252///
253/// // Or explicitly materialize the streaming result into a map.
254/// let set = RangeSetBlaze::from_iter([1_u8..=3, 7..=10]);
255/// let map: RangeMapBlaze<u8, bool> = set.ranges().fill_gaps().into_range_map_blaze();
256/// assert_eq!(map.get(2), Some(&true));
257/// assert_eq!(map.get(5), Some(&false));
258/// ```
259#[derive(Clone, Debug)]
260#[must_use = "iterators are lazy and do nothing unless consumed"]
261pub struct FillGapsIter<T, I> {
262 iter: I,
263 next_start: T,
264 pending: Option<RangeInclusive<T>>,
265 done: bool,
266}
267
268impl<T, I> FillGapsIter<T, I>
269where
270 T: Integer,
271 I: SortedDisjoint<T>,
272{
273 /// Creates a gap-filling iterator from a sorted, disjoint set stream.
274 pub(crate) fn new(iter: I) -> Self {
275 Self {
276 iter,
277 next_start: T::min_value(),
278 pending: None,
279 done: false,
280 }
281 }
282}
283
284impl<T, I> Iterator for FillGapsIter<T, I>
285where
286 T: Integer,
287 I: SortedDisjoint<T>,
288{
289 type Item = (RangeInclusive<T>, bool);
290
291 fn next(&mut self) -> Option<Self::Item> {
292 if self.done {
293 return None;
294 }
295
296 let Some(range) = self.pending.take().or_else(|| self.iter.next()) else {
297 self.done = true;
298 return Some((self.next_start..=T::max_value(), false));
299 };
300
301 let (start, end) = range.clone().into_inner();
302 debug_assert!(start <= end);
303
304 if self.next_start < start {
305 let gap = self.next_start..=start.sub_one();
306 self.next_start = start;
307 self.pending = Some(range);
308 return Some((gap, false));
309 }
310
311 if end == T::max_value() {
312 self.done = true;
313 } else {
314 self.next_start = end.add_one();
315 }
316 Some((range, true))
317 }
318
319 fn size_hint(&self) -> (usize, Option<usize>) {
320 if self.done {
321 return (0, Some(0));
322 }
323
324 let (low, high) = self.iter.size_hint();
325 let pending = usize::from(self.pending.is_some());
326 let low = low.saturating_add(pending);
327 let high = high.and_then(|high| high.checked_mul(2)?.checked_add(pending)?.checked_add(1));
328 (low, high)
329 }
330}
331
332impl<T, I> FusedIterator for FillGapsIter<T, I>
333where
334 T: Integer,
335 I: SortedDisjoint<T>,
336{
337}
338
339/// An iterator that fills the gaps in a sorted, disjoint map stream.
340///
341/// Mapped ranges are returned with `Some(value)`, and missing portions of the
342/// integer domain are returned with `None`. The output covers the complete
343/// domain from [`Integer::min_value`] through [`Integer::max_value`].
344/// In other words, this is a total map stream from a
345/// [`SortedDisjointMap<T, VC>`]: its logical output is `Option<VC::Value>`,
346/// with `Some(value)` for mapped input ranges and `None` for gaps. The `None`
347/// values are ordinary map values, so the resulting map's key domain is
348/// universal.
349///
350/// This iterator is created by [`SortedDisjointMap::fill_gaps`], typically from
351/// a map stream such as [`RangeMapBlaze::range_values`]. To materialize the
352/// result instead of streaming it, use [`RangeMapBlaze::fill_gaps`].
353///
354/// [`RangeMapBlaze::range_values`]: crate::RangeMapBlaze::range_values
355/// [`RangeMapBlaze::fill_gaps`]: crate::RangeMapBlaze::fill_gaps
356///
357/// For the set and map APIs together, see the [Ranges and gaps guide][crate::gaps].
358///
359/// # Example
360///
361/// ```
362/// use range_set_blaze::{
363/// CheckSortedDisjointMap, RangeMapBlaze, SortedDisjointMap,
364/// };
365///
366/// // From the streaming layer directly.
367/// let input = CheckSortedDisjointMap::new([(1..=3, &"red"), (7..=10, &"blue")]);
368/// let output = input.fill_gaps().collect::<Vec<_>>();
369/// assert_eq!(output[0], (0..=0, None));
370/// assert_eq!(output[1], (1..=3, Some(&"red")));
371/// assert_eq!(output[2], (4..=6, None));
372/// assert_eq!(output[3], (7..=10, Some(&"blue")));
373/// assert_eq!(output[4], (11..=u8::MAX, None));
374///
375/// // Or explicitly materialize the streaming result into a map.
376/// let map = RangeMapBlaze::from_iter([(1_u8..=3, "red"), (7..=10, "blue")]);
377/// let filled: RangeMapBlaze<u8, Option<&str>> = map.range_values().fill_gaps()
378/// .into_range_map_blaze();
379/// assert_eq!(filled.get(5), Some(&None));
380/// assert_eq!(filled.get(2), Some(&Some("red")));
381/// ```
382#[derive(Clone, Debug)]
383#[must_use = "iterators are lazy and do nothing unless consumed"]
384pub struct FillGapsIterMap<T, VC, I> {
385 iter: I,
386 next_start: T,
387 pending: Option<(RangeInclusive<T>, VC)>,
388 done: bool,
389}
390
391impl<T, VC, I> FillGapsIterMap<T, VC, I>
392where
393 T: Integer,
394 VC: ValueCarrier,
395 I: SortedDisjointMap<T, VC>,
396{
397 /// Creates a gap-filling iterator from a sorted, disjoint map stream.
398 pub(crate) fn new(iter: I) -> Self {
399 Self {
400 iter,
401 next_start: T::min_value(),
402 pending: None,
403 done: false,
404 }
405 }
406}
407
408impl<T, VC, I> Iterator for FillGapsIterMap<T, VC, I>
409where
410 T: Integer,
411 VC: ValueCarrier,
412 I: SortedDisjointMap<T, VC>,
413{
414 type Item = (RangeInclusive<T>, Option<VC>);
415
416 fn next(&mut self) -> Option<Self::Item> {
417 if self.done {
418 return None;
419 }
420
421 let Some((range, value)) = self.pending.take().or_else(|| self.iter.next()) else {
422 self.done = true;
423 return Some((self.next_start..=T::max_value(), None));
424 };
425
426 let (start, end) = range.clone().into_inner();
427 debug_assert!(start <= end);
428
429 if self.next_start < start {
430 let gap = self.next_start..=start.sub_one();
431 self.next_start = start;
432 self.pending = Some((range, value));
433 return Some((gap, None));
434 }
435
436 if end == T::max_value() {
437 self.done = true;
438 } else {
439 self.next_start = end.add_one();
440 }
441 Some((range, Some(value)))
442 }
443
444 fn size_hint(&self) -> (usize, Option<usize>) {
445 if self.done {
446 return (0, Some(0));
447 }
448
449 let (low, high) = self.iter.size_hint();
450 let pending = usize::from(self.pending.is_some());
451 let low = low.saturating_add(pending);
452 let high = high.and_then(|high| high.checked_mul(2)?.checked_add(pending)?.checked_add(1));
453 (low, high)
454 }
455}
456
457impl<T, VC, I> FusedIterator for FillGapsIterMap<T, VC, I>
458where
459 T: Integer,
460 VC: ValueCarrier,
461 I: SortedDisjointMap<T, VC>,
462{
463}