//! Stores a disjoint collection of ranges over numeric types. //! //! Overlapping and adjacent ranges are automatically merged together. use alloc::collections::BTreeMap; use core::{ cmp::{max, min}, fmt::{Debug, Formatter}, iter::Peekable, ops::RangeInclusive, }; use types::Fixed; #[derive(Default, Clone, PartialEq, Eq)] /// A set of disjoint ranges over numeric types. /// /// Overlapping and adjacent ranges are automatically merged together. pub struct RangeSet { // an entry in the map ranges[a] = b implies there is an range [a, b] (inclusive) in this set. ranges: BTreeMap, } /// Allows a two values to be tested for adjacency. pub trait OrdAdjacency { /// Returns true if self is adjacent on either side of rhs. fn are_adjacent(self, rhs: Self) -> bool; } impl RangeSet where T: Ord + Copy + OrdAdjacency, { // Returns true if there are no members in this set currently. pub fn is_empty(&self) -> bool { self.ranges.is_empty() } /// Insert a range into this set, automatically merging with existing ranges as needed. pub fn insert(&mut self, range: RangeInclusive) { if range.end() < range.start() { // ignore or malformed ranges. return; } let mut start = *range.start(); let mut end = *range.end(); // There may be up to one intersecting range prior to this new range, check for it and merge if needed. if let Some((prev_start, prev_end)) = self.prev_range(start) { if range_is_subset(start, end, prev_start, prev_end) { return; } if ranges_overlap_or_adjacent(start, end, prev_start, prev_end) { start = min(start, prev_start); end = max(end, prev_end); self.ranges.remove(&prev_start); } }; // There may be one or more ranges proceeding this new range that intersect, find and merge them as needed. loop { let Some((next_start, next_end)) = self.next_range(start) else { // No existing ranges which might overlap, can now insert the current range self.ranges.insert(start, end); return; }; if range_is_subset(start, end, next_start, next_end) { return; } if ranges_overlap_or_adjacent(start, end, next_start, next_end) { start = min(start, next_start); end = max(end, next_end); self.ranges.remove(&next_start); } else { self.ranges.insert(start, end); return; } } } /// Returns an iterator over the contained ranges. pub fn iter(&'_ self) -> impl Iterator> + '_ { self.ranges.iter().map(|(a, b)| *a..=*b) } /// Returns an iterator over the intersection of this and other. pub fn intersection<'a>( &'a self, other: &'a Self, ) -> impl Iterator> + 'a { IntersectionIter { it_a: self.iter().peekable(), it_b: other.iter().peekable(), } } /// Finds a range in this set with a start greater than or equal to the provided start value. fn next_range(&self, start: T) -> Option<(T, T)> { let (next_start, next_end) = self.ranges.range(start..).next()?; Some((*next_start, *next_end)) } /// Finds a range in this set with a start less than the provided start value. fn prev_range(&self, start: T) -> Option<(T, T)> { let (next_start, next_end) = self.ranges.range(..start).next_back()?; Some((*next_start, *next_end)) } } impl Extend> for RangeSet where T: Copy + Ord + OrdAdjacency, { fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(|r| self.insert(r)); } } impl FromIterator> for RangeSet where T: Default + Copy + Ord + OrdAdjacency, { fn from_iter>>(iter: I) -> Self { let mut result: Self = Default::default(); result.extend(iter); result } } impl Debug for RangeSet where T: Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { write!(f, "RangeSet {{")?; for (start, end) in self.ranges.iter() { write!(f, "[{:?}, {:?}], ", start, end)?; } write!(f, "}}") } } struct IntersectionIter where A: Iterator>, B: Iterator>, { it_a: Peekable, it_b: Peekable, } impl Iterator for IntersectionIter where A: Iterator>, B: Iterator>, T: Ord + Copy, { type Item = RangeInclusive; fn next(&mut self) -> Option { loop { let (Some(a), Some(b)) = (self.it_a.peek(), self.it_b.peek()) else { return None; }; let a = a.clone(); let b = b.clone(); match range_intersection(&a, &b) { Some(intersection) => { self.step_iterators(&a, &b); return Some(intersection); } None => self.step_iterators(&a, &b), } } } } impl IntersectionIter where A: Iterator>, B: Iterator>, T: Ord, { fn step_iterators(&mut self, a: &RangeInclusive, b: &RangeInclusive) { if a.end() <= b.end() { self.it_a.next(); } if a.end() >= b.end() { self.it_b.next(); } } } impl OrdAdjacency for u32 { fn are_adjacent(self, rhs: u32) -> bool { matches!(self.checked_add(1).map(|r| r == rhs), Some(true)) || matches!(rhs.checked_add(1).map(|r| r == self), Some(true)) } } impl OrdAdjacency for u16 { fn are_adjacent(self, rhs: u16) -> bool { matches!(self.checked_add(1).map(|r| r == rhs), Some(true)) || matches!(rhs.checked_add(1).map(|r| r == self), Some(true)) } } impl OrdAdjacency for Fixed { fn are_adjacent(self, rhs: Fixed) -> bool { matches!( self.checked_add(Fixed::EPSILON).map(|r| r == rhs), Some(true) ) || matches!( rhs.checked_add(Fixed::EPSILON).map(|r| r == self), Some(true) ) } } /// If a and b intersect return a range representing the intersection. fn range_intersection( a: &RangeInclusive, b: &RangeInclusive, ) -> Option> { if a.start() <= b.end() && b.start() <= a.end() { Some(*max(a.start(), b.start())..=*min(a.end(), b.end())) } else { None } } /// Returns true if the ranges [a_start, a_end] and [b_start, b_end] overlap or are adjacent to each other. /// /// All bounds are inclusive. fn ranges_overlap_or_adjacent(a_start: T, a_end: T, b_start: T, b_end: T) -> bool where T: Ord + OrdAdjacency, { (a_start <= b_end && b_start <= a_end) || (a_end.are_adjacent(b_start)) || (b_end.are_adjacent(a_start)) } /// Returns true if the range [a_start, a_end] is a subset of [b_start, b_end]. /// /// All bounds are inclusive. fn range_is_subset(a_start: T, a_end: T, b_start: T, b_end: T) -> bool where T: Ord, { a_start >= b_start && a_end <= b_end } #[cfg(test)] mod test { use super::*; #[test] #[allow(clippy::reversed_empty_ranges)] fn insert_invalid() { let mut map: RangeSet = Default::default(); map.insert(12..=11); assert_eq!(map.iter().collect::>(), vec![],); } #[test] fn insert_non_overlapping() { let mut map: RangeSet = Default::default(); map.insert(11..=11); map.insert(2..=3); map.insert(6..=9); assert_eq!(map.iter().collect::>(), vec![2..=3, 6..=9, 11..=11],); } #[test] fn insert_subset_before() { let mut map: RangeSet = Default::default(); map.insert(2..=8); map.insert(3..=7); assert_eq!(map.iter().collect::>(), vec![2..=8],); } #[test] fn insert_subset_after() { let mut map: RangeSet = Default::default(); map.insert(2..=8); map.insert(2..=7); map.insert(2..=8); assert_eq!(map.iter().collect::>(), vec![2..=8],); } #[test] fn insert_overlapping_before() { let mut map: RangeSet = Default::default(); map.insert(2..=8); map.insert(7..=11); assert_eq!(map.iter().collect::>(), vec![2..=11],); } #[test] fn insert_overlapping_after() { let mut map: RangeSet = Default::default(); map.insert(10..=14); map.insert(7..=11); assert_eq!(map.iter().collect::>(), vec![7..=14],); let mut map: RangeSet = Default::default(); map.insert(10..=14); map.insert(10..=17); assert_eq!(map.iter().collect::>(), vec![10..=17],); } #[test] fn insert_overlapping_multiple_after() { let mut map: RangeSet = Default::default(); map.insert(10..=14); map.insert(16..=17); map.insert(7..=16); assert_eq!(map.iter().collect::>(), vec![7..=17],); let mut map: RangeSet = Default::default(); map.insert(10..=14); map.insert(16..=17); map.insert(10..=16); assert_eq!(map.iter().collect::>(), vec![10..=17],); let mut map: RangeSet = Default::default(); map.insert(10..=14); map.insert(16..=17); map.insert(10..=17); assert_eq!(map.iter().collect::>(), vec![10..=17],); } #[test] fn insert_overlapping_before_and_after() { let mut map: RangeSet = Default::default(); map.insert(6..=8); map.insert(10..=14); map.insert(16..=20); map.insert(7..=19); assert_eq!(map.iter().collect::>(), vec![6..=20],); } #[test] fn insert_joins_adjacent() { let mut map: RangeSet = Default::default(); map.insert(6..=8); map.insert(9..=10); assert_eq!(map.iter().collect::>(), vec![6..=10],); let mut map: RangeSet = Default::default(); map.insert(9..=10); map.insert(6..=8); assert_eq!(map.iter().collect::>(), vec![6..=10],); let mut map: RangeSet = Default::default(); map.insert(6..=8); map.insert(10..=10); map.insert(9..=9); assert_eq!(map.iter().collect::>(), vec![6..=10],); } #[test] fn from_iter_and_extend() { let mut map: RangeSet = [2..=5, 13..=64, 7..=9].into_iter().collect(); assert_eq!(map.iter().collect::>(), vec![2..=5, 7..=9, 13..=64],); map.extend([6..=17, 100..=101]); assert_eq!(map.iter().collect::>(), vec![2..=64, 100..=101],); } #[test] fn intersection() { let a: RangeSet = [2..=5, 7..=9, 13..=64].into_iter().collect(); let b: RangeSet = [1..=3, 5..=8, 13..=64, 67..=69].into_iter().collect(); let expected = vec![2..=3, 5..=5, 7..=8, 13..=64]; assert_eq!(a.intersection(&b).collect::>(), expected); assert_eq!(b.intersection(&a).collect::>(), expected); } }