Skip to main content

range_tree_rs/
lib.rs

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