use bitvec::vec::BitVec;
use rustc_hash::FxHashSet;
use std::hash::Hash;
#[derive(Debug, Default)]
pub(crate) struct BitmapSet<T>
where
T: Default + Copy + PartialEq + Eq + Hash,
{
items: Vec<(usize, T)>,
set: FxHashSet<(usize, T)>,
p_bitmap: BitVec<usize>,
n_bitmap: BitVec<usize>,
}
impl<T> BitmapSet<T>
where
T: Default + Copy + PartialEq + Eq + Hash,
{
pub const MAX_OFFSET: usize = 524288;
pub fn new() -> Self {
Self {
items: Vec::new(),
set: FxHashSet::default(),
p_bitmap: BitVec::repeat(false, 1024),
n_bitmap: BitVec::repeat(false, 1024),
}
}
#[inline]
pub fn insert(&mut self, key: usize, value: T) -> bool {
let first = match self.items.first() {
Some(first) => first,
None => {
self.items.push((key, value));
return true;
}
};
if first.0 == key && first.1 == value {
return false;
}
let offset = key as isize - first.0 as isize;
match offset {
offset if offset < 0 => {
let offset = (-offset as usize) - 1;
unsafe {
if self.n_bitmap.len() <= offset {
assert!(offset < Self::MAX_OFFSET);
self.n_bitmap.resize(offset + 1, false);
self.n_bitmap.set_unchecked(offset, true);
self.items.push((key, value));
self.set.insert((key, value))
} else if !*self.n_bitmap.get_unchecked(offset) {
self.n_bitmap.set_unchecked(offset, true);
self.items.push((key, value));
self.set.insert((key, value))
} else if self.set.insert((key, value)) {
self.items.push((key, value));
true
} else {
false
}
}
}
offset => {
let offset = offset as usize;
unsafe {
if self.p_bitmap.len() <= offset {
assert!(offset < Self::MAX_OFFSET);
self.p_bitmap.resize(offset + 1, false);
self.p_bitmap.set_unchecked(offset, true);
self.items.push((key, value));
self.set.insert((key, value))
} else if !*self.p_bitmap.get_unchecked(offset) {
self.p_bitmap.set_unchecked(offset, true);
self.items.push((key, value));
self.set.insert((key, value))
} else if self.set.insert((key, value)) {
self.items.push((key, value));
true
} else {
false
}
}
}
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[inline]
pub fn clear(&mut self) {
let first_key = match self.items.first() {
Some(first) => first.0,
None => return,
};
for (key, _) in self.items.drain(0..) {
let offset = key as isize - first_key as isize;
match offset {
offset if offset < 0 => {
self.n_bitmap.set(((-offset) as usize) - 1, false);
}
offset => {
self.p_bitmap.set(offset as usize, false);
}
}
}
self.set.clear();
}
pub fn iter(&self) -> impl Iterator<Item = &(usize, T)> {
self.items.iter()
}
}
#[cfg(test)]
mod tests {
use super::BitmapSet;
#[test]
fn thread_set() {
let mut s = BitmapSet::new();
assert!(s.insert(4, 0));
assert!(s.insert(2, 0));
assert!(s.insert(3, 0));
assert!(s.insert(10, 0));
assert!(s.insert(0, 0));
assert!(s.insert(2000, 0));
assert!(!s.insert(4, 0));
assert!(!s.insert(2, 0));
assert!(!s.insert(3, 0));
assert!(!s.insert(10, 0));
assert!(!s.insert(0, 0));
assert!(!s.insert(2000, 0));
assert!(s.insert(4, 1));
assert!(!s.insert(4, 1));
assert_eq!(
s.items,
vec![(4, 0), (2, 0), (3, 0), (10, 0), (0, 0), (2000, 0), (4, 1)]
);
s.clear();
assert_eq!(s.p_bitmap.count_ones(), 0);
assert_eq!(s.n_bitmap.count_ones(), 0);
assert!(s.insert(200, 0));
assert!(s.insert(3, 0));
assert!(s.insert(10, 0));
assert!(s.insert(300, 0));
assert!(s.insert(250, 0));
assert_eq!(
s.items,
vec![(200, 0), (3, 0), (10, 0), (300, 0), (250, 0)]
);
}
}