use crate::traits::BitLength;
use mem_dbg::{MemDbg, MemSize};
use std::{
iter::FusedIterator,
sync::atomic::{AtomicUsize, Ordering},
};
#[cfg(feature = "rayon")]
use crate::RAYON_MIN_LEN;
#[cfg(feature = "rayon")]
use rayon::prelude::*;
pub const BITS: usize = usize::BITS as usize;
macro_rules! panic_if_out_of_bounds {
($index: expr, $len: expr) => {
if $index >= $len {
panic!("Bit index out of bounds: {} >= {}", $index, $len)
}
};
}
impl<T: ?Sized + AsRef<[usize]> + BitLength> BitVecOps for T {}
pub trait BitVecOps: AsRef<[usize]> + BitLength {
#[inline]
fn get(&self, index: usize) -> bool {
panic_if_out_of_bounds!(index, self.len());
unsafe { self.get_unchecked(index) }
}
#[inline(always)]
unsafe fn get_unchecked(&self, index: usize) -> bool {
let word_index = index / BITS;
let word = unsafe { self.as_ref().get_unchecked(word_index) };
(word >> (index % BITS)) & 1 != 0
}
#[inline(always)]
fn iter(&self) -> BitIter<'_, [usize]> {
BitIter::new(self.as_ref(), self.len())
}
fn iter_ones(&self) -> OnesIter<'_, [usize]> {
OnesIter::new(self.as_ref(), self.len())
}
fn iter_zeros(&self) -> ZerosIter<'_, [usize]> {
ZerosIter::new(self.as_ref(), self.len())
}
#[cfg(feature = "rayon")]
fn par_count_ones(&self) -> usize {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_ref();
let mut num_ones;
num_ones = bits[..full_words]
.par_iter()
.with_min_len(RAYON_MIN_LEN)
.map(|x| x.count_ones() as usize)
.sum();
if residual != 0 {
num_ones += (self.as_ref()[full_words] << (BITS - residual)).count_ones() as usize
}
num_ones
}
}
impl<T: AsRef<[usize]> + AsMut<[usize]> + BitLength> BitVecOpsMut for T {}
pub trait BitVecOpsMut: AsRef<[usize]> + AsMut<[usize]> + BitLength {
#[inline]
fn set(&mut self, index: usize, value: bool) {
panic_if_out_of_bounds!(index, self.len());
unsafe { self.set_unchecked(index, value) }
}
#[inline(always)]
unsafe fn set_unchecked(&mut self, index: usize, value: bool) {
let word_index = index / BITS;
let bit_index = index % BITS;
let bits = self.as_mut();
unsafe {
if value {
*bits.get_unchecked_mut(word_index) |= 1 << bit_index;
} else {
*bits.get_unchecked_mut(word_index) &= !(1 << bit_index);
}
}
}
fn fill(&mut self, value: bool) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_mut();
let word_value = if value { !0 } else { 0 };
bits[..full_words].iter_mut().for_each(|x| *x = word_value);
if residual != 0 {
let mask = (1 << residual) - 1;
bits[full_words] = (bits[full_words] & !mask) | (word_value & mask);
}
}
#[cfg(feature = "rayon")]
fn par_fill(&mut self, value: bool) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_mut();
let word_value = if value { !0 } else { 0 };
bits[..full_words]
.par_iter_mut()
.with_min_len(RAYON_MIN_LEN)
.for_each(|x| *x = word_value);
if residual != 0 {
let mask = (1 << residual) - 1;
bits[full_words] = (bits[full_words] & !mask) | (word_value & mask);
}
}
fn reset(&mut self) {
self.fill(false);
}
#[cfg(feature = "rayon")]
fn par_reset(&mut self) {
self.par_fill(false);
}
fn flip(&mut self) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_mut();
bits[..full_words].iter_mut().for_each(|x| *x = !*x);
if residual != 0 {
let mask = (1 << residual) - 1;
bits[full_words] = (bits[full_words] & !mask) | (!bits[full_words] & mask);
}
}
#[cfg(feature = "rayon")]
fn par_flip(&mut self) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_mut();
bits[..full_words]
.par_iter_mut()
.with_min_len(RAYON_MIN_LEN)
.for_each(|x| *x = !*x);
if residual != 0 {
let mask = (1 << residual) - 1;
bits[full_words] = (bits[full_words] & !mask) | (!bits[full_words] & mask);
}
}
}
#[derive(Debug, Clone, MemDbg, MemSize)]
pub struct BitIter<'a, B: ?Sized> {
bits: &'a B,
len: usize,
next_bit_pos: usize,
}
impl<'a, B: ?Sized + AsRef<[usize]>> BitIter<'a, B> {
pub fn new(bits: &'a B, len: usize) -> Self {
debug_assert!(len <= bits.as_ref().len() * BITS);
BitIter {
bits,
len,
next_bit_pos: 0,
}
}
}
impl<B: ?Sized + AsRef<[usize]>> Iterator for BitIter<'_, B> {
type Item = bool;
fn next(&mut self) -> Option<bool> {
if self.next_bit_pos == self.len {
return None;
}
let word_idx = self.next_bit_pos / BITS;
let bit_idx = self.next_bit_pos % BITS;
let word = unsafe { *self.bits.as_ref().get_unchecked(word_idx) };
let bit = (word >> bit_idx) & 1;
self.next_bit_pos += 1;
Some(bit != 0)
}
}
impl<B: ?Sized + AsRef<[usize]>> ExactSizeIterator for BitIter<'_, B> {
fn len(&self) -> usize {
self.len - self.next_bit_pos
}
}
impl<B: ?Sized + AsRef<[usize]>> FusedIterator for BitIter<'_, B> {}
#[derive(Debug, Clone, MemDbg, MemSize)]
pub struct OnesIter<'a, B: ?Sized> {
bits: &'a B,
len: usize,
word_idx: usize,
word: usize,
}
impl<'a, B: ?Sized + AsRef<[usize]>> OnesIter<'a, B> {
pub fn new(bits: &'a B, len: usize) -> Self {
debug_assert!(len <= bits.as_ref().len() * BITS);
let word = if bits.as_ref().is_empty() {
0
} else {
unsafe { *bits.as_ref().get_unchecked(0) }
};
Self {
bits,
len,
word_idx: 0,
word,
}
}
}
impl<B: ?Sized + AsRef<[usize]>> Iterator for OnesIter<'_, B> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.word == 0 {
self.word_idx += 1;
if self.word_idx >= self.bits.as_ref().len() {
return None;
}
self.word = unsafe { *self.bits.as_ref().get_unchecked(self.word_idx) };
}
let bit_idx = self.word.trailing_zeros() as usize;
let res = (self.word_idx * BITS) + bit_idx;
if res >= self.len {
None
} else {
self.word &= self.word - 1;
Some(res)
}
}
}
impl<B: ?Sized + AsRef<[usize]>> FusedIterator for OnesIter<'_, B> {}
#[derive(Debug, Clone, MemDbg, MemSize)]
pub struct ZerosIter<'a, B: ?Sized> {
bits: &'a B,
len: usize,
word_idx: usize,
word: usize,
}
impl<'a, B: ?Sized + AsRef<[usize]>> ZerosIter<'a, B> {
pub fn new(bits: &'a B, len: usize) -> Self {
debug_assert!(len <= bits.as_ref().len() * BITS);
let word = if bits.as_ref().is_empty() {
0
} else {
unsafe { !*bits.as_ref().get_unchecked(0) }
};
Self {
bits,
len,
word_idx: 0,
word,
}
}
}
impl<B: ?Sized + AsRef<[usize]>> Iterator for ZerosIter<'_, B> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.word == 0 {
self.word_idx += 1;
if self.word_idx >= self.bits.as_ref().len() {
return None;
}
self.word = unsafe { !*self.bits.as_ref().get_unchecked(self.word_idx) };
}
let bit_idx = self.word.trailing_zeros() as usize;
let res = (self.word_idx * BITS) + bit_idx;
if res >= self.len {
None
} else {
self.word &= self.word - 1;
Some(res)
}
}
}
impl<B: ?Sized + AsRef<[usize]>> FusedIterator for ZerosIter<'_, B> {}
impl<T: ?Sized + AsRef<[AtomicUsize]> + BitLength> AtomicBitVecOps for T {}
pub trait AtomicBitVecOps: AsRef<[AtomicUsize]> + BitLength {
fn get(&self, index: usize, ordering: Ordering) -> bool {
panic_if_out_of_bounds!(index, self.len());
unsafe { self.get_unchecked(index, ordering) }
}
fn set(&self, index: usize, value: bool, ordering: Ordering) {
panic_if_out_of_bounds!(index, self.len());
unsafe { self.set_unchecked(index, value, ordering) }
}
fn swap(&self, index: usize, value: bool, ordering: Ordering) -> bool {
panic_if_out_of_bounds!(index, self.len());
unsafe { self.swap_unchecked(index, value, ordering) }
}
#[inline]
unsafe fn get_unchecked(&self, index: usize, ordering: Ordering) -> bool {
let word_index = index / BITS;
let bits = self.as_ref();
let word = unsafe { bits.get_unchecked(word_index).load(ordering) };
(word >> (index % BITS)) & 1 != 0
}
#[inline]
unsafe fn set_unchecked(&self, index: usize, value: bool, ordering: Ordering) {
let word_index = index / BITS;
let bit_index = index % BITS;
let bits = self.as_ref();
unsafe {
if value {
bits.get_unchecked(word_index)
.fetch_or(1 << bit_index, ordering);
} else {
bits.get_unchecked(word_index)
.fetch_and(!(1 << bit_index), ordering);
}
}
}
#[inline]
unsafe fn swap_unchecked(&self, index: usize, value: bool, ordering: Ordering) -> bool {
let word_index = index / BITS;
let bit_index = index % BITS;
let bits = self.as_ref();
let old_word = unsafe {
if value {
bits.get_unchecked(word_index)
.fetch_or(1 << bit_index, ordering)
} else {
bits.get_unchecked(word_index)
.fetch_and(!(1 << bit_index), ordering)
}
};
(old_word >> (bit_index)) & 1 != 0
}
fn fill(&mut self, value: bool, ordering: Ordering) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_ref();
let word_value = if value { !0 } else { 0 };
core::sync::atomic::fence(Ordering::SeqCst);
bits[..full_words]
.iter()
.for_each(|x| x.store(word_value, ordering));
if residual != 0 {
let mask = (1 << residual) - 1;
bits[full_words].store(
(bits[full_words].load(ordering) & !mask) | (word_value & mask),
ordering,
);
}
}
#[cfg(feature = "rayon")]
fn par_fill(&mut self, value: bool, ordering: Ordering) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_ref();
let word_value = if value { !0 } else { 0 };
core::sync::atomic::fence(Ordering::SeqCst);
bits[..full_words]
.par_iter()
.with_min_len(RAYON_MIN_LEN)
.for_each(|x| x.store(word_value, ordering));
if residual != 0 {
let mask = (1 << residual) - 1;
bits[full_words].store(
(bits[full_words].load(ordering) & !mask) | (word_value & mask),
ordering,
);
}
}
fn reset(&mut self, ordering: Ordering) {
self.fill(false, ordering);
}
#[cfg(feature = "rayon")]
fn par_reset(&mut self, ordering: Ordering) {
self.par_fill(false, ordering);
}
fn flip(&mut self, ordering: Ordering) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_ref();
core::sync::atomic::fence(Ordering::SeqCst);
bits[..full_words]
.iter()
.for_each(|x| _ = x.fetch_xor(!0, ordering));
if residual != 0 {
let mask = (1 << residual) - 1;
let last_word = bits[full_words].load(ordering);
bits[full_words].store((last_word & !mask) | (!last_word & mask), ordering);
}
}
#[cfg(feature = "rayon")]
fn par_flip(&mut self, ordering: Ordering) {
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_ref();
core::sync::atomic::fence(Ordering::SeqCst);
bits[..full_words]
.par_iter()
.with_min_len(RAYON_MIN_LEN)
.for_each(|x| _ = x.fetch_xor(!0, ordering));
if residual != 0 {
let mask = (1 << residual) - 1;
let last_word = bits[full_words].load(ordering);
bits[full_words].store((last_word & !mask) | (!last_word & mask), ordering);
}
}
#[cfg(feature = "rayon")]
fn par_count_ones(&self) -> usize {
use crate::RAYON_MIN_LEN;
let full_words = self.len() / BITS;
let residual = self.len() % BITS;
let bits = self.as_ref();
let mut num_ones;
core::sync::atomic::fence(Ordering::SeqCst);
num_ones = bits[..full_words]
.par_iter()
.with_min_len(RAYON_MIN_LEN)
.map(|x| x.load(Ordering::Relaxed).count_ones() as usize)
.sum();
if residual != 0 {
num_ones += (bits[full_words].load(Ordering::Relaxed) << (BITS - residual)).count_ones()
as usize
}
num_ones
}
#[inline(always)]
fn iter(&self) -> AtomicBitIter<'_, [AtomicUsize]> {
AtomicBitIter::new(self.as_ref(), self.len())
}
}
#[derive(Debug, MemDbg, MemSize)]
pub struct AtomicBitIter<'a, B: ?Sized> {
bits: &'a B,
len: usize,
next_bit_pos: usize,
}
impl<'a, B: ?Sized + AsRef<[AtomicUsize]>> AtomicBitIter<'a, B> {
pub fn new(bits: &'a B, len: usize) -> Self {
debug_assert!(len <= bits.as_ref().len() * BITS);
AtomicBitIter {
bits,
len,
next_bit_pos: 0,
}
}
}
impl<B: ?Sized + AsRef<[AtomicUsize]>> Iterator for AtomicBitIter<'_, B> {
type Item = bool;
fn next(&mut self) -> Option<bool> {
if self.next_bit_pos == self.len {
return None;
}
let word_idx = self.next_bit_pos / BITS;
let bit_idx = self.next_bit_pos % BITS;
let word = unsafe {
self.bits
.as_ref()
.get_unchecked(word_idx)
.load(Ordering::Relaxed)
};
let bit = (word >> bit_idx) & 1;
self.next_bit_pos += 1;
Some(bit != 0)
}
}
impl<B: ?Sized + AsRef<[AtomicUsize]>> ExactSizeIterator for AtomicBitIter<'_, B> {
fn len(&self) -> usize {
self.len - self.next_bit_pos
}
}
impl<B: ?Sized + AsRef<[AtomicUsize]>> FusedIterator for AtomicBitIter<'_, B> {}