Skip to main content

range_tree_rs/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![cfg_attr(docsrs, allow(unused_attributes))]
3
4//! This crate provides a range-tree implementation, intended to manage range section with btree.
5
6use core::{
7    cmp::Ordering,
8    fmt,
9    ops::{AddAssign, Bound, RangeBounds, SubAssign},
10};
11use embed_collections::btree::{BTreeMap, Entry};
12use num_traits::*;
13
14pub use embed_collections::btree::{Cursor, IntoIter, Iter};
15
16pub trait RangeTreeKey:
17    Unsigned + AddAssign + SubAssign + Ord + Copy + fmt::Debug + fmt::Display + Default + 'static
18{
19}
20
21impl<T> RangeTreeKey for T where
22    T: Unsigned
23        + AddAssign
24        + SubAssign
25        + Ord
26        + Copy
27        + fmt::Debug
28        + fmt::Display
29        + Default
30        + 'static
31{
32}
33
34pub struct RangeTree<T: RangeTreeKey> {
35    // the tree stores ranges in [key:start, value:size) format
36    tree: BTreeMap<T, T>,
37    space: T,
38}
39
40/// Trait for allocator
41///
42/// when range tree merge/split, need to mirror the adding and removal range from size_tree
43pub trait RangeTreeOps<T: RangeTreeKey> {
44    /// Callback for manage size tree
45    fn op_add(&mut self, start: T, size: T);
46    /// Callback for manage size tree
47    fn op_remove(&mut self, start: T, size: T);
48}
49
50#[derive(Default)]
51pub struct DummyOps();
52
53impl<T: RangeTreeKey> RangeTreeOps<T> for DummyOps {
54    #[inline]
55    fn op_add(&mut self, _start: T, _size: T) {}
56
57    #[inline]
58    fn op_remove(&mut self, _start: T, _size: T) {}
59}
60
61impl<T: RangeTreeKey> RangeTree<T> {
62    pub fn new() -> Self {
63        Self { tree: BTreeMap::new(), space: T::zero() }
64    }
65
66    #[inline]
67    pub fn is_empty(&self) -> bool {
68        self.tree.is_empty()
69    }
70
71    #[inline(always)]
72    pub fn get_space(&self) -> T {
73        self.space
74    }
75
76    #[inline(always)]
77    pub fn len(&self) -> usize {
78        self.tree.len()
79    }
80
81    /// Add range segment, merge with adjacent ranges, assuming no intersections.
82    ///
83    /// Returns `Ok(())` if there are no intersection;
84    /// otherwise returns the overlapping range as `Err((existing_start, existing_size))`.
85    ///
86    /// This equals to add + add_find_overlap in v0.1
87    #[inline]
88    pub fn add(&mut self, start: T, size: T) -> Result<(), (T, T)> {
89        self.add_with(start, size, &mut DummyOps {})
90    }
91
92    #[inline]
93    pub fn add_with<O>(&mut self, start: T, size: T, ops: &mut O) -> Result<(), (T, T)>
94    where
95        O: RangeTreeOps<T>,
96    {
97        assert!(size > T::zero(), "range tree add size={} error", size);
98        let end = start + size;
99        let mut prev = None;
100        let mut next = None;
101        match self.tree.entry(start) {
102            Entry::Occupied(ent) => {
103                return Err((*ent.key(), *ent.get()));
104            }
105            Entry::Vacant(ent) => {
106                if let Some((_start, _size)) = ent.peek_backward() {
107                    let _end = *_start + *_size;
108                    match _end.cmp(&start) {
109                        Ordering::Equal => {
110                            prev = Some((*_start, *_size));
111                        }
112                        Ordering::Greater => return Err((*_start, *_size)),
113                        _ => {}
114                    }
115                }
116                if let Some((_start, _size)) = ent.peek_forward() {
117                    match end.cmp(_start) {
118                        Ordering::Equal => {
119                            next = Some((*_start, *_size));
120                        }
121                        Ordering::Greater => return Err((*_start, *_size)),
122                        _ => {}
123                    }
124                }
125                match (prev, next) {
126                    (None, None) => {
127                        ops.op_add(start, size);
128                        ent.insert(size);
129                    }
130                    (None, Some((next_start, mut next_size))) => {
131                        let mut ent_next = ent.move_forward().expect("merge next");
132                        ops.op_remove(next_start, next_size);
133                        next_size += size;
134                        *ent_next.get_mut() = next_size;
135                        ent_next.alter_key(start).expect("merge next alter_key");
136                        ops.op_add(start, next_size);
137                    }
138                    (Some((prev_start, mut prev_size)), None) => {
139                        ops.op_remove(prev_start, prev_size);
140                        let mut ent_prev = ent.move_backward().expect("merge prev");
141                        prev_size += size;
142                        *ent_prev.get_mut() = prev_size;
143                        ops.op_add(prev_start, prev_size);
144                    }
145                    (Some((prev_start, prev_size)), Some((next_start, next_size))) => {
146                        ops.op_remove(prev_start, prev_size);
147                        ops.op_remove(next_start, next_size);
148                        let mut ent_prev = ent.move_backward().expect("merge prev");
149                        let final_size = prev_size + size + next_size;
150                        *ent_prev.get_mut() = final_size;
151                        ops.op_add(prev_start, final_size);
152                        let ent_next = ent_prev.move_forward().expect("merge next");
153                        ent_next.remove();
154                    }
155                }
156                self.space += size;
157                Ok(())
158            }
159        }
160    }
161
162    #[inline(always)]
163    pub fn add_abs(&mut self, start: T, end: T) -> Result<(), (T, T)> {
164        assert!(start < end, "range tree add start={} end={}", start, end);
165        self.add(start, end - start)
166    }
167
168    /// Add range which may have multiple intersections with existing range, ensuring union result
169    #[inline]
170    pub fn add_loosely(&mut self, start: T, size: T) {
171        assert!(size > T::zero(), "range tree add size error");
172        let new_end = start + size;
173        let base_ent = match self.tree.entry(start) {
174            Entry::Occupied(oe) => {
175                if start + *oe.get() >= new_end {
176                    return;
177                }
178                Entry::Occupied(oe)
179            }
180            Entry::Vacant(ve) => {
181                if let Some((pre_start, pre_size)) = ve.peek_backward() {
182                    let cur_end = *pre_start + *pre_size;
183                    if cur_end >= new_end {
184                        return;
185                    }
186                    if cur_end >= start {
187                        Entry::Occupied(ve.move_backward().expect("move back to merge"))
188                    } else {
189                        Entry::Vacant(ve)
190                    }
191                } else {
192                    Entry::Vacant(ve)
193                }
194            }
195        };
196
197        macro_rules! remove_intersect {
198            ($next_start: expr, $new_end: expr) => {
199                if let Some((last_start, last_size)) = self.tree.remove_range_with(
200                    $next_start..=$new_end,
201                    |_removed_start, removed_size| {
202                        self.space -= *removed_size;
203                    },
204                ) {
205                    let last_end = last_start + last_size;
206                    if last_end > new_end {
207                        let _size = last_end - new_end;
208                        // add back and join with previous range
209                        self.add(new_end, _size)
210                            .expect("add {new_end:?}:{_size:?} should not fail");
211                    }
212                }
213            };
214        }
215        match base_ent {
216            Entry::Occupied(mut oe) => {
217                let base_start = *oe.key();
218                let old_size = *oe.get();
219
220                // extend the size to final size
221                let final_size = new_end - base_start;
222                self.space += final_size - old_size;
223                *oe.get_mut() = final_size;
224
225                if let Some((_next_start, _next_size)) = oe.peek_forward() {
226                    let next_start = *_next_start;
227                    let next_size = *_next_size;
228                    if next_start < new_end {
229                        drop(oe);
230                        remove_intersect!(next_start, new_end);
231                    } else if next_start == new_end {
232                        // space is neutral (moving between segments)
233                        *oe.get_mut() += next_size;
234                        self.tree.remove(&next_start);
235                    }
236                }
237            }
238            Entry::Vacant(ve) => {
239                let base_start = start;
240                self.space += size;
241
242                if let Some((_next_start, _next_size)) = ve.peek_forward() {
243                    let next_start = *_next_start;
244                    let next_size = *_next_size;
245                    if next_start < new_end {
246                        ve.insert(size);
247                        remove_intersect!(next_start, new_end);
248                    } else if next_start == new_end {
249                        let final_size = new_end - base_start + next_size;
250                        ve.insert(final_size);
251                        self.tree.remove(&next_start);
252                    } else {
253                        ve.insert(size);
254                    }
255                } else {
256                    ve.insert(size);
257                }
258            }
259        }
260    }
261
262    /// Valid and remove specify range start:size
263    ///
264    /// # Return value
265    /// - Only return Ok(()) when there's existing range equal to or contain the removal range in the tree,
266    /// - return Err(None) when not found,
267    /// - return Err(Some(start, size)) when a range intersect with the removal range, or when the
268    ///   removal range larger than existing range.
269    #[inline]
270    pub fn remove(&mut self, start: T, size: T) -> Result<(), Option<(T, T)>> {
271        self.remove_with(start, size, &mut DummyOps {})
272    }
273
274    /// Valid and remove specify range start:size
275    ///
276    /// # Return value
277    ///
278    /// - Only return Ok(()) when there's existing range equal to or contain the removal range in the tree,
279    /// - return Err(None) when not found,
280    /// - return Err(Some(start, size)) when a range intersect with the removal range, or when the
281    ///   removal range larger than existing range.
282    pub fn remove_with<O>(&mut self, start: T, size: T, ops: &mut O) -> Result<(), Option<(T, T)>>
283    where
284        O: RangeTreeOps<T>,
285    {
286        let end = start + size;
287        let ent = self.tree.entry(start);
288        match ent {
289            Entry::Occupied(mut oent) => {
290                let rs_size = *oent.get();
291                ops.op_remove(start, rs_size);
292                if rs_size == size {
293                    // Exact match or subset removed
294                    oent.remove();
295                    self.space -= rs_size;
296                    return Ok(());
297                } else if rs_size > size {
298                    // Shrink from front
299                    let new_start = start + size;
300                    let new_size = rs_size - size;
301                    oent.alter_key(new_start).expect("shrink alter_key");
302                    *oent.get_mut() = new_size;
303                    ops.op_add(new_start, new_size);
304                    self.space -= size;
305                    return Ok(());
306                } else {
307                    // existing range smaller than what need to remove
308                    return Err(Some((start, rs_size)));
309                }
310            }
311            Entry::Vacant(vent) => {
312                if let Some((&rs_start, &rs_size)) = vent.peek_backward() {
313                    let rs_end = rs_start + rs_size;
314                    if rs_end > start {
315                        ops.op_remove(rs_start, rs_size);
316                        let mut oent = vent.move_backward().expect("move back to overlapping");
317                        if rs_end > end {
318                            let new_size = start - rs_start;
319                            // punch a hold in the middle
320                            *oent.get_mut() = new_size;
321                            ops.op_add(rs_start, new_size);
322                            let new_size2 = rs_end - end;
323                            // TODO optimize add insert after entry for btree
324                            self.tree.insert(end, new_size2);
325                            ops.op_add(end, new_size2);
326                            self.space -= size;
327                            return Ok(());
328                        } else if rs_end == end {
329                            // Shrink from back
330                            let new_size = start - rs_start;
331                            *oent.get_mut() = new_size;
332                            ops.op_add(rs_start, new_size);
333                            self.space -= rs_end - start;
334                            return Ok(());
335                        } else {
336                            return Err(Some((rs_start, rs_size)));
337                        }
338                    } else {
339                        return Err(None);
340                    }
341                } else {
342                    return Err(None);
343                }
344            }
345        }
346    }
347
348    /// Remove all the intersection ranges in the tree
349    ///
350    /// the range start:size to remove allow to be larger than the existing range
351    ///
352    /// Equals to remove_and_split in v0.1
353    ///
354    /// return true if overlapping range found and removed.
355    /// return false if overlapping range not found.
356    ///
357    /// #[inline]
358    pub fn remove_loosely(&mut self, mut start: T, mut size: T) -> bool {
359        let end = start + size;
360        let mut ent = self.tree.entry(start);
361        let mut removed = false;
362        loop {
363            match ent {
364                Entry::Occupied(mut oent) => {
365                    let rs_size = *oent.get();
366                    if rs_size == size {
367                        // Exact match or subset removed
368                        oent.remove();
369                        self.space -= rs_size;
370                        return true;
371                    } else if rs_size > size {
372                        // Shrink from front
373                        let new_start = start + size;
374                        let new_size = rs_size - size;
375                        oent.alter_key(new_start).expect("shrink alter_key");
376                        *oent.get_mut() = new_size;
377                        self.space -= size;
378                        return true;
379                    } else {
380                        if let Some((_next_start, _next_size)) = oent.peek_forward() {
381                            if *_next_start < end {
382                                start = *_next_start;
383                                size = end - start;
384                                self.space -= *oent.get();
385                                oent.remove();
386                                ent = self.tree.entry(start);
387                                removed = true;
388                                continue;
389                            }
390                        }
391                        self.space -= rs_size;
392                        oent.remove();
393                        return true;
394                    }
395                }
396                Entry::Vacant(vent) => {
397                    if let Some((&rs_start, &rs_size)) = vent.peek_backward() {
398                        let rs_end = rs_start + rs_size;
399                        if rs_end > start {
400                            let mut oent = vent.move_backward().expect("move back to overlapping");
401                            if rs_end > end {
402                                let new_size = start - rs_start;
403                                // punch a hold in the middle
404                                *oent.get_mut() = new_size;
405                                let new_size2 = rs_end - end;
406                                // TODO optimize add insert after entry for btree
407                                self.tree.insert(end, new_size2);
408                                self.space -= size;
409                                return true;
410                            } else {
411                                // Shrink from back
412                                let new_size = start - rs_start;
413                                *oent.get_mut() = new_size;
414                                self.space -= rs_end - start;
415                                if rs_end == end {
416                                    return true;
417                                }
418                                if let Some((next_start, _)) = oent.peek_forward() {
419                                    if *next_start < end {
420                                        start = *next_start;
421                                        size = end - *next_start;
422                                        ent = Entry::Occupied(
423                                            oent.move_forward()
424                                                .expect("move forward to overlapping"),
425                                        );
426                                        continue;
427                                    }
428                                }
429                                return true;
430                            }
431                        }
432                    }
433                    // Handle the case where range starts before the first overlapping segment
434                    if let Some((next_start, _)) = vent.peek_forward() {
435                        if *next_start < end {
436                            start = *next_start;
437                            size = end - *next_start;
438                            ent = Entry::Occupied(
439                                vent.move_forward().expect("move forward to overlapping"),
440                            );
441                            continue;
442                        }
443                    }
444                    return removed;
445                }
446            }
447        }
448    }
449
450    /// return only when segment overlaps with [start, start+size]
451    #[inline]
452    pub fn range<'a, R: RangeBounds<T>>(&'a self, r: R) -> RangeIter<'a, T> {
453        let start = match r.start_bound() {
454            Bound::Included(start) => Some(*start),
455            Bound::Excluded(start) => Some(*start),
456            _ => None,
457        };
458        let cursor = if let Some(_start) = start {
459            let mut _cursor = self.tree.cursor(&_start);
460            if let Some((pre_start, pre_size)) = _cursor.peek_backward() {
461                let pre_end = *pre_start + *pre_size;
462                if pre_end > _start {
463                    _cursor.previous();
464                }
465                // TODO what if we find pre_start < start but pre_start + size >= start
466            }
467            _cursor
468        } else {
469            self.tree.first_cursor()
470        };
471        RangeIter { cursor, end: r.end_bound().cloned(), not_empty: true }
472    }
473
474    pub fn collect(&self) -> Vec<(T, T)> {
475        let mut v = Vec::with_capacity(self.len());
476        for (start, size) in &self.tree {
477            v.push((*start, *size))
478        }
479        v
480    }
481
482    #[inline]
483    pub fn iter(&self) -> Iter<'_, T, T> {
484        self.tree.iter()
485    }
486
487    pub fn validate(&self) {
488        self.tree.validate();
489    }
490
491    #[inline]
492    pub fn memory_used(&self) -> usize {
493        self.tree.memory_used()
494    }
495}
496
497impl<'a, T: RangeTreeKey> IntoIterator for &'a RangeTree<T> {
498    type Item = (&'a T, &'a T);
499    type IntoIter = Iter<'a, T, T>;
500
501    #[inline]
502    fn into_iter(self) -> Self::IntoIter {
503        self.iter()
504    }
505}
506
507impl<T: RangeTreeKey> IntoIterator for RangeTree<T> {
508    type Item = (T, T);
509    type IntoIter = IntoIter<T, T>;
510
511    #[inline]
512    fn into_iter(self) -> Self::IntoIter {
513        self.tree.into_iter()
514    }
515}
516
517pub struct RangeIter<'a, T: RangeTreeKey> {
518    cursor: Cursor<'a, T, T>,
519    end: Bound<T>,
520    not_empty: bool,
521}
522
523impl<'a, T: RangeTreeKey> Iterator for RangeIter<'a, T> {
524    type Item = (T, T);
525
526    #[inline]
527    fn next(&mut self) -> Option<Self::Item> {
528        if self.not_empty {
529            if let Some((start, size)) = self.cursor.next() {
530                match self.end {
531                    Bound::Unbounded => return Some((*start, *size)),
532                    Bound::Excluded(end) => {
533                        if *start < end {
534                            return Some((*start, *size));
535                        }
536                        self.not_empty = false;
537                        return None;
538                    }
539                    Bound::Included(end) => {
540                        if *start <= end {
541                            return Some((*start, *size));
542                        }
543                        self.not_empty = false;
544                        return None;
545                    }
546                }
547            }
548            self.not_empty = false;
549        }
550        return None;
551    }
552}