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