Skip to content

Commit dc3c8df

Browse files
committed
BTree: avoid most unsafe code in iterators
1 parent aa65b08 commit dc3c8df

File tree

2 files changed

+118
-135
lines changed

2 files changed

+118
-135
lines changed

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

+25-14
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use core::ops::{Index, RangeBounds};
99
use core::ptr;
1010

1111
use super::borrow::DormantMutRef;
12-
use super::navigate::LeafRange;
12+
use super::navigate::{deallocating_next_unchecked, LeafRange};
1313
use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
1414
use super::search::SearchResult::*;
1515

@@ -149,7 +149,10 @@ pub struct BTreeMap<K, V> {
149149
unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap<K, V> {
150150
fn drop(&mut self) {
151151
if let Some(root) = self.root.take() {
152-
Dropper { front: root.into_dying().first_leaf_edge(), remaining_length: self.length };
152+
Dropper {
153+
front: Some(root.into_dying().first_leaf_edge()),
154+
remaining_length: self.length,
155+
};
153156
}
154157
}
155158
}
@@ -334,7 +337,7 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
334337
/// purpose: to drop the remainder of an `IntoIter`. Therefore it also serves to
335338
/// drop an entire tree without the need to first look up a `back` leaf edge.
336339
struct Dropper<K, V> {
337-
front: Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge>,
340+
front: Option<Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge>>,
338341
remaining_length: usize,
339342
}
340343

@@ -1298,7 +1301,9 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
12981301
None
12991302
} else {
13001303
self.length -= 1;
1301-
Some(unsafe { self.range.inner.next_unchecked() })
1304+
let result = self.range.inner.next_checked();
1305+
debug_assert!(result.is_some());
1306+
result
13021307
}
13031308
}
13041309

@@ -1329,7 +1334,9 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
13291334
None
13301335
} else {
13311336
self.length -= 1;
1332-
Some(unsafe { self.range.inner.next_back_unchecked() })
1337+
let result = self.range.inner.next_back_checked();
1338+
debug_assert!(result.is_some());
1339+
result
13331340
}
13341341
}
13351342
}
@@ -1367,7 +1374,9 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
13671374
None
13681375
} else {
13691376
self.length -= 1;
1370-
Some(unsafe { self.range.inner.next_unchecked() })
1377+
let result = self.range.inner.next_checked();
1378+
debug_assert!(result.is_some());
1379+
result
13711380
}
13721381
}
13731382

@@ -1395,7 +1404,9 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
13951404
None
13961405
} else {
13971406
self.length -= 1;
1398-
Some(unsafe { self.range.inner.next_back_unchecked() })
1407+
let result = self.range.inner.next_back_checked();
1408+
debug_assert!(result.is_some());
1409+
result
13991410
}
14001411
}
14011412
}
@@ -1443,11 +1454,13 @@ impl<K, V> Drop for Dropper<K, V> {
14431454
) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>>
14441455
{
14451456
if this.remaining_length == 0 {
1446-
unsafe { ptr::read(&this.front).deallocating_end() }
1457+
if let Some(front) = this.front.take() {
1458+
front.deallocating_end();
1459+
}
14471460
None
14481461
} else {
14491462
this.remaining_length -= 1;
1450-
Some(unsafe { this.front.deallocating_next_unchecked() })
1463+
unsafe { deallocating_next_unchecked(&mut this.front) }
14511464
}
14521465
}
14531466

@@ -1474,9 +1487,7 @@ impl<K, V> Drop for Dropper<K, V> {
14741487
#[stable(feature = "btree_drop", since = "1.7.0")]
14751488
impl<K, V> Drop for IntoIter<K, V> {
14761489
fn drop(&mut self) {
1477-
if let Some(front) = self.range.take_front() {
1478-
Dropper { front, remaining_length: self.length };
1479-
}
1490+
Dropper { front: self.range.take_front(), remaining_length: self.length };
14801491
}
14811492
}
14821493

@@ -1490,7 +1501,7 @@ impl<K, V> Iterator for IntoIter<K, V> {
14901501
} else {
14911502
self.length -= 1;
14921503
let kv = unsafe { self.range.deallocating_next_unchecked() };
1493-
Some(kv.into_key_val())
1504+
Some(kv.unwrap().into_key_val())
14941505
}
14951506
}
14961507

@@ -1507,7 +1518,7 @@ impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
15071518
} else {
15081519
self.length -= 1;
15091520
let kv = unsafe { self.range.deallocating_next_back_unchecked() };
1510-
Some(kv.into_key_val())
1521+
Some(kv.unwrap().into_key_val())
15111522
}
15121523
}
15131524
}

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

+93-121
Original file line numberDiff line numberDiff line change
@@ -35,46 +35,42 @@ impl<BorrowType, K, V> LeafRange<BorrowType, K, V> {
3535
}
3636

3737
impl<'a, K, V> LeafRange<marker::Immut<'a>, K, V> {
38+
/// Moves the leaf edge handle to the next leaf edge and returns
39+
/// references to the key and value in between.
3840
#[inline]
3941
pub fn next_checked(&mut self) -> Option<(&'a K, &'a V)> {
40-
if self.is_empty() { None } else { Some(unsafe { self.next_unchecked() }) }
42+
if self.is_empty() { None } else { perform_next(&mut self.front, |kv| kv.into_kv()) }
4143
}
4244

45+
/// Moves the leaf edge handle to the previous leaf edge and returns
46+
/// references to the key and value in between.
4347
#[inline]
4448
pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> {
45-
if self.is_empty() { None } else { Some(unsafe { self.next_back_unchecked() }) }
46-
}
47-
48-
#[inline]
49-
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
50-
unsafe { self.front.as_mut().unwrap().next_unchecked() }
51-
}
52-
53-
#[inline]
54-
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
55-
unsafe { self.back.as_mut().unwrap().next_back_unchecked() }
49+
if self.is_empty() { None } else { perform_next_back(&mut self.back, |kv| kv.into_kv()) }
5650
}
5751
}
5852

5953
impl<'a, K, V> LeafRange<marker::ValMut<'a>, K, V> {
54+
/// Moves the leaf edge handle to the next leaf edge and returns
55+
/// references to the key and value in between.
6056
#[inline]
6157
pub fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> {
62-
if self.is_empty() { None } else { Some(unsafe { self.next_unchecked() }) }
58+
if self.is_empty() {
59+
None
60+
} else {
61+
perform_next(&mut self.front, |kv| unsafe { ptr::read(kv).into_kv_valmut() })
62+
}
6363
}
6464

65+
/// Moves the leaf edge handle to the previous leaf edge and returns
66+
/// references to the key and value in between.
6567
#[inline]
6668
pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> {
67-
if self.is_empty() { None } else { Some(unsafe { self.next_back_unchecked() }) }
68-
}
69-
70-
#[inline]
71-
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
72-
unsafe { self.front.as_mut().unwrap().next_unchecked() }
73-
}
74-
75-
#[inline]
76-
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
77-
unsafe { self.back.as_mut().unwrap().next_back_unchecked() }
69+
if self.is_empty() {
70+
None
71+
} else {
72+
perform_next_back(&mut self.back, |kv| unsafe { ptr::read(kv).into_kv_valmut() })
73+
}
7874
}
7975
}
8076

@@ -89,19 +85,15 @@ impl<K, V> LeafRange<marker::Dying, K, V> {
8985
#[inline]
9086
pub unsafe fn deallocating_next_unchecked(
9187
&mut self,
92-
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
93-
debug_assert!(self.front.is_some());
94-
let front = self.front.as_mut().unwrap();
95-
unsafe { front.deallocating_next_unchecked() }
88+
) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> {
89+
unsafe { deallocating_next_unchecked(&mut self.front) }
9690
}
9791

9892
#[inline]
9993
pub unsafe fn deallocating_next_back_unchecked(
10094
&mut self,
101-
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
102-
debug_assert!(self.back.is_some());
103-
let back = self.back.as_mut().unwrap();
104-
unsafe { back.deallocating_next_back_unchecked() }
95+
) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> {
96+
unsafe { deallocating_next_back_unchecked(&mut self.back) }
10597
}
10698
}
10799

@@ -388,100 +380,80 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> {
388380
}
389381
}
390382

391-
impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge> {
392-
/// Moves the leaf edge handle to the next leaf edge and returns references to the
393-
/// key and value in between.
394-
///
395-
/// # Safety
396-
/// There must be another KV in the direction travelled.
397-
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
398-
super::mem::replace(self, |leaf_edge| {
399-
let kv = leaf_edge.next_kv().ok().unwrap();
400-
(kv.next_leaf_edge(), kv.into_kv())
401-
})
402-
}
403-
404-
/// Moves the leaf edge handle to the previous leaf edge and returns references to the
405-
/// key and value in between.
406-
///
407-
/// # Safety
408-
/// There must be another KV in the direction travelled.
409-
unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
410-
super::mem::replace(self, |leaf_edge| {
411-
let kv = leaf_edge.next_back_kv().ok().unwrap();
412-
(kv.next_back_leaf_edge(), kv.into_kv())
413-
})
414-
}
383+
/// If possible, extract some result from the next KV and move to the edge beyond it.
384+
fn perform_next<BorrowType: marker::BorrowType, K, V, F, R>(
385+
front: &mut Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>,
386+
f: F,
387+
) -> Option<R>
388+
where
389+
F: Fn(&Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>) -> R,
390+
{
391+
super::mem::replace(front, |edge| {
392+
if let Some(kv) = edge.and_then(|edge| edge.next_kv().ok()) {
393+
let result = f(&kv);
394+
(Some(kv.next_leaf_edge()), Some(result))
395+
} else {
396+
(None, None)
397+
}
398+
})
415399
}
416400

417-
impl<'a, K, V> Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge> {
418-
/// Moves the leaf edge handle to the next leaf edge and returns references to the
419-
/// key and value in between.
420-
///
421-
/// # Safety
422-
/// There must be another KV in the direction travelled.
423-
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
424-
let kv = super::mem::replace(self, |leaf_edge| {
425-
let kv = leaf_edge.next_kv().ok().unwrap();
426-
(unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)
427-
});
428-
// Doing this last is faster, according to benchmarks.
429-
kv.into_kv_valmut()
430-
}
431-
432-
/// Moves the leaf edge handle to the previous leaf and returns references to the
433-
/// key and value in between.
434-
///
435-
/// # Safety
436-
/// There must be another KV in the direction travelled.
437-
unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
438-
let kv = super::mem::replace(self, |leaf_edge| {
439-
let kv = leaf_edge.next_back_kv().ok().unwrap();
440-
(unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)
441-
});
442-
// Doing this last is faster, according to benchmarks.
443-
kv.into_kv_valmut()
444-
}
401+
/// If possible, extract some result from the previous KV and move to the edge beyond it.
402+
fn perform_next_back<BorrowType: marker::BorrowType, K, V, F, R>(
403+
back: &mut Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>,
404+
f: F,
405+
) -> Option<R>
406+
where
407+
F: Fn(&Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>) -> R,
408+
{
409+
super::mem::replace(back, |edge| {
410+
if let Some(kv) = edge.and_then(|edge| edge.next_back_kv().ok()) {
411+
let result = f(&kv);
412+
(Some(kv.next_back_leaf_edge()), Some(result))
413+
} else {
414+
(None, None)
415+
}
416+
})
445417
}
446418

447-
impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> {
448-
/// Moves the leaf edge handle to the next leaf edge and returns the key and value
449-
/// in between, deallocating any node left behind while leaving the corresponding
450-
/// edge in its parent node dangling.
451-
///
452-
/// # Safety
453-
/// - There must be another KV in the direction travelled.
454-
/// - That KV was not previously returned by counterpart
455-
/// `deallocating_next_back_unchecked` on any copy of the handles
456-
/// being used to traverse the tree.
457-
///
458-
/// The only safe way to proceed with the updated handle is to compare it, drop it,
459-
/// or call this method or counterpart `deallocating_next_back_unchecked` again.
460-
pub unsafe fn deallocating_next_unchecked(
461-
&mut self,
462-
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
463-
super::mem::replace(self, |leaf_edge| unsafe { leaf_edge.deallocating_next().unwrap() })
464-
}
419+
/// Moves the leaf edge handle to the next leaf edge and returns the key and value
420+
/// in between, deallocating any node left behind while leaving the corresponding
421+
/// edge in its parent node dangling.
422+
///
423+
/// # Safety
424+
/// - The next KV, if any, was not previously returned by counterpart
425+
/// `deallocating_next_back_unchecked` on any copy of the handles
426+
/// being used to traverse the tree.
427+
///
428+
/// The only safe way to proceed with the updated handle is to compare it, drop it,
429+
/// or call this method or counterpart `deallocating_next_back_unchecked` again.
430+
pub unsafe fn deallocating_next_unchecked<K, V>(
431+
opt_hndl: &mut Option<Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge>>,
432+
) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> {
433+
super::mem::replace(opt_hndl, |edge| {
434+
edge.and_then(|edge| unsafe { edge.deallocating_next() })
435+
.map_or((None, None), |p| (Some(p.0), Some(p.1)))
436+
})
437+
}
465438

466-
/// Moves the leaf edge handle to the previous leaf edge and returns the key and value
467-
/// in between, deallocating any node left behind while leaving the corresponding
468-
/// edge in its parent node dangling.
469-
///
470-
/// # Safety
471-
/// - There must be another KV in the direction travelled.
472-
/// - That leaf edge was not previously returned by counterpart
473-
/// `deallocating_next_unchecked` on any copy of the handles
474-
/// being used to traverse the tree.
475-
///
476-
/// The only safe way to proceed with the updated handle is to compare it, drop it,
477-
/// or call this method or counterpart `deallocating_next_unchecked` again.
478-
unsafe fn deallocating_next_back_unchecked(
479-
&mut self,
480-
) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> {
481-
super::mem::replace(self, |leaf_edge| unsafe {
482-
leaf_edge.deallocating_next_back().unwrap()
483-
})
484-
}
439+
/// Moves the leaf edge handle to the previous leaf edge and returns the key and value
440+
/// in between, deallocating any node left behind while leaving the corresponding
441+
/// edge in its parent node dangling.
442+
///
443+
/// # Safety
444+
/// - The previous KV, if any, was not previously returned by counterpart
445+
/// `deallocating_next_unchecked` on any copy of the handles
446+
/// being used to traverse the tree.
447+
///
448+
/// The only safe way to proceed with the updated handle is to compare it, drop it,
449+
/// or call this method or counterpart `deallocating_next_unchecked` again.
450+
unsafe fn deallocating_next_back_unchecked<K, V>(
451+
opt_hndl: &mut Option<Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge>>,
452+
) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> {
453+
super::mem::replace(opt_hndl, |edge| {
454+
edge.and_then(|edge| unsafe { edge.deallocating_next_back() })
455+
.map_or((None, None), |p| (Some(p.0), Some(p.1)))
456+
})
485457
}
486458

487459
impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {

0 commit comments

Comments
 (0)