Skip to content

Commit 5c02926

Browse files
committed
Auto merge of #84904 - ssomers:btree_drop_kv_in_place, r=Mark-Simulacrum
BTree: no longer copy keys and values before dropping them When dropping BTreeMap or BTreeSet instances, keys-value pairs are up to now each copied and then dropped, at least according to source code. This is because the code for dropping and for iterators is shared. This PR postpones the treatment of doomed key-value pairs from the intermediate functions `deallocating_next`(`_back`) to the last minute, so the we can drop the keys and values in place. According to the library/alloc benchmarks, this does make a difference, (and a positive difference with an `#[inline]` on `drop_key_val`). It does not change anything for #81444 though. r? `@Mark-Simulacrum`
2 parents ba8d7e2 + 728204b commit 5c02926

File tree

3 files changed

+95
-45
lines changed

3 files changed

+95
-45
lines changed

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

+15-6
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,10 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
14391439
impl<K, V> Drop for Dropper<K, V> {
14401440
fn drop(&mut self) {
14411441
// Similar to advancing a non-fusing iterator.
1442-
fn next_or_end<K, V>(this: &mut Dropper<K, V>) -> Option<(K, V)> {
1442+
fn next_or_end<K, V>(
1443+
this: &mut Dropper<K, V>,
1444+
) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>>
1445+
{
14431446
if this.remaining_length == 0 {
14441447
unsafe { ptr::read(&this.front).deallocating_end() }
14451448
None
@@ -1455,13 +1458,15 @@ impl<K, V> Drop for Dropper<K, V> {
14551458
fn drop(&mut self) {
14561459
// Continue the same loop we perform below. This only runs when unwinding, so we
14571460
// don't have to care about panics this time (they'll abort).
1458-
while let Some(_pair) = next_or_end(&mut self.0) {}
1461+
while let Some(kv) = next_or_end(&mut self.0) {
1462+
kv.drop_key_val();
1463+
}
14591464
}
14601465
}
14611466

1462-
while let Some(pair) = next_or_end(self) {
1467+
while let Some(kv) = next_or_end(self) {
14631468
let guard = DropGuard(self);
1464-
drop(pair);
1469+
kv.drop_key_val();
14651470
mem::forget(guard);
14661471
}
14671472
}
@@ -1485,7 +1490,9 @@ impl<K, V> Iterator for IntoIter<K, V> {
14851490
None
14861491
} else {
14871492
self.length -= 1;
1488-
Some(unsafe { self.range.front.as_mut().unwrap().deallocating_next_unchecked() })
1493+
let front = self.range.front.as_mut().unwrap();
1494+
let kv = unsafe { front.deallocating_next_unchecked() };
1495+
Some(kv.into_key_val())
14891496
}
14901497
}
14911498

@@ -1501,7 +1508,9 @@ impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
15011508
None
15021509
} else {
15031510
self.length -= 1;
1504-
Some(unsafe { self.range.back.as_mut().unwrap().deallocating_next_back_unchecked() })
1511+
let back = self.range.back.as_mut().unwrap();
1512+
let kv = unsafe { back.deallocating_next_back_unchecked() };
1513+
Some(kv.into_key_val())
15051514
}
15061515
}
15071516
}

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

+44-36
Original file line numberDiff line numberDiff line change
@@ -237,25 +237,27 @@ impl<BorrowType: marker::BorrowType, K, V>
237237

238238
impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> {
239239
/// Given a leaf edge handle into a dying tree, returns the next leaf edge
240-
/// on the right side, and the key-value pair in between, which is either
241-
/// in the same leaf node, in an ancestor node, or non-existent.
240+
/// on the right side, and the key-value pair in between, if they exist.
242241
///
243-
/// This method also deallocates any node(s) it reaches the end of. This
244-
/// implies that if no more key-value pair exists, the entire remainder of
245-
/// the tree will have been deallocated and there is nothing left to return.
242+
/// If the given edge is the last one in a leaf, this method deallocates
243+
/// the leaf, as well as any ancestor nodes whose last edge was reached.
244+
/// This implies that if no more key-value pair follows, the entire tree
245+
/// will have been deallocated and there is nothing left to return.
246246
///
247247
/// # Safety
248-
/// The given edge must not have been previously returned by counterpart
249-
/// `deallocating_next_back`.
250-
unsafe fn deallocating_next(self) -> Option<(Self, (K, V))> {
248+
/// - The given edge must not have been previously returned by counterpart
249+
/// `deallocating_next_back`.
250+
/// - The returned KV handle is only valid to access the key and value,
251+
/// and only valid until the next call to this method or counterpart
252+
/// `deallocating_next_back`.
253+
pub unsafe fn deallocating_next(
254+
self,
255+
) -> Option<(Self, Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>)>
256+
{
251257
let mut edge = self.forget_node_type();
252258
loop {
253259
edge = match edge.right_kv() {
254-
Ok(kv) => {
255-
let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
256-
let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
257-
return Some((kv.next_leaf_edge(), (k, v)));
258-
}
260+
Ok(kv) => return Some((unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)),
259261
Err(last_edge) => match unsafe { last_edge.into_node().deallocate_and_ascend() } {
260262
Some(parent_edge) => parent_edge.forget_node_type(),
261263
None => return None,
@@ -265,25 +267,27 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> {
265267
}
266268

267269
/// Given a leaf edge handle into a dying tree, returns the next leaf edge
268-
/// on the left side, and the key-value pair in between, which is either
269-
/// in the same leaf node, in an ancestor node, or non-existent.
270+
/// on the left side, and the key-value pair in between, if they exist.
270271
///
271-
/// This method also deallocates any node(s) it reaches the end of. This
272-
/// implies that if no more key-value pair exists, the entire remainder of
273-
/// the tree will have been deallocated and there is nothing left to return.
272+
/// If the given edge is the first one in a leaf, this method deallocates
273+
/// the leaf, as well as any ancestor nodes whose first edge was reached.
274+
/// This implies that if no more key-value pair follows, the entire tree
275+
/// will have been deallocated and there is nothing left to return.
274276
///
275277
/// # Safety
276-
/// The given edge must not have been previously returned by counterpart
277-
/// `deallocating_next`.
278-
unsafe fn deallocating_next_back(self) -> Option<(Self, (K, V))> {
278+
/// - The given edge must not have been previously returned by counterpart
279+
/// `deallocating_next`.
280+
/// - The returned KV handle is only valid to access the key and value,
281+
/// and only valid until the next call to this method or counterpart
282+
/// `deallocating_next`.
283+
unsafe fn deallocating_next_back(
284+
self,
285+
) -> Option<(Self, Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>)>
286+
{
279287
let mut edge = self.forget_node_type();
280288
loop {
281289
edge = match edge.left_kv() {
282-
Ok(kv) => {
283-
let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
284-
let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
285-
return Some((kv.next_back_leaf_edge(), (k, v)));
286-
}
290+
Ok(kv) => return Some((unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)),
287291
Err(last_edge) => match unsafe { last_edge.into_node().deallocate_and_ascend() } {
288292
Some(parent_edge) => parent_edge.forget_node_type(),
289293
None => return None,
@@ -373,13 +377,15 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> {
373377
///
374378
/// # Safety
375379
/// - There must be another KV in the direction travelled.
376-
/// - That KV was not previously returned by counterpart `next_back_unchecked`
377-
/// on any copy of the handles being used to traverse the tree.
380+
/// - That KV was not previously returned by counterpart
381+
/// `deallocating_next_back_unchecked` on any copy of the handles
382+
/// being used to traverse the tree.
378383
///
379384
/// The only safe way to proceed with the updated handle is to compare it, drop it,
380-
/// call this method again subject to its safety conditions, or call counterpart
381-
/// `next_back_unchecked` subject to its safety conditions.
382-
pub unsafe fn deallocating_next_unchecked(&mut self) -> (K, V) {
385+
/// or call this method or counterpart `deallocating_next_back_unchecked` again.
386+
pub unsafe fn deallocating_next_unchecked(
387+
&mut self,
388+
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
383389
super::mem::replace(self, |leaf_edge| unsafe {
384390
leaf_edge.deallocating_next().unwrap_unchecked()
385391
})
@@ -391,13 +397,15 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> {
391397
///
392398
/// # Safety
393399
/// - There must be another KV in the direction travelled.
394-
/// - That leaf edge was not previously returned by counterpart `next_unchecked`
395-
/// on any copy of the handles being used to traverse the tree.
400+
/// - That leaf edge was not previously returned by counterpart
401+
/// `deallocating_next_unchecked` on any copy of the handles
402+
/// being used to traverse the tree.
396403
///
397404
/// The only safe way to proceed with the updated handle is to compare it, drop it,
398-
/// call this method again subject to its safety conditions, or call counterpart
399-
/// `next_unchecked` subject to its safety conditions.
400-
pub unsafe fn deallocating_next_back_unchecked(&mut self) -> (K, V) {
405+
/// or call this method or counterpart `deallocating_next_unchecked` again.
406+
pub unsafe fn deallocating_next_back_unchecked(
407+
&mut self,
408+
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
401409
super::mem::replace(self, |leaf_edge| unsafe {
402410
leaf_edge.deallocating_next_back().unwrap_unchecked()
403411
})

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

+36-3
Original file line numberDiff line numberDiff line change
@@ -422,21 +422,30 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
422422
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
423423
}
424424

425-
/// Borrows exclusive access to the leaf portion of any leaf or internal node.
425+
/// Borrows exclusive access to the leaf portion of a leaf or internal node.
426426
fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
427427
let ptr = Self::as_leaf_ptr(self);
428428
// SAFETY: we have exclusive access to the entire node.
429429
unsafe { &mut *ptr }
430430
}
431431

432-
/// Offers exclusive access to the leaf portion of any leaf or internal node.
432+
/// Offers exclusive access to the leaf portion of a leaf or internal node.
433433
fn into_leaf_mut(mut self) -> &'a mut LeafNode<K, V> {
434434
let ptr = Self::as_leaf_ptr(&mut self);
435435
// SAFETY: we have exclusive access to the entire node.
436436
unsafe { &mut *ptr }
437437
}
438438
}
439439

440+
impl<K, V, Type> NodeRef<marker::Dying, K, V, Type> {
441+
/// Borrows exclusive access to the leaf portion of a dying leaf or internal node.
442+
fn as_leaf_dying(&mut self) -> &mut LeafNode<K, V> {
443+
let ptr = Self::as_leaf_ptr(self);
444+
// SAFETY: we have exclusive access to the entire node.
445+
unsafe { &mut *ptr }
446+
}
447+
}
448+
440449
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
441450
/// Borrows exclusive access to an element of the key storage area.
442451
///
@@ -1040,13 +1049,37 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
10401049
}
10411050
}
10421051

1043-
/// Replace the key and value that the KV handle refers to.
1052+
/// Replaces the key and value that the KV handle refers to.
10441053
pub fn replace_kv(&mut self, k: K, v: V) -> (K, V) {
10451054
let (key, val) = self.kv_mut();
10461055
(mem::replace(key, k), mem::replace(val, v))
10471056
}
10481057
}
10491058

1059+
impl<K, V, NodeType> Handle<NodeRef<marker::Dying, K, V, NodeType>, marker::KV> {
1060+
/// Extracts the key and value that the KV handle refers to.
1061+
pub fn into_key_val(mut self) -> (K, V) {
1062+
debug_assert!(self.idx < self.node.len());
1063+
let leaf = self.node.as_leaf_dying();
1064+
unsafe {
1065+
let key = leaf.keys.get_unchecked_mut(self.idx).assume_init_read();
1066+
let val = leaf.vals.get_unchecked_mut(self.idx).assume_init_read();
1067+
(key, val)
1068+
}
1069+
}
1070+
1071+
/// Drops the key and value that the KV handle refers to.
1072+
#[inline]
1073+
pub fn drop_key_val(mut self) {
1074+
debug_assert!(self.idx < self.node.len());
1075+
let leaf = self.node.as_leaf_dying();
1076+
unsafe {
1077+
leaf.keys.get_unchecked_mut(self.idx).assume_init_drop();
1078+
leaf.vals.get_unchecked_mut(self.idx).assume_init_drop();
1079+
}
1080+
}
1081+
}
1082+
10501083
impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
10511084
/// Helps implementations of `split` for a particular `NodeType`,
10521085
/// by taking care of leaf data.

0 commit comments

Comments
 (0)