Skip to content

Commit 17ab457

Browse files
committed
Somewhat complicated way to respect BTreeMap's node length invariant
1 parent 441fd22 commit 17ab457

File tree

1 file changed

+65
-16
lines changed
  • library/alloc/src/collections/btree

1 file changed

+65
-16
lines changed

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

+65-16
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,53 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
821821
}
822822
}
823823

824+
enum InsertionPlace {
825+
Left(usize),
826+
Right(usize),
827+
}
828+
829+
/// Given an edge index where we want to insert into a node filled to capacity,
830+
/// computes a sensible KV index of a split point and where to perform the insertion.
831+
/// The goal of the split point is for its key and value to end up in a parent node;
832+
/// the keys, values and edges to the left of the split point become the left child;
833+
/// the keys, values and edges to the right of the split point become the right child.
834+
fn splitpoint(edge_idx: usize) -> (usize, InsertionPlace) {
835+
debug_assert!(edge_idx <= CAPACITY);
836+
// Rust issue #74834 tries to explain these symmetric rules.
837+
let middle_kv_idx;
838+
let insertion;
839+
if edge_idx <= B - 2 {
840+
middle_kv_idx = B - 2;
841+
insertion = InsertionPlace::Left(edge_idx);
842+
} else if edge_idx == B - 1 {
843+
middle_kv_idx = B - 1;
844+
insertion = InsertionPlace::Left(edge_idx);
845+
} else if edge_idx == B {
846+
middle_kv_idx = B - 1;
847+
insertion = InsertionPlace::Right(0);
848+
} else {
849+
middle_kv_idx = B;
850+
let new_edge_idx = edge_idx - (B + 1);
851+
insertion = InsertionPlace::Right(new_edge_idx);
852+
}
853+
let mut left_len = middle_kv_idx;
854+
let mut right_len = CAPACITY - middle_kv_idx - 1;
855+
match insertion {
856+
InsertionPlace::Left(edge_idx) => {
857+
debug_assert!(edge_idx <= left_len);
858+
left_len += 1;
859+
}
860+
InsertionPlace::Right(edge_idx) => {
861+
debug_assert!(edge_idx <= right_len);
862+
right_len += 1;
863+
}
864+
}
865+
debug_assert!(left_len >= MIN_LEN);
866+
debug_assert!(right_len >= MIN_LEN);
867+
debug_assert!(left_len + right_len == CAPACITY);
868+
(middle_kv_idx, insertion)
869+
}
870+
824871
impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::Edge> {
825872
/// Helps implementations of `insert_fit` for a particular `NodeType`,
826873
/// by taking care of leaf data.
@@ -863,18 +910,20 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
863910
let kv = unsafe { Handle::new_kv(self.node, self.idx) };
864911
(InsertResult::Fit(kv), ptr)
865912
} else {
866-
let middle = unsafe { Handle::new_kv(self.node, B) };
913+
let (middle_kv_idx, insertion) = splitpoint(self.idx);
914+
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
867915
let (mut left, k, v, mut right) = middle.split();
868-
let ptr = if self.idx <= B {
869-
unsafe { Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val) }
870-
} else {
871-
unsafe {
916+
let ptr = match insertion {
917+
InsertionPlace::Left(insert_idx) => unsafe {
918+
Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val)
919+
},
920+
InsertionPlace::Right(insert_idx) => unsafe {
872921
Handle::new_edge(
873922
right.node_as_mut().cast_unchecked::<marker::Leaf>(),
874-
self.idx - (B + 1),
923+
insert_idx,
875924
)
876925
.insert_fit(key, val)
877-
}
926+
},
878927
};
879928
(InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), ptr)
880929
}
@@ -936,20 +985,20 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
936985
let kv = unsafe { Handle::new_kv(self.node, self.idx) };
937986
InsertResult::Fit(kv)
938987
} else {
939-
let middle = unsafe { Handle::new_kv(self.node, B) };
988+
let (middle_kv_idx, insertion) = splitpoint(self.idx);
989+
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
940990
let (mut left, k, v, mut right) = middle.split();
941-
if self.idx <= B {
942-
unsafe {
943-
Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val, edge);
944-
}
945-
} else {
946-
unsafe {
991+
match insertion {
992+
InsertionPlace::Left(insert_idx) => unsafe {
993+
Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val, edge);
994+
},
995+
InsertionPlace::Right(insert_idx) => unsafe {
947996
Handle::new_edge(
948997
right.node_as_mut().cast_unchecked::<marker::Internal>(),
949-
self.idx - (B + 1),
998+
insert_idx,
950999
)
9511000
.insert_fit(key, val, edge);
952-
}
1001+
},
9531002
}
9541003
InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right })
9551004
}

0 commit comments

Comments
 (0)