Skip to main content

alloc/collections/btree/
search.rs

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