use super::{
digit::{AtomicDigit, Digit, BITS},
BitVec,
};
use std::fmt;
use std::sync::atomic::Ordering::Relaxed;
pub struct AtomicBitVec(pub Vec<AtomicDigit>);
impl AtomicBitVec {
#[inline]
pub fn zeros(n: usize) -> Self {
let (i, j) = (n / BITS, n % BITS);
let mut res = Self(Vec::with_capacity(i + (j > 0) as usize));
for _ in 0..i {
res.0.push(AtomicDigit::new(0));
}
if j > 0 {
res.0.push(AtomicDigit::new(0));
}
res
}
#[inline]
pub fn one(bit_index: usize, n: usize) -> Self {
let res = Self::zeros(n);
res.set_bit(bit_index, true);
res
}
#[inline]
pub fn set_bit(&self, index: usize, value: bool) {
let (i, j) = (index / BITS, index % BITS);
if value {
self.0[i].fetch_or(1 << j, Relaxed);
} else {
self.0[i].fetch_and(!(1 << j), Relaxed);
}
}
#[inline]
pub fn get_bit(&self, index: usize) -> bool {
let (i, j) = (index / BITS, index % BITS);
(self.0[i].load(Relaxed) & (1 << j)) != 0
}
#[inline]
pub fn is_zero(&self) -> bool {
self.0.iter().all(|x| x.load(Relaxed) == 0)
}
#[inline]
pub fn iter_ones(&self) -> IterOnes {
IterOnes {
data: self,
array_index: 0,
current: self.0[0].load(Relaxed),
}
}
#[inline]
pub fn iter_zeros(&self) -> IterZeros {
IterZeros {
data: self,
array_index: 0,
current: self.0[0].load(Relaxed),
}
}
#[inline]
pub fn clear(&self) {
self.0.iter().for_each(|x| x.store(0, Relaxed));
}
#[inline]
pub fn from_bitvec(bits: &BitVec, n: usize) -> Self {
let res = Self::zeros(n);
for (i, b) in bits.0.iter().enumerate() {
if *b == 0 {
continue;
}
res.0[i].store(*b, Relaxed);
}
res
}
#[inline]
pub fn into_bitvec(&self) -> BitVec {
let mut bits = BitVec(Vec::with_capacity(self.0.len()));
for a in &self.0 {
bits.0.push(a.load(Relaxed));
}
bits.normalize();
bits
}
#[inline]
pub fn assign_from(&self, rhs: &BitVec) {
for (a, b) in self.0.iter().zip(rhs.0.iter()) {
a.store(*b, Relaxed);
}
if self.0.len() > rhs.0.len() {
for a in self.0.iter().skip(rhs.0.len()) {
a.store(0, Relaxed);
}
}
}
pub fn truncate(&mut self, bit_len: usize) {
let (i, j) = (bit_len / BITS, bit_len % BITS);
self.0.truncate(i + (j > 0) as usize);
if j > 0 {
self.0[i].fetch_and(Digit::MAX >> (BITS - j), Relaxed);
}
}
}
impl AtomicBitVec {
pub fn eq(&self, other: &BitVec) -> bool {
if self.0.len() != other.0.len() {
return false;
}
self.0
.iter()
.zip(other.0.iter())
.all(|(a, b)| a.load(Relaxed) == *b)
}
pub fn bitor_assign(&self, rhs: &BitVec) {
for (a, b) in self.0.iter().zip(rhs.0.iter()) {
if *b != 0 {
a.fetch_or(*b, Relaxed);
}
}
}
pub fn bitor_assign_atomic(&self, rhs: &AtomicBitVec) {
for (a, b) in self.0.iter().zip(rhs.0.iter()) {
let b = b.load(Relaxed);
if b != 0 {
a.fetch_or(b, Relaxed);
}
}
}
}
impl fmt::Debug for AtomicBitVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AtomicBitVec(")?;
for i in (0..self.0.len()).rev() {
write!(f, "{:0>BITS$b}", self.0[i].load(Relaxed))?;
}
write!(f, ")")
}
}
pub struct IterOnes<'a> {
data: &'a AtomicBitVec,
array_index: usize,
current: Digit,
}
impl<'a> IterOnes<'a> {
pub fn chunks(self, chunk_size: usize) -> ChunkIter<Self> {
ChunkIter {
iter: self,
chunk_size,
done: false,
}
}
}
impl<'a> Iterator for IterOnes<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.current == 0 {
self.array_index += 1;
if self.array_index == self.data.0.len() {
return None;
}
self.current = self.data.0[self.array_index].load(Relaxed);
}
let trailing_zeros = self.current.trailing_zeros();
self.current &= !(1 << trailing_zeros);
Some(self.array_index * BITS + trailing_zeros as usize)
}
}
pub struct IterZeros<'a> {
data: &'a AtomicBitVec,
array_index: usize,
current: Digit,
}
impl<'a> IterZeros<'a> {
pub fn chunks(self, chunk_size: usize) -> ChunkIter<Self> {
ChunkIter {
iter: self,
chunk_size,
done: false,
}
}
}
impl<'a> Iterator for IterZeros<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.current == Digit::MAX {
self.array_index += 1;
if self.array_index == self.data.0.len() {
return None;
}
self.current = self.data.0[self.array_index].load(Relaxed);
}
let trailing_ones = self.current.trailing_ones();
self.current |= 1 << trailing_ones;
Some(self.array_index * BITS + trailing_ones as usize)
}
}
pub struct ChunkIter<I> {
iter: I,
chunk_size: usize,
done: bool,
}
impl<I: Iterator> Iterator for ChunkIter<I> {
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let mut chunk = Vec::with_capacity(self.chunk_size);
for _ in 0..self.chunk_size {
if let Some(x) = self.iter.next() {
chunk.push(x);
} else {
self.done = true;
break;
}
}
if chunk.is_empty() {
None
} else {
Some(chunk)
}
}
}