diff options
| author | Stein Somers <git@steinsomers.be> | 2020-04-22 13:06:24 +0200 |
|---|---|---|
| committer | Stein Somers <git@steinsomers.be> | 2020-04-25 00:05:10 +0200 |
| commit | 873022797ae7f09872738c7367d8d658a1a34ad5 (patch) | |
| tree | 5566d20651f18ec2bbd0cd4ab1d72ea54ba1529e /src/liballoc | |
| parent | 8f5c66c6a30cb770da3da953fa911b6c7a5769bb (diff) | |
| download | rust-873022797ae7f09872738c7367d8d658a1a34ad5.tar.gz rust-873022797ae7f09872738c7367d8d658a1a34ad5.zip | |
Speed up BTreeMap iteration by intertwined descend to the initial leaf edges
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/collections/btree/map.rs | 76 |
1 files changed, 47 insertions, 29 deletions
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<K, V> IntoIterator for BTreeMap<K, V> { fn into_iter(self) -> IntoIter<K, V> { 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<BorrowType, K, V, Q: ?Sized, R: RangeBounds<Q>>( root1: NodeRef<BorrowType, K, V, marker::LeafOrInternal>, root2: NodeRef<BorrowType, K, V, marker::LeafOrInternal>, @@ -2126,6 +2121,33 @@ where } } +/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound. +fn full_range_search<BorrowType, K, V>( + root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>, +) -> ( + Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>, + Handle<NodeRef<BorrowType, K, V, marker::Leaf>, 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<K, V> BTreeMap<K, V> { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2150,12 +2172,12 @@ impl<K, V> BTreeMap<K, V> { /// ``` #[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<K, V> BTreeMap<K, V> { /// ``` #[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 } } } |
