Skip to content

Commit 8730227

Browse files
committed
Speed up BTreeMap iteration by intertwined descend to the initial leaf edges
1 parent 8f5c66c commit 8730227

File tree

1 file changed

+47
-29
lines changed
  • src/liballoc/collections/btree

1 file changed

+47
-29
lines changed

src/liballoc/collections/btree/map.rs

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,16 +1545,10 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
15451545

15461546
fn into_iter(self) -> IntoIter<K, V> {
15471547
let mut me = ManuallyDrop::new(self);
1548-
if let Some(root) = me.root.as_mut() {
1549-
let root1 = unsafe { ptr::read(root).into_ref() };
1550-
let root2 = unsafe { ptr::read(root).into_ref() };
1551-
let len = me.length;
1552-
1553-
IntoIter {
1554-
front: Some(root1.first_leaf_edge()),
1555-
back: Some(root2.last_leaf_edge()),
1556-
length: len,
1557-
}
1548+
if let Some(root) = me.root.take() {
1549+
let (f, b) = full_range_search(root.into_ref());
1550+
1551+
IntoIter { front: Some(f), back: Some(b), length: me.length }
15581552
} else {
15591553
IntoIter { front: None, back: None, length: 0 }
15601554
}
@@ -2042,6 +2036,7 @@ where
20422036
}
20432037
}
20442038

2039+
/// Finds the leaf edges delimiting a specified range in or underneath a node.
20452040
fn range_search<BorrowType, K, V, Q: ?Sized, R: RangeBounds<Q>>(
20462041
root1: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
20472042
root2: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
@@ -2126,6 +2121,33 @@ where
21262121
}
21272122
}
21282123

2124+
/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound.
2125+
fn full_range_search<BorrowType, K, V>(
2126+
root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
2127+
) -> (
2128+
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
2129+
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
2130+
) {
2131+
// We duplicate the root NodeRef here -- we will never access it in a way
2132+
// that overlaps references obtained from the root.
2133+
let mut min_node = unsafe { ptr::read(&root) };
2134+
let mut max_node = root;
2135+
loop {
2136+
let front = min_node.first_edge();
2137+
let back = max_node.last_edge();
2138+
match (front.force(), back.force()) {
2139+
(Leaf(f), Leaf(b)) => {
2140+
return (f, b);
2141+
}
2142+
(Internal(min_int), Internal(max_int)) => {
2143+
min_node = min_int.descend();
2144+
max_node = max_int.descend();
2145+
}
2146+
_ => unreachable!("BTreeMap has different depths"),
2147+
};
2148+
}
2149+
}
2150+
21292151
impl<K, V> BTreeMap<K, V> {
21302152
/// Gets an iterator over the entries of the map, sorted by key.
21312153
///
@@ -2150,12 +2172,12 @@ impl<K, V> BTreeMap<K, V> {
21502172
/// ```
21512173
#[stable(feature = "rust1", since = "1.0.0")]
21522174
pub fn iter(&self) -> Iter<'_, K, V> {
2153-
Iter {
2154-
range: Range {
2155-
front: self.root.as_ref().map(|r| r.as_ref().first_leaf_edge()),
2156-
back: self.root.as_ref().map(|r| r.as_ref().last_leaf_edge()),
2157-
},
2158-
length: self.length,
2175+
if let Some(root) = &self.root {
2176+
let (f, b) = full_range_search(root.as_ref());
2177+
2178+
Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length }
2179+
} else {
2180+
Iter { range: Range { front: None, back: None }, length: 0 }
21592181
}
21602182
}
21612183

@@ -2182,19 +2204,15 @@ impl<K, V> BTreeMap<K, V> {
21822204
/// ```
21832205
#[stable(feature = "rust1", since = "1.0.0")]
21842206
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
2185-
IterMut {
2186-
range: if let Some(root) = &mut self.root {
2187-
let root1 = root.as_mut();
2188-
let root2 = unsafe { ptr::read(&root1) };
2189-
RangeMut {
2190-
front: Some(root1.first_leaf_edge()),
2191-
back: Some(root2.last_leaf_edge()),
2192-
_marker: PhantomData,
2193-
}
2194-
} else {
2195-
RangeMut { front: None, back: None, _marker: PhantomData }
2196-
},
2197-
length: self.length,
2207+
if let Some(root) = &mut self.root {
2208+
let (f, b) = full_range_search(root.as_mut());
2209+
2210+
IterMut {
2211+
range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData },
2212+
length: self.length,
2213+
}
2214+
} else {
2215+
IterMut { range: RangeMut { front: None, back: None, _marker: PhantomData }, length: 0 }
21982216
}
21992217
}
22002218

0 commit comments

Comments
 (0)