Skip to content

Commit 829d69b

Browse files
committed
Auto merge of #74827 - ssomers:btree_cleanup_insert, r=Mark-Simulacrum
Move bulk of BTreeMap::insert method down to new method on handle Adjust the boundary between the map and node layers for insertion: do more in the node layer, keep root manipulation and pointer dereferencing separate. No change in undefined behaviour or performance. r? @Mark-Simulacrum
2 parents c186aed + f5c47fa commit 829d69b

File tree

2 files changed

+70
-37
lines changed

2 files changed

+70
-37
lines changed

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

+9-32
Original file line numberDiff line numberDiff line change
@@ -2465,40 +2465,17 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
24652465
pub fn insert(self, value: V) -> &'a mut V {
24662466
*self.length += 1;
24672467

2468-
let out_ptr;
2469-
2470-
let mut ins_k;
2471-
let mut ins_v;
2472-
let mut ins_edge;
2473-
2474-
let mut cur_parent = match self.handle.insert(self.key, value) {
2475-
(Fit(handle), _) => return handle.into_kv_mut().1,
2476-
(Split(left, k, v, right), ptr) => {
2477-
ins_k = k;
2478-
ins_v = v;
2479-
ins_edge = right;
2480-
out_ptr = ptr;
2481-
left.ascend().map_err(|n| n.into_root_mut())
2468+
let out_ptr = match self.handle.insert_recursing(self.key, value) {
2469+
(Fit(_), val_ptr) => val_ptr,
2470+
(Split(ins), val_ptr) => {
2471+
let root = ins.left.into_root_mut();
2472+
root.push_internal_level().push(ins.k, ins.v, ins.right);
2473+
val_ptr
24822474
}
24832475
};
2484-
2485-
loop {
2486-
match cur_parent {
2487-
Ok(parent) => match parent.insert(ins_k, ins_v, ins_edge) {
2488-
Fit(_) => return unsafe { &mut *out_ptr },
2489-
Split(left, k, v, right) => {
2490-
ins_k = k;
2491-
ins_v = v;
2492-
ins_edge = right;
2493-
cur_parent = left.ascend().map_err(|n| n.into_root_mut());
2494-
}
2495-
},
2496-
Err(root) => {
2497-
root.push_internal_level().push(ins_k, ins_v, ins_edge);
2498-
return unsafe { &mut *out_ptr };
2499-
}
2500-
}
2501-
}
2476+
// Now that we have finished growing the tree using borrowed references,
2477+
// dereference the pointer to a part of it, that we picked up along the way.
2478+
unsafe { &mut *out_ptr }
25022479
}
25032480
}
25042481

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

+61-5
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
843843
/// this edge. This method splits the node if there isn't enough room.
844844
///
845845
/// The returned pointer points to the inserted value.
846-
pub fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) {
846+
fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) {
847847
if self.node.len() < CAPACITY {
848848
let ptr = self.insert_fit(key, val);
849849
let kv = unsafe { Handle::new_kv(self.node, self.idx) };
@@ -862,7 +862,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
862862
.insert_fit(key, val)
863863
}
864864
};
865-
(InsertResult::Split(left, k, v, right), ptr)
865+
(InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), ptr)
866866
}
867867
}
868868
}
@@ -918,7 +918,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
918918
/// Inserts a new key/value pair and an edge that will go to the right of that new pair
919919
/// between this edge and the key/value pair to the right of this edge. This method splits
920920
/// the node if there isn't enough room.
921-
pub fn insert(
921+
fn insert(
922922
mut self,
923923
key: K,
924924
val: V,
@@ -946,7 +946,43 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
946946
.insert_fit(key, val, edge);
947947
}
948948
}
949-
InsertResult::Split(left, k, v, right)
949+
InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right })
950+
}
951+
}
952+
}
953+
954+
impl<'a, K: 'a, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
955+
/// Inserts a new key/value pair between the key/value pairs to the right and left of
956+
/// this edge. This method splits the node if there isn't enough room, and tries to
957+
/// insert the split off portion into the parent node recursively, until the root is reached.
958+
///
959+
/// If the returned result is a `Fit`, its handle's node can be this edge's node or an ancestor.
960+
/// If the returned result is a `Split`, the `left` field will be the root node.
961+
/// The returned pointer points to the inserted value.
962+
pub fn insert_recursing(
963+
self,
964+
key: K,
965+
value: V,
966+
) -> (InsertResult<'a, K, V, marker::LeafOrInternal>, *mut V) {
967+
let (mut split, val_ptr) = match self.insert(key, value) {
968+
(InsertResult::Fit(handle), ptr) => {
969+
return (InsertResult::Fit(handle.forget_node_type()), ptr);
970+
}
971+
(InsertResult::Split(split), val_ptr) => (split, val_ptr),
972+
};
973+
974+
loop {
975+
split = match split.left.ascend() {
976+
Ok(parent) => match parent.insert(split.k, split.v, split.right) {
977+
InsertResult::Fit(handle) => {
978+
return (InsertResult::Fit(handle.forget_node_type()), val_ptr);
979+
}
980+
InsertResult::Split(split) => split,
981+
},
982+
Err(root) => {
983+
return (InsertResult::Split(SplitResult { left: root, ..split }), val_ptr);
984+
}
985+
};
950986
}
951987
}
952988
}
@@ -1389,6 +1425,14 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::K
13891425
}
13901426
}
13911427

1428+
impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::KV> {
1429+
pub fn forget_node_type(
1430+
self,
1431+
) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
1432+
unsafe { Handle::new_kv(self.node.forget_type(), self.idx) }
1433+
}
1434+
}
1435+
13921436
impl<BorrowType, K, V, HandleType>
13931437
Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, HandleType>
13941438
{
@@ -1455,9 +1499,21 @@ pub enum ForceResult<Leaf, Internal> {
14551499
Internal(Internal),
14561500
}
14571501

1502+
/// Result of insertion, when a node needed to expand beyond its capacity.
1503+
/// Does not distinguish between `Leaf` and `Internal` because `Root` doesn't.
1504+
pub struct SplitResult<'a, K, V> {
1505+
// Altered node in existing tree with elements and edges that belong to the left of `k`.
1506+
pub left: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
1507+
// Some key and value split off, to be inserted elsewhere.
1508+
pub k: K,
1509+
pub v: V,
1510+
// Owned, unattached, new node with elements and edges that belong to the right of `k`.
1511+
pub right: Root<K, V>,
1512+
}
1513+
14581514
pub enum InsertResult<'a, K, V, Type> {
14591515
Fit(Handle<NodeRef<marker::Mut<'a>, K, V, Type>, marker::KV>),
1460-
Split(NodeRef<marker::Mut<'a>, K, V, Type>, K, V, Root<K, V>),
1516+
Split(SplitResult<'a, K, V>),
14611517
}
14621518

14631519
pub mod marker {

0 commit comments

Comments
 (0)