Skip to content

Commit b64b5fa

Browse files
authored
Rollup merge of #77935 - ssomers:btree_cleanup_1, r=Mark-Simulacrum
BTreeMap: make PartialCmp/PartialEq explicit and tested Follow-up on a topic raised in #77612 r? @Mark-Simulacrum
2 parents 9d8bf44 + a22cd05 commit b64b5fa

File tree

2 files changed

+62
-7
lines changed

2 files changed

+62
-7
lines changed

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

+29-7
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,13 @@ impl<K, V> Root<K, V> {
257257
/// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the
258258
/// `NodeRef` could be pointing to either type of node.
259259
pub struct NodeRef<BorrowType, K, V, Type> {
260-
/// The number of levels below the node.
260+
/// The number of levels below the node, a property of the node that cannot be
261+
/// entirely described by `Type` and that the node does not store itself either.
262+
/// Unconstrained if `Type` is `LeafOrInternal`, must be zero if `Type` is `Leaf`,
263+
/// and must be non-zero if `Type` is `Internal`.
261264
height: usize,
265+
/// The pointer to the leaf or internal node. The definition of `InternalNode`
266+
/// ensures that the pointer is valid either way.
262267
node: NonNull<LeafNode<K, V>>,
263268
_marker: PhantomData<(BorrowType, Type)>,
264269
}
@@ -315,8 +320,8 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
315320
unsafe { usize::from((*self.as_leaf_ptr()).len) }
316321
}
317322

318-
/// Returns the height of this node in the whole tree. Zero height denotes the
319-
/// leaf level.
323+
/// Returns the height of this node with respect to the leaf level. Zero height means the
324+
/// node is a leaf itself.
320325
pub fn height(&self) -> usize {
321326
self.height
322327
}
@@ -584,9 +589,11 @@ impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
584589
// to avoid aliasing with outstanding references to other elements,
585590
// in particular, those returned to the caller in earlier iterations.
586591
let leaf = self.node.as_ptr();
592+
let keys = unsafe { &raw const (*leaf).keys };
593+
let vals = unsafe { &raw mut (*leaf).vals };
587594
// We must coerce to unsized array pointers because of Rust issue #74679.
588-
let keys: *const [_] = unsafe { &raw const (*leaf).keys };
589-
let vals: *mut [_] = unsafe { &raw mut (*leaf).vals };
595+
let keys: *const [_] = keys;
596+
let vals: *mut [_] = vals;
590597
// SAFETY: The keys and values of a node must always be initialized up to length.
591598
let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() };
592599
let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() };
@@ -817,19 +824,34 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
817824
}
818825
}
819826

827+
impl<BorrowType, K, V, NodeType> NodeRef<BorrowType, K, V, NodeType> {
828+
/// Could be a public implementation of PartialEq, but only used in this module.
829+
fn eq(&self, other: &Self) -> bool {
830+
let Self { node, height, _marker: _ } = self;
831+
if *node == other.node {
832+
debug_assert_eq!(*height, other.height);
833+
true
834+
} else {
835+
false
836+
}
837+
}
838+
}
839+
820840
impl<BorrowType, K, V, NodeType, HandleType> PartialEq
821841
for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
822842
{
823843
fn eq(&self, other: &Self) -> bool {
824-
self.node.node == other.node.node && self.idx == other.idx
844+
let Self { node, idx, _marker: _ } = self;
845+
node.eq(&other.node) && *idx == other.idx
825846
}
826847
}
827848

828849
impl<BorrowType, K, V, NodeType, HandleType> PartialOrd
829850
for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
830851
{
831852
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
832-
if self.node.node == other.node.node { Some(self.idx.cmp(&other.idx)) } else { None }
853+
let Self { node, idx, _marker: _ } = self;
854+
if node.eq(&other.node) { Some(idx.cmp(&other.idx)) } else { None }
833855
}
834856
}
835857

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

+33
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
use core::cmp::Ordering::*;
23

34
#[test]
45
fn test_splitpoint() {
@@ -24,6 +25,38 @@ fn test_splitpoint() {
2425
}
2526
}
2627

28+
#[test]
29+
fn test_partial_cmp_eq() {
30+
let mut root1: Root<i32, ()> = Root::new_leaf();
31+
let mut leaf1 = unsafe { root1.leaf_node_as_mut() };
32+
leaf1.push(1, ());
33+
root1.push_internal_level();
34+
let root2: Root<i32, ()> = Root::new_leaf();
35+
36+
let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type();
37+
let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type();
38+
let top_edge_1 = root1.node_as_ref().first_edge();
39+
let top_edge_2 = root2.node_as_ref().first_edge();
40+
41+
assert!(leaf_edge_1a == leaf_edge_1a);
42+
assert!(leaf_edge_1a != leaf_edge_1b);
43+
assert!(leaf_edge_1a != top_edge_1);
44+
assert!(leaf_edge_1a != top_edge_2);
45+
assert!(top_edge_1 == top_edge_1);
46+
assert!(top_edge_1 != top_edge_2);
47+
48+
assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1a), Some(Equal));
49+
assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1b), Some(Less));
50+
assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_1), None);
51+
assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_2), None);
52+
assert_eq!(top_edge_1.partial_cmp(&top_edge_1), Some(Equal));
53+
assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None);
54+
55+
root1.pop_internal_level();
56+
unsafe { root1.into_ref().deallocate_and_ascend() };
57+
unsafe { root2.into_ref().deallocate_and_ascend() };
58+
}
59+
2760
#[test]
2861
#[cfg(target_arch = "x86_64")]
2962
fn test_sizes() {

0 commit comments

Comments
 (0)