Rollup merge of #40739 - cuviper:hash-rev-drop, r=arthurprs
Simplify hash table drops
This replaces the `std::collections:#️⃣: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.
This commit is contained in:
commit
dd9e5892f4
1 changed files with 18 additions and 47 deletions
|
|
@ -896,15 +896,23 @@ impl<K, V> RawTable<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator that copies out each entry. Used while the table
|
||||
/// is being dropped.
|
||||
unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets<K, V> {
|
||||
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<K, V>,
|
||||
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<K, V> {
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue