use crate::table::HashIndex;
pub struct MultiBucketGuard<'a> {
pub(crate) index: &'a HashIndex,
pub(crate) stack: [(usize, bool); HashIndex::INLINE_LOCK_ENTRIES],
pub(crate) len: usize,
pub(crate) extra: Vec<(usize, bool)>,
}
impl<'a> MultiBucketGuard<'a> {
pub const INLINE_CAPACITY: usize = HashIndex::INLINE_LOCK_ENTRIES;
#[inline]
pub fn new(index: &'a HashIndex) -> Self {
Self {
index,
stack: [(0, false); Self::INLINE_CAPACITY],
len: 0,
extra: Vec::new(),
}
}
#[inline]
pub(crate) fn from_slice(index: &'a HashIndex, entries: &[(usize, bool)]) -> Self {
let count = entries.len();
if count <= Self::INLINE_CAPACITY {
let mut stack = [(0, false); Self::INLINE_CAPACITY];
stack[..count].copy_from_slice(entries);
Self {
index,
stack,
len: count,
extra: Vec::new(),
}
} else {
let mut stack = [(0, false); Self::INLINE_CAPACITY];
stack.copy_from_slice(&entries[..Self::INLINE_CAPACITY]);
Self {
index,
stack,
len: Self::INLINE_CAPACITY,
extra: entries[Self::INLINE_CAPACITY..].to_vec(),
}
}
}
#[inline]
pub fn len(&self) -> usize {
self.len + self.extra.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &(usize, bool)> {
self.stack[..self.len].iter().chain(self.extra.iter())
}
}
impl Drop for MultiBucketGuard<'_> {
fn drop(&mut self) {
for &(bucket_idx, is_exclusive) in self.iter().rev() {
let bucket = unsafe { self.index.buckets.get_unchecked(bucket_idx) };
if is_exclusive {
bucket.unlock_exclusive();
} else {
bucket.unlock_shared();
}
}
}
}