use crate::{
utils::{prefetch_read_NTA, select_in_word},
AccessBin, RankBin, SelectBin,
};
use mem_dbg::{MemDbg, MemSize};
use serde::{Deserialize, Serialize};
pub mod rs_narrow;
pub mod rs_wide;
#[derive(Copy, Clone, Default, Eq, PartialEq, Serialize, Deserialize, MemSize, MemDbg, Debug)]
#[repr(C, align(64))]
struct DataLine {
words: [u64; 8],
}
impl DataLine {
#[inline]
fn set_symbol(&mut self, symbol: u64, i: usize) {
assert!(i < 512);
let mask: u64 = 1 << (i % 64);
self.words[i >> 6] ^= self.words[i >> 6] & mask; self.words[i >> 6] ^= (symbol & 1) << (i % 64); }
#[inline]
fn get_word(&self, i: usize) -> u64 {
assert!(i < 8);
self.words[i]
}
#[inline]
fn count_ones(&self) -> usize {
self.words
.iter()
.fold(0, |a, x| a + x.count_ones() as usize)
}
#[inline]
fn count_zeros(&self) -> usize {
512 - self.count_ones()
}
}
impl AccessBin for DataLine {
#[inline(always)]
fn get(&self, i: usize) -> Option<bool> {
assert!(i < 512);
Some(unsafe { self.get_unchecked(i) })
}
#[inline(always)]
unsafe fn get_unchecked(&self, i: usize) -> bool {
(self.words[i >> 6] >> (i % 64)) & 1 == 1
}
}
impl RankBin for DataLine {
#[inline(always)]
fn rank1(&self, i: usize) -> Option<usize> {
if i > 512 {
return None;
}
Some(unsafe { self.rank1_unchecked(i) })
}
#[inline(always)]
fn prefetch(&self, _pos: usize) {}
#[inline(always)]
unsafe fn rank1_unchecked(&self, i: usize) -> usize {
let mut left = i as i32;
let mut rank = 0;
for w in 0..8 {
if left < 0 {
break;
}
let cur_word = self.words.get_unchecked(w);
let mask: u64 = if left > 63 {
0xFFFFFFFFFFFFFFFF
} else {
(1 << left) - 1
};
rank += (cur_word & mask).count_ones() as usize;
left -= 64;
}
rank
}
fn count_zeros(&self) -> usize {
self.count_zeros()
}
}
fn cast_to_u64_slice(data_lines: &[DataLine]) -> &[u64] {
unsafe {
let len = data_lines.len().checked_mul(8).unwrap();
let ptr = data_lines.as_ptr();
let u64_ptr = ptr as *const u64;
std::slice::from_raw_parts(u64_ptr, len)
}
}
impl SelectBin for DataLine {
fn select1(&self, i: usize) -> Option<usize> {
if i >= self.count_ones() {
return None;
}
Some(unsafe { self.select1_unchecked(i) })
}
#[inline(always)]
unsafe fn select1_unchecked(&self, i: usize) -> usize {
let mut off = 0;
let mut rank = 0;
for w in 0..8 {
let kp = self.words.get_unchecked(w).count_ones();
if kp as usize > (i - rank) {
off += select_in_word(*self.words.get_unchecked(w), (i - rank) as u64) as usize;
break;
} else {
rank += kp as usize;
off += 64;
}
}
off
}
fn select0(&self, i: usize) -> Option<usize> {
if i >= self.count_zeros() {
return None;
}
Some(unsafe { self.select1_unchecked(i) })
}
#[inline(always)]
unsafe fn select0_unchecked(&self, i: usize) -> usize {
let mut rank = 0;
let mut off = 0;
for w in 0..8 {
let word_to_select = !self.words.get_unchecked(w);
let kp = word_to_select.count_ones();
if kp as usize > (i - rank) {
off += select_in_word(word_to_select, (i - rank) as u64) as usize;
break;
} else {
rank += kp as usize;
off += 64;
}
}
off
}
}
#[derive(Default, Clone, Serialize, Deserialize, MemSize, MemDbg, Eq, PartialEq)]
pub struct BitVector {
data: Box<[DataLine]>,
n_bits: usize,
count_ones: usize,
}
impl BitVector {
#[must_use]
#[inline]
pub fn get_bits(&self, index: usize, len: usize) -> Option<u64> {
if (len == 0) | (len > 64) | (index + len > self.n_bits) {
return None;
}
Some(unsafe { self.get_bits_unchecked(index, len) })
}
#[must_use]
#[inline]
pub unsafe fn get_bits_unchecked(&self, index: usize, len: usize) -> u64 {
BitVectorMut::get_bits_slice(cast_to_u64_slice(&self.data), index, len)
}
#[must_use]
#[inline(always)]
pub fn get_word(&self, i: usize) -> u64 {
self.data[i >> 3].words[i % 8]
}
#[must_use]
#[inline]
pub fn words(&self) -> &[u64] {
&cast_to_u64_slice(&self.data)[..self.n_bits.div_ceil(64)]
}
#[must_use]
pub fn ones(&self) -> BitVectorBitPositionsIter<'_, true> {
BitVectorBitPositionsIter::new(cast_to_u64_slice(&self.data), self.n_bits)
}
#[must_use]
pub fn ones_with_pos(&self, pos: usize) -> BitVectorBitPositionsIter<'_, true> {
BitVectorBitPositionsIter::with_pos(cast_to_u64_slice(&self.data), self.n_bits, pos)
}
#[must_use]
pub fn zeros(&self) -> BitVectorBitPositionsIter<'_, false> {
BitVectorBitPositionsIter::new(cast_to_u64_slice(&self.data), self.n_bits)
}
#[must_use]
pub fn zeros_with_pos(&self, pos: usize) -> BitVectorBitPositionsIter<'_, false> {
BitVectorBitPositionsIter::with_pos(cast_to_u64_slice(&self.data), self.n_bits, pos)
}
pub fn iter(&self) -> BitVectorIter<'_> {
BitVectorIter {
data: cast_to_u64_slice(&self.data),
n_bits: self.n_bits,
i: 0,
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.n_bits == 0
}
pub fn len(&self) -> usize {
self.n_bits
}
pub fn count_ones(&self) -> usize {
self.count_ones
}
#[inline]
#[must_use]
pub fn count_zeros(&self) -> usize {
self.len() - self.count_ones
}
pub fn n_lines(&self) -> usize {
self.data.len()
}
#[inline]
pub fn prefetch_line(&self, n: usize) {
prefetch_read_NTA(&self.data, n);
}
}
impl AccessBin for BitVector {
#[inline(always)]
fn get(&self, index: usize) -> Option<bool> {
if index >= self.len() {
return None;
}
Some(unsafe { self.get_unchecked(index) })
}
#[inline(always)]
unsafe fn get_unchecked(&self, index: usize) -> bool {
BitVectorMut::get_bit_slice(cast_to_u64_slice(&self.data), index)
}
}
impl FromIterator<bool> for BitVector {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = bool>,
{
let mut bv = BitVectorMut::default();
bv.extend(iter);
bv.into()
}
}
pub trait MyPrimInt: TryInto<usize> {}
macro_rules! impl_my_prim_int {
($($t:ty),*) => {
$(impl MyPrimInt for $t {
})*
}
}
impl_my_prim_int![i8, u8, i16, u16, i32, u32, i64, u64, isize, usize, u128, i128];
impl<V> FromIterator<V> for BitVector
where
V: MyPrimInt,
<V as TryInto<usize>>::Error: std::fmt::Debug,
{
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = V>,
<V as TryInto<usize>>::Error: std::fmt::Debug,
{
let mut bv = BitVectorMut::default();
bv.extend(
iter.into_iter()
.map(|x| x.try_into().expect("Cannot a value convert to usize")),
);
bv.into()
}
}
impl From<BitVectorMut> for BitVector {
fn from(bvm: BitVectorMut) -> Self {
Self {
data: bvm.data.into_boxed_slice(),
n_bits: bvm.n_bits,
count_ones: bvm.count_ones,
}
}
}
impl From<BitVector> for BitVectorMut {
fn from(bv: BitVector) -> Self {
Self {
data: bv.data.into(),
n_bits: bv.n_bits,
count_ones: bv.count_ones,
}
}
}
impl AsRef<BitVector> for BitVector {
fn as_ref(&self) -> &BitVector {
self
}
}
impl AsRef<BitVectorMut> for BitVectorMut {
fn as_ref(&self) -> &BitVectorMut {
self
}
}
pub struct BitVectorBitPositionsIter<'a, const BIT: bool> {
data: &'a [u64],
n_bits: usize,
cur_position: usize,
cur_word_pos: usize,
cur_word: u64,
}
impl<'a, const BIT: bool> BitVectorBitPositionsIter<'a, BIT> {
#[must_use]
#[inline(always)]
pub fn new(data: &'a [u64], n_bits: usize) -> Self {
BitVectorBitPositionsIter {
data,
n_bits,
cur_position: 0,
cur_word_pos: 0, cur_word: 0, }
}
#[must_use]
#[inline(always)]
pub fn with_pos(data: &'a [u64], n_bits: usize, pos: usize) -> Self {
let cur_word_pos = pos >> 6;
let cur_word = if cur_word_pos < data.len() {
if BIT {
data[cur_word_pos]
} else {
!data[cur_word_pos]
}
} else {
0
};
let l = pos % 64;
let cur_word = cur_word >> l;
dbg!(pos, l);
BitVectorBitPositionsIter {
data,
n_bits,
cur_position: pos,
cur_word_pos: cur_word_pos + 1,
cur_word,
}
}
}
impl<'a, const BIT: bool> Iterator for BitVectorBitPositionsIter<'a, BIT> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.cur_position >= self.n_bits {
return None;
}
while self.cur_word == 0 {
if self.cur_word_pos < self.data.len() {
if BIT {
self.cur_word = self.data[self.cur_word_pos];
} else {
self.cur_word = !self.data[self.cur_word_pos];
}
self.cur_position = self.cur_word_pos << 6;
} else {
return None;
}
self.cur_word_pos += 1;
}
let l = self.cur_word.trailing_zeros() as usize;
self.cur_position += l;
let pos = self.cur_position;
self.cur_word = if l >= 63 { 0 } else { self.cur_word >> (l + 1) };
self.cur_position += 1;
if pos >= self.n_bits {
None
} else {
Some(pos)
}
}
}
pub struct BitVectorIter<'a> {
data: &'a [u64],
n_bits: usize,
i: usize,
}
pub struct BitVectorIntoIter {
bv: BitVector,
i: usize,
}
impl ExactSizeIterator for BitVectorIntoIter {
fn len(&self) -> usize {
self.bv.n_bits - self.i
}
}
impl Iterator for BitVectorIntoIter {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
self.i += 1;
self.bv.get(self.i - 1)
}
}
impl IntoIterator for BitVector {
type IntoIter = BitVectorIntoIter;
type Item = bool;
fn into_iter(self) -> Self::IntoIter {
BitVectorIntoIter { bv: self, i: 0 }
}
}
impl IntoIterator for BitVectorMut {
type IntoIter = BitVectorIntoIter;
type Item = bool;
fn into_iter(self) -> Self::IntoIter {
BitVectorIntoIter {
bv: self.into(), i: 0,
}
}
}
impl<'a> IntoIterator for &'a BitVector {
type IntoIter = BitVectorIter<'a>;
type Item = bool;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> Iterator for BitVectorIter<'a> {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
if self.i < self.n_bits {
self.i += 1;
Some(unsafe { BitVectorMut::get_bit_slice(self.data, self.i - 1) })
} else {
None
}
}
}
impl<'a> ExactSizeIterator for BitVectorIter<'a> {
fn len(&self) -> usize {
self.n_bits - self.i
}
}
#[derive(Default, Clone, Serialize, Deserialize, MemSize, MemDbg, Eq, PartialEq)]
pub struct BitVectorMut {
data: Vec<DataLine>,
n_bits: usize,
count_ones: usize,
}
impl BitVectorMut {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_capacity(n_bits: usize) -> Self {
let capacity = n_bits.div_ceil(64);
Self {
data: Vec::with_capacity(capacity),
..Self::default()
}
}
#[must_use]
pub fn with_zeros(n_bits: usize) -> Self {
let mut bv = Self::with_capacity(n_bits);
bv.extend_with_zeros(n_bits);
bv.shrink_to_fit();
bv
}
#[must_use]
#[inline]
pub fn from_packed_data(data: &[u64], n_bits: usize) -> Self {
assert!(n_bits <= data.len() * 64);
let data = &data[..n_bits.div_ceil(64)];
let mut v = BitVectorMut::with_capacity(n_bits);
if let [rest @ .., last] = data {
for d in rest {
v.append_bits(*d, 64);
}
v.append_bits(*last, ((n_bits - 1) % 64) + 1);
}
v
}
#[inline]
pub fn push(&mut self, bit: bool) {
let pos_in_line = self.n_bits % 512;
if pos_in_line == 0 {
self.data.push(DataLine::default());
}
if bit {
if let Some(last) = self.data.last_mut() {
last.set_symbol(1, pos_in_line);
}
self.count_ones += 1;
}
self.n_bits += 1;
}
#[inline]
pub fn append_bits(&mut self, bits: u64, len: usize) {
assert!(len == 64 || (bits >> len) == 0);
assert!(len <= 64);
if len == 0 {
return;
}
for i in 0..len {
self.push((bits >> i) & 1 == 1);
}
}
#[inline]
pub fn extend_with_zeros(&mut self, n: usize) {
self.n_bits += n;
let new_size = self.n_bits.div_ceil(512);
self.data.resize_with(new_size, Default::default);
}
#[inline]
pub fn set(&mut self, index: usize, bit: bool) {
assert!(index < self.n_bits);
unsafe {
if bit && !self.get_unchecked(index) {
self.count_ones += 1;
}
if !bit && self.get_unchecked(index) {
self.count_ones -= 1;
}
}
let dl = index >> 9;
let pos_in_dl = index & 511;
self.data[dl].set_symbol(bit as u64, pos_in_dl);
}
#[must_use]
#[inline]
pub fn get_bits(&self, index: usize, len: usize) -> Option<u64> {
if (len == 0) | (len > 64) | (index + len >= self.n_bits) {
return None;
}
Some(unsafe { self.get_bits_unchecked(index, len) })
}
#[must_use]
#[inline]
pub unsafe fn get_bits_unchecked(&self, index: usize, len: usize) -> u64 {
Self::get_bits_slice(cast_to_u64_slice(&self.data), index, len)
}
#[inline]
unsafe fn get_bits_slice(data: &[u64], index: usize, len: usize) -> u64 {
let block = index >> 6;
let shift = index & 63;
let mask = if len == 64 {
std::u64::MAX
} else {
(1_u64 << len) - 1
};
if shift + len <= 64 {
return data[block] >> shift & mask;
}
(data[block] >> shift) | (data[block + 1] << (64 - shift) & mask)
}
#[inline]
#[must_use]
unsafe fn get_bit_slice(data: &[u64], index: usize) -> bool {
let word = index >> 6;
let pos_in_word = index & 63;
data[word] >> pos_in_word & 1_u64 == 1
}
#[inline]
pub fn set_bits(&mut self, index: usize, len: usize, bits: u64) {
assert!(index + len <= self.n_bits);
assert!(len == 64 || (bits >> len) == 0);
assert!(len <= 64);
if len == 0 {
return;
}
self.count_ones += bits.count_ones() as usize;
for i in 0..len {
self.data[(index + i) >> 9].set_symbol((bits >> i) & 1, (index + i) % 512)
}
}
#[must_use]
#[inline(always)]
pub fn get_word(&self, i: usize) -> u64 {
self.data[i >> 3].words[i % 8]
}
#[must_use]
pub fn ones(&self) -> BitVectorBitPositionsIter<'_, true> {
BitVectorBitPositionsIter::new(cast_to_u64_slice(&self.data), self.n_bits)
}
#[must_use]
pub fn ones_with_pos(&self, pos: usize) -> BitVectorBitPositionsIter<'_, true> {
BitVectorBitPositionsIter::with_pos(cast_to_u64_slice(&self.data), self.n_bits, pos)
}
#[must_use]
pub fn zeros(&self) -> BitVectorBitPositionsIter<'_, false> {
BitVectorBitPositionsIter::new(cast_to_u64_slice(&self.data), self.n_bits)
}
#[must_use]
pub fn zeros_with_pos(&self, pos: usize) -> BitVectorBitPositionsIter<'_, false> {
BitVectorBitPositionsIter::with_pos(cast_to_u64_slice(&self.data), self.n_bits, pos)
}
pub fn iter(&self) -> BitVectorIter<'_> {
BitVectorIter {
data: cast_to_u64_slice(&self.data),
n_bits: self.n_bits,
i: 0,
}
}
pub fn shrink_to_fit(&mut self) {
self.data.shrink_to_fit();
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.n_bits == 0
}
pub fn len(&self) -> usize {
self.n_bits
}
pub fn count_ones(&self) -> usize {
self.count_ones
}
#[inline]
#[must_use]
pub fn count_zeros(&self) -> usize {
self.len() - self.count_ones
}
}
impl AccessBin for BitVectorMut {
#[inline(always)]
fn get(&self, index: usize) -> Option<bool> {
if index >= self.len() {
return None;
}
Some(unsafe { self.get_unchecked(index) })
}
#[inline(always)]
unsafe fn get_unchecked(&self, index: usize) -> bool {
Self::get_bit_slice(cast_to_u64_slice(&self.data), index)
}
}
impl Extend<bool> for BitVectorMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = bool>,
{
for bit in iter {
self.push(bit);
}
}
}
impl FromIterator<bool> for BitVectorMut {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = bool>,
{
let mut bv = BitVectorMut::default();
bv.extend(iter);
bv.shrink_to_fit();
bv
}
}
impl FromIterator<usize> for BitVectorMut {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = usize>,
{
let mut bv = BitVectorMut::default();
bv.extend(iter);
bv.shrink_to_fit();
bv
}
}
impl Extend<usize> for BitVectorMut {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = usize>,
{
for pos in iter {
if pos >= self.n_bits {
self.extend_with_zeros(pos + 1 - self.n_bits);
}
self.set(pos, true);
}
}
}
impl std::fmt::Debug for BitVector {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let data_str: Vec<String> = self.data.iter().map(|x| format!("{:?}", x)).collect();
write!(
fmt,
"BitVector {{ n_bits:{:?}, data:{:?}}}",
self.n_bits, data_str
)
}
}
impl std::fmt::Debug for BitVectorMut {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let data_str: Vec<String> = self.data.iter().map(|x| format!("{:?}", x)).collect();
write!(
fmt,
"BitVectorMut {{ n_bits:{:?}, data:{:?}}}",
self.n_bits, data_str
)
}
}
#[cfg(test)]
mod tests;