rangemap/
operations.rs

1use core::cmp::Ordering;
2use core::iter::{FusedIterator, Peekable};
3use core::ops::{Range, RangeInclusive};
4
5/// Trait to determine the ordering of the start and end of a range.
6trait RangeOrder {
7    /// Ordering of start value
8    fn order_start(&self, other: &Self) -> Ordering;
9
10    /// Ordering of end value
11    fn order_end(&self, other: &Self) -> Ordering;
12}
13
14impl<T: Ord> RangeOrder for Range<T> {
15    fn order_start(&self, other: &Self) -> Ordering {
16        self.start.cmp(&other.start)
17    }
18
19    fn order_end(&self, other: &Self) -> Ordering {
20        self.end.cmp(&other.end)
21    }
22}
23
24impl<T: Ord> RangeOrder for RangeInclusive<T> {
25    fn order_start(&self, other: &Self) -> Ordering {
26        self.start().cmp(other.start())
27    }
28
29    fn order_end(&self, other: &Self) -> Ordering {
30        self.end().cmp(other.end())
31    }
32}
33
34/// Range which can be merged with a next range if they overlap.
35trait RangeMerge: Sized {
36    /// Merges this range and the next range, if they overlap.
37    fn merge(&mut self, next: &Self) -> bool;
38}
39
40impl<T: Ord + Clone> RangeMerge for Range<T> {
41    fn merge(&mut self, other: &Self) -> bool {
42        if !self.contains(&other.start) {
43            return false;
44        }
45
46        if other.end > self.end {
47            self.end = other.end.clone();
48        }
49
50        true
51    }
52}
53
54impl<T: Ord + Clone> RangeMerge for RangeInclusive<T> {
55    fn merge(&mut self, other: &Self) -> bool {
56        if !self.contains(other.start()) {
57            return false;
58        }
59
60        if other.end() > self.end() {
61            *self = RangeInclusive::new(self.start().clone(), other.end().clone());
62        }
63
64        true
65    }
66}
67
68/// Range which can be merged with a next range if they overlap.
69trait RangeIntersect: Sized {
70    /// Attempt to merge the next range into the current range, if they overlap.
71    fn intersect(&self, next: &Self) -> Option<Self>;
72}
73
74impl<T: Ord + Clone> RangeIntersect for Range<T> {
75    fn intersect(&self, other: &Self) -> Option<Self> {
76        let start = (&self.start).max(&other.start);
77        let end = (&self.end).min(&other.end);
78
79        if start >= end {
80            return None;
81        }
82
83        Some(start.clone()..end.clone())
84    }
85}
86
87impl<T: Ord + Clone> RangeIntersect for RangeInclusive<T> {
88    fn intersect(&self, other: &Self) -> Option<Self> {
89        let start = self.start().max(other.start());
90        let end = self.end().min(other.end());
91
92        if start > end {
93            return None;
94        }
95
96        Some(start.clone()..=end.clone())
97    }
98}
99
100#[test]
101fn test_intersect() {
102    assert_eq!((0..5).intersect(&(0..3)), Some(0..3));
103    assert_eq!((0..3).intersect(&(0..5)), Some(0..3));
104    assert_eq!((0..3).intersect(&(3..3)), None);
105}
106
107/// Iterator that produces the union of two iterators of sorted ranges.
108pub struct Union<'a, T, L, R = L>
109where
110    T: 'a,
111    L: Iterator<Item = &'a T>,
112    R: Iterator<Item = &'a T>,
113{
114    left: Peekable<L>,
115    right: Peekable<R>,
116}
117
118impl<'a, T, L, R> Union<'a, T, L, R>
119where
120    T: 'a,
121    L: Iterator<Item = &'a T>,
122    R: Iterator<Item = &'a T>,
123{
124    /// Create new Union iterator.
125    ///
126    /// Requires that the two iterators produce sorted ranges.
127    pub fn new(left: L, right: R) -> Self {
128        Self {
129            left: left.peekable(),
130            right: right.peekable(),
131        }
132    }
133}
134
135impl<'a, R, I> Iterator for Union<'a, R, I>
136where
137    R: RangeOrder + RangeMerge + Clone,
138    I: Iterator<Item = &'a R>,
139{
140    type Item = R;
141
142    fn next(&mut self) -> Option<Self::Item> {
143        // get start range
144        let mut range = match (self.left.peek(), self.right.peek()) {
145            // if there is only one possible range, pick that
146            (Some(_), None) => self.left.next().unwrap(),
147            (None, Some(_)) => self.right.next().unwrap(),
148            // when there are two ranges, pick the one with the earlier start
149            (Some(left), Some(right)) => {
150                if left.order_start(right).is_lt() {
151                    self.left.next().unwrap()
152                } else {
153                    self.right.next().unwrap()
154                }
155            }
156            // otherwise we are done
157            (None, None) => return None,
158        }
159        .clone();
160
161        // peek into next value of iterator and merge if it is contiguous
162        let mut join = |iter: &mut Peekable<I>| {
163            if let Some(next) = iter.peek() {
164                if range.merge(next) {
165                    iter.next().unwrap();
166                    return true;
167                }
168            }
169            false
170        };
171
172        // keep merging ranges as long as we can
173        loop {
174            if !(join(&mut self.left) || join(&mut self.right)) {
175                break;
176            }
177        }
178
179        Some(range)
180    }
181}
182
183impl<'a, R, I> FusedIterator for Union<'a, R, I>
184where
185    R: RangeOrder + RangeMerge + Clone,
186    I: Iterator<Item = &'a R>,
187{
188}
189
190/// Iterator that produces the union of two iterators of sorted ranges.
191pub struct Intersection<'a, T, L, R = L>
192where
193    T: 'a,
194    L: Iterator<Item = &'a T>,
195    R: Iterator<Item = &'a T>,
196{
197    left: Peekable<L>,
198    right: Peekable<R>,
199}
200
201impl<'a, T, L, R> Intersection<'a, T, L, R>
202where
203    T: 'a,
204    L: Iterator<Item = &'a T>,
205    R: Iterator<Item = &'a T>,
206{
207    /// Create new Intersection iterator.
208    ///
209    /// Requires that the two iterators produce sorted ranges.
210    pub fn new(left: L, right: R) -> Self {
211        Self {
212            left: left.peekable(),
213            right: right.peekable(),
214        }
215    }
216}
217
218impl<'a, R, I> Iterator for Intersection<'a, R, I>
219where
220    R: RangeOrder + RangeIntersect + Clone,
221    I: Iterator<Item = &'a R>,
222{
223    type Item = R;
224
225    fn next(&mut self) -> Option<Self::Item> {
226        loop {
227            // if we don't have at least two ranges, there cannot be an intersection
228            let (Some(left), Some(right)) = (self.left.peek(), self.right.peek()) else {
229                return None;
230            };
231
232            let intersection = left.intersect(right);
233
234            // pop the range that ends earlier
235            if left.order_end(right).is_lt() {
236                self.left.next();
237            } else {
238                self.right.next();
239            }
240
241            if let Some(intersection) = intersection {
242                return Some(intersection);
243            }
244        }
245    }
246}