From a033f1a8eeb55bdf93749a5d0c4d803bbe0d8dfc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 22 Mar 2017 10:32:38 -0700 Subject: [PATCH] Simplify hash table drops This replaces the `std::collections::hash::table::RevMoveBuckets` iterator with a simpler `while` loop. This iterator was only used for dropping the remaining elements of a `RawTable`, so instead we can just loop through directly and drop them in place. This should be functionally equivalent to the former code, but a little easier to read. I was hoping it might have some performance benefit too, but it seems the optimizer was already good enough to see through the iterator -- the generated code is nearly the same. Maybe it will still help if an element type has more complicated drop code. --- src/libstd/collections/hash/table.rs | 65 ++++++++-------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 211605bef1ee0..da5fb1a47333e 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -896,15 +896,23 @@ impl RawTable { } } - /// Returns an iterator that copies out each entry. Used while the table - /// is being dropped. - unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets { - let raw_bucket = self.first_bucket_raw(); - RevMoveBuckets { - raw: raw_bucket.offset(self.capacity as isize), - hashes_end: raw_bucket.hash, - elems_left: self.size, - marker: marker::PhantomData, + /// Drops buckets in reverse order. It leaves the table in an inconsistent + /// state and should only be used for dropping the table's remaining + /// entries. It's used in the implementation of Drop. + unsafe fn rev_drop_buckets(&mut self) { + let first_raw = self.first_bucket_raw(); + let mut raw = first_raw.offset(self.capacity as isize); + let mut elems_left = self.size; + + while elems_left != 0 { + debug_assert!(raw.hash != first_raw.hash); + + raw = raw.offset(-1); + + if *raw.hash != EMPTY_BUCKET { + elems_left -= 1; + ptr::drop_in_place(raw.pair as *mut (K, V)); + } } } @@ -964,43 +972,6 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { } } -/// An iterator that moves out buckets in reverse order. It leaves the table -/// in an inconsistent state and should only be used for dropping -/// the table's remaining entries. It's used in the implementation of Drop. -struct RevMoveBuckets<'a, K, V> { - raw: RawBucket, - hashes_end: *mut HashUint, - elems_left: usize, - - // As above, `&'a (K,V)` would seem better, but we often use - // 'static for the lifetime, and this is not a publicly exposed - // type. - marker: marker::PhantomData<&'a ()>, -} - -impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> { - type Item = (K, V); - - fn next(&mut self) -> Option<(K, V)> { - if self.elems_left == 0 { - return None; - } - - loop { - debug_assert!(self.raw.hash != self.hashes_end); - - unsafe { - self.raw = self.raw.offset(-1); - - if *self.raw.hash != EMPTY_BUCKET { - self.elems_left -= 1; - return Some(ptr::read(self.raw.pair)); - } - } - } - } -} - /// Iterator over shared references to entries in a table. pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, @@ -1227,7 +1198,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { unsafe { if needs_drop::<(K, V)>() { // avoid linear runtime for types that don't need drop - for _ in self.rev_move_buckets() {} + self.rev_drop_buckets(); } }