Skip to content

Commit

Permalink
Use RawTable::get_many_mut for safe swap_indices
Browse files Browse the repository at this point in the history
  • Loading branch information
cuviper committed Sep 6, 2023
1 parent 0604c5b commit 8e03753
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 23 deletions.
20 changes: 20 additions & 0 deletions src/map/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,26 @@ impl<K, V> IndexMapCore<K, V> {
}
}

pub(crate) fn swap_indices(&mut self, a: usize, b: usize) {
// If they're equal and in-bounds, there's nothing to do.
if a == b && a < self.entries.len() {
return;
}

// We'll get a "nice" bounds-check from indexing `self.entries`,
// and then we expect to find it in the table as well.
let [ref_a, ref_b] = self
.indices
.get_many_mut(
[self.entries[a].hash.get(), self.entries[b].hash.get()],
move |i, &x| if i == 0 { x == a } else { x == b },
)
.expect("indices not found");

mem::swap(ref_a, ref_b);
self.entries.swap(a, b);
}

/// Remove an entry by swapping it with the last
pub(crate) fn swap_remove_full<Q>(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)>
where
Expand Down
23 changes: 0 additions & 23 deletions src/map/core/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,29 +100,6 @@ impl<K, V> IndexMapCore<K, V> {
// only the item references that are appropriately bound to `&mut self`.
unsafe { self.indices.iter().map(|bucket| bucket.as_mut()) }
}

/// Return the raw bucket for the given index
fn find_index(&self, index: usize) -> RawBucket {
// We'll get a "nice" bounds-check from indexing `self.entries`,
// and then we expect to find it in the table as well.
let hash = self.entries[index].hash.get();
self.indices
.find(hash, move |&i| i == index)
.expect("index not found")
}

pub(crate) fn swap_indices(&mut self, a: usize, b: usize) {
// SAFETY: Can't take two `get_mut` references from one table, so we
// must use raw buckets to do the swap. This is still safe because we
// are locally sure they won't dangle, and we write them individually.
unsafe {
let raw_bucket_a = self.find_index(a);
let raw_bucket_b = self.find_index(b);
*raw_bucket_a.as_mut() = b;
*raw_bucket_b.as_mut() = a;
}
self.entries.swap(a, b);
}
}

/// A view into an occupied entry in a `IndexMap`.
Expand Down

0 comments on commit 8e03753

Please sign in to comment.