use super::{Blocks, Chunks, Fid};
use crate::internal_data_structure::popcount_table::PopcountTable;
use crate::internal_data_structure::raw_bit_vector::RawBitVector;
use std::ops::Index;
impl From<&str> for Fid {
fn from(s: &str) -> Self {
let bits: Vec<bool> = s
.as_bytes()
.iter()
.filter_map(|c| match c {
48 => Some(false),
49 => Some(true),
95 => None,
_ => panic!("`s` must consist of '0' or '1'. '{}' included.", c),
})
.collect();
Self::from(&bits[..])
}
}
impl From<&[bool]> for Fid {
fn from(bits: &[bool]) -> Self {
assert!(!bits.is_empty());
let mut byte_vec: Vec<u8> = Vec::with_capacity(bits.len() / 8 + 1);
let mut last_byte_len = 0u8;
for bits8 in bits.chunks(8) {
last_byte_len = bits8.len() as u8;
let byte = (0..last_byte_len).fold(0, |byte, i| {
byte + if bits8[i as usize] { 1 << (7 - i) } else { 0 }
});
byte_vec.push(byte);
}
Fid::build(byte_vec, last_byte_len)
}
}
static TRUE: bool = true;
static FALSE: bool = false;
impl Index<u64> for Fid {
type Output = bool;
fn index(&self, index: u64) -> &Self::Output {
if self.rbv().access(index) {
&TRUE
} else {
&FALSE
}
}
}
impl Fid {
fn build(byte_vec: Vec<u8>, last_byte_len: u8) -> Self {
let bit_len = (byte_vec.len() - 1) as u64 * 8 + last_byte_len as u64;
let rbv = RawBitVector::new(&byte_vec[..], 0, last_byte_len);
let chunks = Chunks::new(&rbv);
let table = PopcountTable::new(Blocks::calc_block_size(rbv.len()));
Self {
byte_vec,
bit_len,
chunks,
table,
}
}
pub fn rank(&self, i: u64) -> u64 {
let n = self.len();
assert!(i < n);
let chunk_size = Chunks::calc_chunk_size(n);
let block_size = Blocks::calc_block_size(n);
let i_chunk = i / chunk_size as u64;
let rank_from_chunk = if i_chunk == 0 {
0
} else {
let chunk_left = self.chunks.access(i_chunk - 1);
chunk_left.value()
};
let chunk_right = self.chunks.access(i_chunk);
let i_block = (i - i_chunk * chunk_size as u64) / block_size as u64;
let rank_from_block = if i_block == 0 {
0
} else {
let block_left = chunk_right.blocks.access(i_block - 1);
block_left.value()
};
let block_right = chunk_right.blocks.access(i_block);
let pos_block_start = i_chunk * chunk_size as u64 + i_block * block_size as u64;
assert!(i - pos_block_start < block_right.length() as u64);
let block_right_rbv = self
.rbv()
.clone_sub(pos_block_start, block_right.length() as u64);
let block_right_as_u32 = block_right_rbv.as_u32();
let bits_to_use = i - pos_block_start + 1;
let block_bits = block_right_as_u32 >> (32 - bits_to_use);
let rank_from_table = self.table.popcount(block_bits as u64);
rank_from_chunk + rank_from_block as u64 + rank_from_table as u64
}
pub fn rank0(&self, i: u64) -> u64 {
(i + 1) - self.rank(i)
}
pub fn select(&self, num: u64) -> Option<u64> {
let n = self.len();
assert!(num <= n);
if num == 0 || num == 1 && self[0] == true {
return Some(0);
}
if self.rank(n - 1) < num {
return None;
};
let mut ng = 0;
let mut ok = n - 1;
while ok - ng > 1 {
let mid = (ok + ng) / 2;
if self.rank(mid) >= num {
ok = mid;
} else {
ng = mid;
}
}
Some(ok)
}
pub fn select0(&self, num: u64) -> Option<u64> {
let n = self.bit_len;
assert!(num <= n);
if num == 0 || num == 1 && self[0] == false {
return Some(0);
}
if self.rank0(n - 1) < num {
return None;
};
let mut ng = 0;
let mut ok = n - 1;
while ok - ng > 1 {
let mid = (ok + ng) / 2;
if self.rank0(mid) >= num {
ok = mid;
} else {
ng = mid;
}
}
Some(ok)
}
pub fn len(&self) -> u64 {
self.bit_len
}
fn rbv(&self) -> RawBitVector {
let last_byte_len_or_0 = (self.bit_len % 8) as u8;
RawBitVector::new(
&self.byte_vec[..],
0,
if last_byte_len_or_0 == 0 {
8
} else {
last_byte_len_or_0
},
)
}
}
#[cfg(test)]
mod from_str_success_tests {
use crate::Fid;
macro_rules! parameterized_tests {
($($name:ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
let (s, expected_bits) = $value;
let fid = Fid::from(s);
for (i, bit) in expected_bits.iter().enumerate() {
assert_eq!(fid[i as u64], *bit);
}
}
)*
}
}
parameterized_tests! {
t1: ("0", vec![false]),
t2: ("1", vec![true]),
t3: ("00", vec![false, false]),
t4: ("01", vec![false, true]),
t5: ("10", vec![true, false]),
t6: ("11", vec![true, true]),
t7: ("0101_0101__0101_1100__1000_001", vec![
false, true, false, true,
false, true, false, true,
false, true, false, true,
true, true, false, false,
true, false, false, false,
false, false, true,
]),
}
}
#[cfg(test)]
mod from_str_failure_tests {
}
#[cfg(test)]
mod from_slice_success_tests {
use crate::Fid;
macro_rules! parameterized_tests {
($($name:ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
let arr = $value;
let fid = Fid::from(&arr[..]);
for (i, bit) in arr.iter().enumerate() {
assert_eq!(fid[i as u64], *bit);
}
}
)*
}
}
parameterized_tests! {
t1: [false],
t2: [true],
t3: [false, false],
t4: [false, true],
t5: [true, false],
t6: [true, true],
t7: [false; 100],
t8: [true; 100],
}
}
#[cfg(test)]
mod from_slice_failure_tests {
use crate::Fid;
#[test]
#[should_panic]
fn empty() {
Fid::from(&[][..]);
}
}
#[cfg(test)]
mod index_u64_success_tests {
}
#[cfg(test)]
mod index_u64_failure_tests {
use crate::Fid;
#[test]
#[should_panic]
fn over_upper_bound() {
let fid = Fid::from("00");
let _ = fid[2];
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod rank_success_tests {
use crate::Fid;
macro_rules! parameterized_tests {
($($name:ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
let (in_fid_str, in_i, expected_rank) = $value;
assert_eq!(
Fid::from(in_fid_str).rank(in_i),
expected_rank
);
}
)*
}
}
parameterized_tests! {
rank1_1: ("0", 0, 0),
rank2_1: ("00", 0, 0),
rank2_2: ("00", 1, 0),
rank3_1: ("01", 0, 0),
rank3_2: ("01", 1, 1),
rank4_1: ("10", 0, 1),
rank4_2: ("10", 1, 1),
rank5_1: ("11", 0, 1),
rank5_2: ("11", 1, 2),
rank6_1: ("10010", 0, 1),
rank6_2: ("10010", 1, 1),
rank6_3: ("10010", 2, 1),
rank6_4: ("10010", 3, 2),
rank6_5: ("10010", 4, 2),
bugfix_11110110_11010101_01000101_11101111_10101011_10100101_01100011_00110100_01010101_10010000_01001100_10111111_00110011_00111110_01110101_11011100: (
"11110110_11010101_01000101_11101111_10101011_10100101_01100011_00110100_01010101_10010000_01001100_10111111_00110011_00111110_01110101_11011100",
49, 31,
),
bugfix_10100001_01010011_10101100_11100001_10110010_10000110_00010100_01001111_01011100_11010011_11110000_00011010_01101111_10101010_11000111_0110011: (
"10100001_01010011_10101100_11100001_10110010_10000110_00010100_01001111_01011100_11010011_11110000_00011010_01101111_10101010_11000111_0110011",
111, 55,
),
bugfix_100_111_101_011_011_100_101_001_111_001_001_101_100_011_000_111_1___01_000_101_100_101_101_001_011_110_010_001_101_010_010_010_111_111_111_001_111_001_100_010_001_010_101_11: (
"100_111_101_011_011_100_101_001_111_001_001_101_100_011_000_111_1___01_000_101_100_101_101_001_011_110_010_001_101_010_010_010_111_111_111_001_111_001_100_010_001_010_101_11",
48, 28,
),
bugfix_11100100_10110100_10000000_10111111_01110101_01100110_00101111_11101001_01100100_00001000_11010100_10100000_00010001_10100101_01100100_0010010: (
"11100100_10110100_10000000_10111111_01110101_01100110_00101111_11101001_01100100_00001000_11010100_10100000_00010001_10100101_01100100_0010010",
126, 56,
),
}
}
#[cfg(test)]
mod rank_failure_tests {
use crate::Fid;
#[test]
#[should_panic]
fn rank_over_upper_bound() {
let fid = Fid::from("00");
let _ = fid.rank(2);
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod rank0_success_tests {
use crate::Fid;
macro_rules! parameterized_tests {
($($name:ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
let (in_fid_str, in_i, expected_rank0) = $value;
assert_eq!(
Fid::from(in_fid_str).rank0(in_i),
expected_rank0
);
}
)*
}
}
parameterized_tests! {
rank0_1_1: ("0", 0, 1),
rank0_2_1: ("00", 0, 1),
rank0_2_2: ("00", 1, 2),
rank0_3_1: ("01", 0, 1),
rank0_3_2: ("01", 1, 1),
rank0_4_1: ("10", 0, 0),
rank0_4_2: ("10", 1, 1),
rank0_5_1: ("11", 0, 0),
rank0_5_2: ("11", 1, 0),
rank0_6_1: ("10010", 0, 0),
rank0_6_2: ("10010", 1, 1),
rank0_6_3: ("10010", 2, 2),
rank0_6_4: ("10010", 3, 2),
rank0_6_5: ("10010", 4, 3),
}
}
#[cfg(test)]
mod rank0_0_failure_tests {
use crate::Fid;
#[test]
#[should_panic]
fn rank0_over_upper_bound() {
let fid = Fid::from("00");
let _ = fid.rank0(2);
}
}
#[cfg(test)]
mod select_success_tests {
}
#[cfg(test)]
mod select_failure_tests {
use crate::Fid;
#[test]
#[should_panic]
fn select_over_max_rank() {
let fid = Fid::from("00");
let _ = fid.select(3);
}
}
#[cfg(test)]
mod select0_success_tests {
}
#[cfg(test)]
mod select0_failure_tests {
use crate::Fid;
#[test]
#[should_panic]
fn select_over_max_rank() {
let fid = Fid::from("00");
let _ = fid.select0(3);
}
}