rune_alloc/btree/
search.rs

1use core::borrow::Borrow;
2use core::cmp::Ordering;
3use core::ops::{Bound, RangeBounds};
4
5use super::node::{marker, ForceResult::*, Handle, NodeRef};
6
7use SearchBound::*;
8use SearchResult::*;
9
10pub(crate) enum SearchBound<T> {
11    /// An inclusive bound to look for, just like `Bound::Included(T)`.
12    Included(T),
13    /// An exclusive bound to look for, just like `Bound::Excluded(T)`.
14    Excluded(T),
15    /// An unconditional inclusive bound, just like `Bound::Unbounded`.
16    AllIncluded,
17    /// An unconditional exclusive bound.
18    AllExcluded,
19}
20
21impl<T> SearchBound<T> {
22    pub(crate) fn from_range(range_bound: Bound<T>) -> Self {
23        match range_bound {
24            Bound::Included(t) => Included(t),
25            Bound::Excluded(t) => Excluded(t),
26            Bound::Unbounded => AllIncluded,
27        }
28    }
29}
30
31pub(crate) enum SearchResult<BorrowType, K, V, FoundType, GoDownType> {
32    Found(Handle<NodeRef<BorrowType, K, V, FoundType>, marker::KV>),
33    GoDown(Handle<NodeRef<BorrowType, K, V, GoDownType>, marker::Edge>),
34}
35
36pub(crate) enum IndexResult {
37    KV(usize),
38    Edge(usize),
39}
40
41impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
42    /// Looks up a given key in a (sub)tree headed by the node, recursively.
43    /// Returns a `Found` with the handle of the matching KV, if any. Otherwise,
44    /// returns a `GoDown` with the handle of the leaf edge where the key belongs.
45    ///
46    /// The result is meaningful only if the tree is ordered by key, like the tree
47    /// in a `BTreeMap` is.
48    pub(crate) fn search_tree<C: ?Sized, Q: ?Sized, E>(
49        mut self,
50        cx: &mut C,
51        key: &Q,
52        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
53    ) -> Result<SearchResult<BorrowType, K, V, marker::LeafOrInternal, marker::Leaf>, E>
54    where
55        K: Borrow<Q>,
56    {
57        loop {
58            self = match self.search_node(cx, key, cmp)? {
59                Found(handle) => return Ok(Found(handle)),
60                GoDown(handle) => match handle.force() {
61                    Leaf(leaf) => return Ok(GoDown(leaf)),
62                    Internal(internal) => internal.descend(),
63                },
64            }
65        }
66    }
67
68    /// Descends to the nearest node where the edge matching the lower bound
69    /// of the range is different from the edge matching the upper bound, i.e.,
70    /// the nearest node that has at least one key contained in the range.
71    ///
72    /// If found, returns an `Ok` with that node, the strictly ascending pair of
73    /// edge indices in the node delimiting the range, and the corresponding
74    /// pair of bounds for continuing the search in the child nodes, in case
75    /// the node is internal.
76    ///
77    /// If not found, returns an `Err` with the leaf edge matching the entire
78    /// range.
79    ///
80    /// As a diagnostic service, panics if the range specifies impossible bounds.
81    ///
82    /// The result is meaningful only if the tree is ordered by key.
83    pub(crate) fn search_tree_for_bifurcation<'r, C: ?Sized, Q: ?Sized, R, E>(
84        mut self,
85        cx: &mut C,
86        range: &'r R,
87        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
88    ) -> Result<
89        Result<
90            (
91                NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
92                usize,
93                usize,
94                SearchBound<&'r Q>,
95                SearchBound<&'r Q>,
96            ),
97            Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
98        >,
99        E,
100    >
101    where
102        K: Borrow<Q>,
103        R: RangeBounds<Q>,
104    {
105        // Inlining these variables should be avoided. We assume the bounds reported by `range`
106        // remain the same, but an adversarial implementation could change between calls (#81138).
107        let (start, end) = (range.start_bound(), range.end_bound());
108        match (start, end) {
109            (Bound::Excluded(s), Bound::Excluded(e))
110                if matches!(cmp(cx, s, e)?, Ordering::Equal) =>
111            {
112                panic!("range start and end are equal and excluded in BTree")
113            }
114            (Bound::Included(s) | Bound::Excluded(s), Bound::Included(e) | Bound::Excluded(e))
115                if matches!(cmp(cx, s, e)?, Ordering::Greater) =>
116            {
117                panic!("range start is greater than range end in BTree")
118            }
119            _ => {}
120        }
121        let mut lower_bound = SearchBound::from_range(start);
122        let mut upper_bound = SearchBound::from_range(end);
123        loop {
124            let (lower_edge_idx, lower_child_bound) =
125                self.find_lower_bound_index(cx, lower_bound, cmp)?;
126            let (upper_edge_idx, upper_child_bound) =
127                unsafe { self.find_upper_bound_index(cx, upper_bound, lower_edge_idx, cmp)? };
128            if lower_edge_idx < upper_edge_idx {
129                return Ok(Ok((
130                    self,
131                    lower_edge_idx,
132                    upper_edge_idx,
133                    lower_child_bound,
134                    upper_child_bound,
135                )));
136            }
137            debug_assert_eq!(lower_edge_idx, upper_edge_idx);
138            let common_edge = unsafe { Handle::new_edge(self, lower_edge_idx) };
139            match common_edge.force() {
140                Leaf(common_edge) => return Ok(Err(common_edge)),
141                Internal(common_edge) => {
142                    self = common_edge.descend();
143                    lower_bound = lower_child_bound;
144                    upper_bound = upper_child_bound;
145                }
146            }
147        }
148    }
149
150    /// Finds an edge in the node delimiting the lower bound of a range.
151    /// Also returns the lower bound to be used for continuing the search in
152    /// the matching child node, if `self` is an internal node.
153    ///
154    /// The result is meaningful only if the tree is ordered by key.
155    pub(crate) fn find_lower_bound_edge<'r, C: ?Sized, Q: ?Sized, E>(
156        self,
157        cx: &mut C,
158        bound: SearchBound<&'r Q>,
159        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
160    ) -> Result<(Handle<Self, marker::Edge>, SearchBound<&'r Q>), E>
161    where
162        K: Borrow<Q>,
163    {
164        let (edge_idx, bound) = self.find_lower_bound_index(cx, bound, cmp)?;
165        let edge = unsafe { Handle::new_edge(self, edge_idx) };
166        Ok((edge, bound))
167    }
168
169    /// Clone of `find_lower_bound_edge` for the upper bound.
170    pub(crate) fn find_upper_bound_edge<'r, C: ?Sized, Q: ?Sized, E>(
171        self,
172        cx: &mut C,
173        bound: SearchBound<&'r Q>,
174        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
175    ) -> Result<(Handle<Self, marker::Edge>, SearchBound<&'r Q>), E>
176    where
177        K: Borrow<Q>,
178    {
179        let (edge_idx, bound) = unsafe { self.find_upper_bound_index(cx, bound, 0, cmp)? };
180        let edge = unsafe { Handle::new_edge(self, edge_idx) };
181        Ok((edge, bound))
182    }
183}
184
185impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
186    /// Looks up a given key in the node, without recursion.
187    /// Returns a `Found` with the handle of the matching KV, if any. Otherwise,
188    /// returns a `GoDown` with the handle of the edge where the key might be found
189    /// (if the node is internal) or where the key can be inserted.
190    ///
191    /// The result is meaningful only if the tree is ordered by key, like the tree
192    /// in a `BTreeMap` is.
193    pub(crate) fn search_node<C: ?Sized, Q: ?Sized, E>(
194        self,
195        cx: &mut C,
196        key: &Q,
197        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
198    ) -> Result<SearchResult<BorrowType, K, V, Type, Type>, E>
199    where
200        K: Borrow<Q>,
201    {
202        Ok(match unsafe { self.find_key_index(cx, key, 0, cmp)? } {
203            IndexResult::KV(idx) => Found(unsafe { Handle::new_kv(self, idx) }),
204            IndexResult::Edge(idx) => GoDown(unsafe { Handle::new_edge(self, idx) }),
205        })
206    }
207
208    /// Returns either the KV index in the node at which the key (or an equivalent)
209    /// exists, or the edge index where the key belongs, starting from a particular index.
210    ///
211    /// The result is meaningful only if the tree is ordered by key, like the tree
212    /// in a `BTreeMap` is.
213    ///
214    /// # Safety
215    /// `start_index` must be a valid edge index for the node.
216    unsafe fn find_key_index<C: ?Sized, Q: ?Sized, E>(
217        &self,
218        cx: &mut C,
219        key: &Q,
220        start_index: usize,
221        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
222    ) -> Result<IndexResult, E>
223    where
224        K: Borrow<Q>,
225    {
226        let node = self.reborrow();
227        let keys = node.keys();
228        debug_assert!(start_index <= keys.len());
229        for (offset, k) in unsafe { keys.get_unchecked(start_index..) }
230            .iter()
231            .enumerate()
232        {
233            match cmp(cx, key, k.borrow())? {
234                Ordering::Greater => {}
235                Ordering::Equal => return Ok(IndexResult::KV(start_index + offset)),
236                Ordering::Less => return Ok(IndexResult::Edge(start_index + offset)),
237            }
238        }
239        Ok(IndexResult::Edge(keys.len()))
240    }
241
242    /// Finds an edge index in the node delimiting the lower bound of a range.
243    /// Also returns the lower bound to be used for continuing the search in
244    /// the matching child node, if `self` is an internal node.
245    ///
246    /// The result is meaningful only if the tree is ordered by key.
247    fn find_lower_bound_index<'r, C: ?Sized, Q: ?Sized, E>(
248        &self,
249        cx: &mut C,
250        bound: SearchBound<&'r Q>,
251        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
252    ) -> Result<(usize, SearchBound<&'r Q>), E>
253    where
254        K: Borrow<Q>,
255    {
256        Ok(match bound {
257            Included(key) => match unsafe { self.find_key_index(cx, key, 0, cmp)? } {
258                IndexResult::KV(idx) => (idx, AllExcluded),
259                IndexResult::Edge(idx) => (idx, bound),
260            },
261            Excluded(key) => match unsafe { self.find_key_index(cx, key, 0, cmp)? } {
262                IndexResult::KV(idx) => (idx + 1, AllIncluded),
263                IndexResult::Edge(idx) => (idx, bound),
264            },
265            AllIncluded => (0, AllIncluded),
266            AllExcluded => (self.len(), AllExcluded),
267        })
268    }
269
270    /// Mirror image of `find_lower_bound_index` for the upper bound,
271    /// with an additional parameter to skip part of the key array.
272    ///
273    /// # Safety
274    /// `start_index` must be a valid edge index for the node.
275    unsafe fn find_upper_bound_index<'r, C: ?Sized, Q: ?Sized, E>(
276        &self,
277        cx: &mut C,
278        bound: SearchBound<&'r Q>,
279        start_index: usize,
280        cmp: fn(&mut C, &Q, &Q) -> Result<Ordering, E>,
281    ) -> Result<(usize, SearchBound<&'r Q>), E>
282    where
283        K: Borrow<Q>,
284    {
285        Ok(match bound {
286            Included(key) => match unsafe { self.find_key_index(cx, key, start_index, cmp)? } {
287                IndexResult::KV(idx) => (idx + 1, AllExcluded),
288                IndexResult::Edge(idx) => (idx, bound),
289            },
290            Excluded(key) => match unsafe { self.find_key_index(cx, key, start_index, cmp)? } {
291                IndexResult::KV(idx) => (idx, AllIncluded),
292                IndexResult::Edge(idx) => (idx, bound),
293            },
294            AllIncluded => (self.len(), AllIncluded),
295            AllExcluded => (start_index, AllExcluded),
296        })
297    }
298}