norm/
matched_ranges.rs

1use core::cmp::Ordering;
2use core::ops::Range;
3
4/// TODO: docs
5pub(crate) struct MatchedRanges<'a> {
6    ranges: &'a mut Vec<Range<usize>>,
7    initial_len: usize,
8}
9
10impl<'a> From<&'a mut Vec<Range<usize>>> for MatchedRanges<'a> {
11    #[inline(always)]
12    fn from(ranges: &'a mut Vec<Range<usize>>) -> Self {
13        let initial_len = ranges.len();
14        Self { ranges, initial_len }
15    }
16}
17
18impl core::fmt::Debug for MatchedRanges<'_> {
19    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
20        use core::fmt::Write;
21
22        let (initial, this) = self.ranges.split_at(self.initial_len);
23
24        if this.is_empty() {
25            return initial.fmt(f);
26        }
27
28        f.write_char('[')?;
29
30        for (idx, initial) in initial.iter().enumerate() {
31            write!(f, "{initial:?}")?;
32            if idx + 1 < initial.len() {
33                f.write_str(", ")?;
34            }
35        }
36
37        f.write_str(" | ")?;
38
39        for (idx, this) in this.iter().enumerate() {
40            write!(f, "{this:?}")?;
41            if idx + 1 < this.len() {
42                f.write_str(", ")?;
43            }
44        }
45
46        f.write_char(']')?;
47
48        Ok(())
49    }
50}
51
52impl<'a> MatchedRanges<'a> {
53    /// TODO: docs
54    #[inline(always)]
55    fn binary_search_by<'r, F>(&'r self, fun: F) -> Result<usize, usize>
56    where
57        F: FnMut(&'r Range<usize>) -> Ordering,
58    {
59        self.ranges[self.initial_len..].binary_search_by(fun)
60    }
61
62    /// TODO: docs
63    #[inline(always)]
64    fn get_mut(&mut self, idx: usize) -> Option<&mut Range<usize>> {
65        self.ranges.get_mut(self.initial_len + idx)
66    }
67
68    /// TODO: docs
69    #[inline(always)]
70    pub(crate) fn insert(&mut self, new_range: Range<usize>) {
71        let insert_idx = match self
72            .binary_search_by(|range| range.start.cmp(&new_range.start))
73        {
74            Err(idx) => idx,
75
76            // The range at `idx` and the new range have the same start.
77            Ok(idx) => {
78                let (range, next_range) = {
79                    let (left, right) = self.split_at_mut(idx + 1);
80                    (&mut left[idx], right.get_mut(0))
81                };
82
83                if range.end >= new_range.end {
84                    // The new range is completely contained within this
85                    // existing range.
86                    return;
87                }
88
89                if let Some(next_range) = next_range {
90                    if new_range.end >= next_range.start {
91                        // The new range fills the gap between this range and
92                        // the next one.
93                        range.end = next_range.end;
94                        self.remove(idx + 1);
95                        return;
96                    }
97                }
98
99                range.end = new_range.end;
100
101                return;
102            },
103        };
104
105        if insert_idx == 0 {
106            let Some(first_range) = self.get_mut(0) else {
107                // This is the first range.
108                self.push(new_range);
109                return;
110            };
111
112            if new_range.end >= first_range.start {
113                first_range.start = new_range.start;
114            } else {
115                self.insert_at(0, new_range);
116            }
117
118            return;
119        }
120
121        if insert_idx == self.len() {
122            let last_range = self.last_mut().unwrap();
123
124            if new_range.start <= last_range.end {
125                last_range.end = last_range.end.max(new_range.end);
126            } else {
127                self.push(new_range);
128            }
129
130            return;
131        }
132
133        let (prev_range, next_range) = {
134            let (left, right) = self.split_at_mut(insert_idx);
135            (&mut left[insert_idx - 1], &mut right[0])
136        };
137
138        match (
139            new_range.start <= prev_range.end,
140            new_range.end >= next_range.start,
141        ) {
142            // The new range fills the gap between two existing ranges, so
143            // we merge them.
144            //
145            // ------   ------    =>    ---------------
146            //     xxxxxxx
147            (true, true) => {
148                prev_range.end = next_range.end;
149                self.remove(insert_idx);
150            },
151
152            // The new range starts within an existing range but ends before
153            // the next one starts, so we extend the end of the existing range.
154            //
155            // ------    ------    =>    --------  ------
156            //     xxxx
157            (true, false) if new_range.end > prev_range.end => {
158                prev_range.end = new_range.end;
159            },
160
161            // The new range ends within an existing range but starts after
162            // the previous one ends, so we extend the start of the existing
163            // range.
164            //
165            // ------    ------    =>    ------  --------
166            //         xxxx
167            (false, true) => {
168                next_range.start = new_range.start;
169            },
170
171            // The new range is strictly within an existing gap, so we just
172            // insert it.
173            // ------         ------    =>   ------  -----  ------
174            //         xxxxx
175            (false, false) => {
176                self.insert_at(insert_idx, new_range);
177            },
178
179            _ => {},
180        }
181    }
182
183    /// TODO: docs
184    #[inline(always)]
185    fn insert_at(&mut self, idx: usize, range: Range<usize>) {
186        self.ranges.insert(self.initial_len + idx, range);
187    }
188
189    /// TODO: docs
190    #[inline(always)]
191    fn last_mut(&mut self) -> Option<&mut Range<usize>> {
192        self.ranges.last_mut()
193    }
194
195    /// TODO: docs
196    #[inline(always)]
197    fn len(&self) -> usize {
198        self.ranges.len() - self.initial_len
199    }
200
201    /// TODO: docs
202    #[inline(always)]
203    fn push(&mut self, range: Range<usize>) {
204        self.ranges.push(range);
205    }
206
207    /// TODO: docs
208    #[inline(always)]
209    fn remove(&mut self, idx: usize) -> Range<usize> {
210        self.ranges.remove(self.initial_len + idx)
211    }
212
213    /// TODO: docs
214    #[inline(always)]
215    fn split_at_mut(
216        &mut self,
217        idx: usize,
218    ) -> (&mut [Range<usize>], &mut [Range<usize>]) {
219        let len = self.initial_len;
220        let (left, right) = self.ranges.split_at_mut(len + idx);
221        let left = &mut left[len..];
222        (left, right)
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    #![allow(clippy::single_range_in_vec_init)]
229
230    use super::*;
231
232    impl<'a> MatchedRanges<'a> {
233        fn as_slice(&self) -> &[Range<usize>] {
234            &self.ranges[..]
235        }
236    }
237
238    fn ranges() -> MatchedRanges<'static> {
239        let vec = Box::leak(Box::default());
240        MatchedRanges::from(vec)
241    }
242
243    #[test]
244    fn matched_ranges_insert_same_start_increasing_end() {
245        let mut ranges = ranges();
246        ranges.insert(0..1);
247        ranges.insert(0..2);
248        ranges.insert(0..3);
249        assert_eq!(ranges.as_slice(), [0..3]);
250        ranges.insert(0..2);
251        assert_eq!(ranges.as_slice(), [0..3]);
252    }
253
254    #[test]
255    fn matched_ranges_insert_consecutive_1() {
256        let mut ranges = ranges();
257        ranges.insert(0..1);
258        ranges.insert(1..2);
259        ranges.insert(2..3);
260        assert_eq!(ranges.as_slice(), [0..3]);
261    }
262
263    #[test]
264    fn matched_ranges_insert_consecutive_2() {
265        let mut ranges = ranges();
266        ranges.insert(2..3);
267        ranges.insert(1..2);
268        ranges.insert(0..1);
269        assert_eq!(ranges.as_slice(), [0..3]);
270    }
271
272    #[test]
273    fn matched_ranges_insert_fill_gap() {
274        let mut ranges = ranges();
275        ranges.insert(0..1);
276        ranges.insert(2..3);
277        assert_eq!(ranges.as_slice(), [0..1, 2..3]);
278        ranges.insert(1..2);
279        assert_eq!(ranges.as_slice(), [0..3]);
280    }
281
282    #[test]
283    fn matched_ranges_insert_extend_end() {
284        let mut ranges = ranges();
285        ranges.insert(0..2);
286        ranges.insert(4..6);
287        ranges.insert(1..3);
288        assert_eq!(ranges.as_slice(), [0..3, 4..6]);
289    }
290
291    #[test]
292    fn matched_ranges_insert_extend_start() {
293        let mut ranges = ranges();
294        ranges.insert(0..2);
295        ranges.insert(4..6);
296        ranges.insert(3..5);
297        assert_eq!(ranges.as_slice(), [0..2, 3..6]);
298    }
299
300    #[test]
301    fn matched_ranges_insert_in_gap() {
302        let mut ranges = ranges();
303        ranges.insert(0..4);
304        ranges.insert(6..8);
305        ranges.insert(10..14);
306        assert_eq!(ranges.as_slice(), [0..4, 6..8, 10..14]);
307    }
308
309    #[test]
310    fn matched_ranges_insert_smaller_1() {
311        let mut ranges = ranges();
312        ranges.insert(3..8);
313        ranges.insert(4..7);
314        assert_eq!(ranges.as_slice(), [3..8]);
315        ranges.insert(5..6);
316        assert_eq!(ranges.as_slice(), [3..8]);
317    }
318
319    #[test]
320    fn matched_ranges_insert_smaller_2() {
321        let mut ranges = ranges();
322        ranges.insert(1..2);
323        ranges.insert(3..8);
324        ranges.insert(4..7);
325        assert_eq!(ranges.as_slice(), [1..2, 3..8]);
326        ranges.insert(5..6);
327        assert_eq!(ranges.as_slice(), [1..2, 3..8]);
328    }
329
330    #[test]
331    fn matched_ranges_insert_smaller_3() {
332        let mut ranges = ranges();
333        ranges.insert(10..11);
334        ranges.insert(3..8);
335        ranges.insert(4..7);
336        assert_eq!(ranges.as_slice(), [3..8, 10..11]);
337        ranges.insert(5..6);
338        assert_eq!(ranges.as_slice(), [3..8, 10..11]);
339    }
340
341    #[test]
342    fn matched_ranges_insert_smaller_4() {
343        let mut ranges = ranges();
344        ranges.insert(1..2);
345        ranges.insert(10..11);
346        ranges.insert(3..8);
347        ranges.insert(4..7);
348        assert_eq!(ranges.as_slice(), [1..2, 3..8, 10..11]);
349        ranges.insert(5..6);
350        assert_eq!(ranges.as_slice(), [1..2, 3..8, 10..11]);
351    }
352}