From 873022797ae7f09872738c7367d8d658a1a34ad5 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Wed, 22 Apr 2020 13:06:24 +0200 Subject: Speed up BTreeMap iteration by intertwined descend to the initial leaf edges --- src/liballoc/collections/btree/map.rs | 76 ++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 29 deletions(-) (limited to 'src/liballoc/collections') diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 91d93a1be1c..b3158c97bfc 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1545,16 +1545,10 @@ impl IntoIterator for BTreeMap { fn into_iter(self) -> IntoIter { let mut me = ManuallyDrop::new(self); - if let Some(root) = me.root.as_mut() { - let root1 = unsafe { ptr::read(root).into_ref() }; - let root2 = unsafe { ptr::read(root).into_ref() }; - let len = me.length; - - IntoIter { - front: Some(root1.first_leaf_edge()), - back: Some(root2.last_leaf_edge()), - length: len, - } + if let Some(root) = me.root.take() { + let (f, b) = full_range_search(root.into_ref()); + + IntoIter { front: Some(f), back: Some(b), length: me.length } } else { IntoIter { front: None, back: None, length: 0 } } @@ -2042,6 +2036,7 @@ where } } +/// Finds the leaf edges delimiting a specified range in or underneath a node. fn range_search>( root1: NodeRef, root2: NodeRef, @@ -2126,6 +2121,33 @@ where } } +/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound. +fn full_range_search( + root: NodeRef, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) { + // We duplicate the root NodeRef here -- we will never access it in a way + // that overlaps references obtained from the root. + let mut min_node = unsafe { ptr::read(&root) }; + let mut max_node = root; + loop { + let front = min_node.first_edge(); + let back = max_node.last_edge(); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + impl BTreeMap { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2150,12 +2172,12 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { - Iter { - range: Range { - front: self.root.as_ref().map(|r| r.as_ref().first_leaf_edge()), - back: self.root.as_ref().map(|r| r.as_ref().last_leaf_edge()), - }, - length: self.length, + if let Some(root) = &self.root { + let (f, b) = full_range_search(root.as_ref()); + + Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length } + } else { + Iter { range: Range { front: None, back: None }, length: 0 } } } @@ -2182,19 +2204,15 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { - IterMut { - range: if let Some(root) = &mut self.root { - let root1 = root.as_mut(); - let root2 = unsafe { ptr::read(&root1) }; - RangeMut { - front: Some(root1.first_leaf_edge()), - back: Some(root2.last_leaf_edge()), - _marker: PhantomData, - } - } else { - RangeMut { front: None, back: None, _marker: PhantomData } - }, - length: self.length, + if let Some(root) = &mut self.root { + let (f, b) = full_range_search(root.as_mut()); + + IterMut { + range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }, + length: self.length, + } + } else { + IterMut { range: RangeMut { front: None, back: None, _marker: PhantomData }, length: 0 } } } -- cgit 1.4.1-3-g733a5