Skip to content

Commit fd6e4e4

Browse files
committed
BTree: no longer search arrays twice to check Ord
1 parent 33d22f8 commit fd6e4e4

File tree

3 files changed

+27
-33
lines changed

3 files changed

+27
-33
lines changed

library/alloc/src/collections/btree/map.rs

-6
Original file line numberDiff line numberDiff line change
@@ -1018,9 +1018,6 @@ impl<K, V> BTreeMap<K, V> {
10181018
///
10191019
/// Panics if range `start > end`.
10201020
/// Panics if range `start == end` and both bounds are `Excluded`.
1021-
/// May panic if the [`Ord`] implementation of type `T` is ill-defined,
1022-
/// either because it does not form a total order or because it does not
1023-
/// correspond to the [`Ord`] implementation of type `K`.
10241021
///
10251022
/// # Examples
10261023
///
@@ -1064,9 +1061,6 @@ impl<K, V> BTreeMap<K, V> {
10641061
///
10651062
/// Panics if range `start > end`.
10661063
/// Panics if range `start == end` and both bounds are `Excluded`.
1067-
/// May panic if the [`Ord`] implementation of type `T` is ill-defined,
1068-
/// either because it does not form a total order or because it does not
1069-
/// correspond to the [`Ord`] implementation of type `K`.
10701064
///
10711065
/// # Examples
10721066
///

library/alloc/src/collections/btree/map/tests.rs

-2
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,6 @@ fn test_range_backwards_4() {
776776
}
777777

778778
#[test]
779-
#[should_panic]
780779
fn test_range_finding_ill_order_in_map() {
781780
let mut map = BTreeMap::new();
782781
map.insert(Cyclic3::B, ());
@@ -789,7 +788,6 @@ fn test_range_finding_ill_order_in_map() {
789788
}
790789

791790
#[test]
792-
#[should_panic]
793791
fn test_range_finding_ill_order_in_range_ord() {
794792
// Has proper order the first time asked, then flips around.
795793
struct EvilTwin(i32);

library/alloc/src/collections/btree/search.rs

+27-25
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
7676
/// If not found, returns an `Err` with the leaf edge matching the entire
7777
/// range.
7878
///
79-
/// As a diagnostic service, panics if the range specifies impossible bounds
80-
/// or if it witnesses that the `Ord` implementation of `Q` violates total
81-
/// order or is inconsistent with the `Ord` implementation of `K`.
79+
/// As a diagnostic service, panics if the range specifies impossible bounds.
8280
///
8381
/// The result is meaningful only if the tree is ordered by key.
8482
pub fn search_tree_for_bifurcation<'r, Q: ?Sized, R>(
@@ -118,14 +116,8 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
118116
let mut upper_bound = SearchBound::from_range(end);
119117
loop {
120118
let (lower_edge_idx, lower_child_bound) = self.find_lower_bound_index(lower_bound);
121-
let (upper_edge_idx, upper_child_bound) = self.find_upper_bound_index(upper_bound);
122-
if lower_edge_idx > upper_edge_idx {
123-
// Since we already checked the range bounds, this can only
124-
// happen if `Q: Ord` does not implement a total order or does
125-
// not correspond to the `K: Ord` implementation that is used
126-
// while populating the tree.
127-
panic!("Ord is ill-defined in BTreeMap range")
128-
}
119+
let (upper_edge_idx, upper_child_bound) =
120+
unsafe { self.find_upper_bound_index(upper_bound, lower_edge_idx) };
129121
if lower_edge_idx < upper_edge_idx {
130122
return Ok((
131123
self,
@@ -135,6 +127,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
135127
upper_child_bound,
136128
));
137129
}
130+
debug_assert_eq!(lower_edge_idx, upper_edge_idx);
138131
let common_edge = unsafe { Handle::new_edge(self, lower_edge_idx) };
139132
match common_edge.force() {
140133
Leaf(common_edge) => return Err(common_edge),
@@ -174,7 +167,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
174167
Q: ?Sized + Ord,
175168
K: Borrow<Q>,
176169
{
177-
let (edge_idx, bound) = self.find_upper_bound_index(bound);
170+
let (edge_idx, bound) = unsafe { self.find_upper_bound_index(bound, 0) };
178171
let edge = unsafe { Handle::new_edge(self, edge_idx) };
179172
(edge, bound)
180173
}
@@ -193,29 +186,33 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
193186
Q: Ord,
194187
K: Borrow<Q>,
195188
{
196-
match self.find_key_index(key) {
189+
match unsafe { self.find_key_index(key, 0) } {
197190
IndexResult::KV(idx) => Found(unsafe { Handle::new_kv(self, idx) }),
198191
IndexResult::Edge(idx) => GoDown(unsafe { Handle::new_edge(self, idx) }),
199192
}
200193
}
201194

202195
/// Returns either the KV index in the node at which the key (or an equivalent)
203-
/// exists, or the edge index where the key belongs.
196+
/// exists, or the edge index where the key belongs, starting from a particular index.
204197
///
205198
/// The result is meaningful only if the tree is ordered by key, like the tree
206199
/// in a `BTreeMap` is.
207-
fn find_key_index<Q: ?Sized>(&self, key: &Q) -> IndexResult
200+
///
201+
/// # Safety
202+
/// `start_index` must be a valid edge index for the node.
203+
unsafe fn find_key_index<Q: ?Sized>(&self, key: &Q, start_index: usize) -> IndexResult
208204
where
209205
Q: Ord,
210206
K: Borrow<Q>,
211207
{
212208
let node = self.reborrow();
213209
let keys = node.keys();
214-
for (i, k) in keys.iter().enumerate() {
210+
debug_assert!(start_index <= keys.len());
211+
for (offset, k) in unsafe { keys.get_unchecked(start_index..) }.iter().enumerate() {
215212
match key.cmp(k.borrow()) {
216213
Ordering::Greater => {}
217-
Ordering::Equal => return IndexResult::KV(i),
218-
Ordering::Less => return IndexResult::Edge(i),
214+
Ordering::Equal => return IndexResult::KV(start_index + offset),
215+
Ordering::Less => return IndexResult::Edge(start_index + offset),
219216
}
220217
}
221218
IndexResult::Edge(keys.len())
@@ -235,11 +232,11 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
235232
K: Borrow<Q>,
236233
{
237234
match bound {
238-
Included(key) => match self.find_key_index(key) {
235+
Included(key) => match unsafe { self.find_key_index(key, 0) } {
239236
IndexResult::KV(idx) => (idx, AllExcluded),
240237
IndexResult::Edge(idx) => (idx, bound),
241238
},
242-
Excluded(key) => match self.find_key_index(key) {
239+
Excluded(key) => match unsafe { self.find_key_index(key, 0) } {
243240
IndexResult::KV(idx) => (idx + 1, AllIncluded),
244241
IndexResult::Edge(idx) => (idx, bound),
245242
},
@@ -248,26 +245,31 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
248245
}
249246
}
250247

251-
/// Clone of `find_lower_bound_index` for the upper bound.
252-
fn find_upper_bound_index<'r, Q>(
248+
/// Mirror image of `find_lower_bound_index` for the upper bound,
249+
/// with an additional parameter to skip part of the key array.
250+
///
251+
/// # Safety
252+
/// `start_index` must be a valid edge index for the node.
253+
unsafe fn find_upper_bound_index<'r, Q>(
253254
&self,
254255
bound: SearchBound<&'r Q>,
256+
start_index: usize,
255257
) -> (usize, SearchBound<&'r Q>)
256258
where
257259
Q: ?Sized + Ord,
258260
K: Borrow<Q>,
259261
{
260262
match bound {
261-
Included(key) => match self.find_key_index(key) {
263+
Included(key) => match unsafe { self.find_key_index(key, start_index) } {
262264
IndexResult::KV(idx) => (idx + 1, AllExcluded),
263265
IndexResult::Edge(idx) => (idx, bound),
264266
},
265-
Excluded(key) => match self.find_key_index(key) {
267+
Excluded(key) => match unsafe { self.find_key_index(key, start_index) } {
266268
IndexResult::KV(idx) => (idx, AllIncluded),
267269
IndexResult::Edge(idx) => (idx, bound),
268270
},
269271
AllIncluded => (self.len(), AllIncluded),
270-
AllExcluded => (0, AllExcluded),
272+
AllExcluded => (start_index, AllExcluded),
271273
}
272274
}
273275
}

0 commit comments

Comments
 (0)