Skip to content

Commit

Permalink
Auto merge of #354 - braddunbar:is-full, r=Amanieu
Browse files Browse the repository at this point in the history
Add RawTable#is_full

There's currently no way to tell  if a particular bucket is full. This can be handy for choosing a random element or iterating over a hash table in a specific order of buckets, so I've added the `is_full` function to RawTable.
  • Loading branch information
bors committed Sep 8, 2022
2 parents 1604045 + 1721ec5 commit 2784682
Showing 1 changed file with 26 additions and 5 deletions.
31 changes: 26 additions & 5 deletions src/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ impl<T, A: Allocator + Clone> RawTable<T, A> {
{
let index = self.bucket_index(&bucket);
let old_ctrl = *self.table.ctrl(index);
debug_assert!(is_full(old_ctrl));
debug_assert!(self.is_bucket_full(index));
let old_growth_left = self.table.growth_left;
let item = self.remove(bucket);
if let Some(new_item) = f(item) {
Expand Down Expand Up @@ -928,6 +928,16 @@ impl<T, A: Allocator + Clone> RawTable<T, A> {
self.table.bucket_mask + 1
}

/// Checks whether the bucket at `index` is full.
///
/// # Safety
///
/// The caller must ensure `index` is less than the number of buckets.
#[inline]
pub unsafe fn is_bucket_full(&self, index: usize) -> bool {
self.table.is_bucket_full(index)
}

/// Returns an iterator over every element in the table. It is up to
/// the caller to ensure that the `RawTable` outlives the `RawIter`.
/// Because we cannot make the `next` method unsafe on the `RawIter`
Expand Down Expand Up @@ -1148,7 +1158,7 @@ impl<A: Allocator + Clone> RawTableInner<A> {
// table. This second scan is guaranteed to find an empty
// slot (due to the load factor) before hitting the trailing
// control bytes (containing EMPTY).
if unlikely(is_full(*self.ctrl(result))) {
if unlikely(self.is_bucket_full(result)) {
debug_assert!(self.bucket_mask < Group::WIDTH);
debug_assert_ne!(probe_seq.pos, 0);
return Group::load_aligned(self.ctrl(0))
Expand Down Expand Up @@ -1329,6 +1339,17 @@ impl<A: Allocator + Clone> RawTableInner<A> {
self.bucket_mask + 1
}

/// Checks whether the bucket at `index` is full.
///
/// # Safety
///
/// The caller must ensure `index` is less than the number of buckets.
#[inline]
unsafe fn is_bucket_full(&self, index: usize) -> bool {
debug_assert!(index < self.buckets());
is_full(*self.ctrl(index))
}

#[inline]
fn num_ctrl_bytes(&self) -> usize {
self.bucket_mask + 1 + Group::WIDTH
Expand Down Expand Up @@ -1427,7 +1448,7 @@ impl<A: Allocator + Clone> RawTableInner<A> {

// Copy all elements to the new table.
for i in 0..self.buckets() {
if !is_full(*self.ctrl(i)) {
if !self.is_bucket_full(i) {
continue;
}

Expand Down Expand Up @@ -1573,7 +1594,7 @@ impl<A: Allocator + Clone> RawTableInner<A> {

#[inline]
unsafe fn erase(&mut self, index: usize) {
debug_assert!(is_full(*self.ctrl(index)));
debug_assert!(self.is_bucket_full(index));
let index_before = index.wrapping_sub(Group::WIDTH) & self.bucket_mask;
let empty_before = Group::load(self.ctrl(index_before)).match_empty();
let empty_after = Group::load(self.ctrl(index)).match_empty();
Expand Down Expand Up @@ -1723,7 +1744,7 @@ impl<T: Clone, A: Allocator + Clone> RawTable<T, A> {
let mut guard = guard((0, &mut *self), |(index, self_)| {
if mem::needs_drop::<T>() && !self_.is_empty() {
for i in 0..=*index {
if is_full(*self_.table.ctrl(i)) {
if self_.is_bucket_full(i) {
self_.bucket(i).drop();
}
}
Expand Down

0 comments on commit 2784682

Please sign in to comment.