Skip to content

Commit 728204b

Browse files
committed
BTree: no longer copy keys and values before dropping them
1 parent 1773f14 commit 728204b

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)