#[cfg(feature = "rayon")]
use rayon::prelude::*;
use super::{Chunk, Chunks};
use crate::internal_data_structure::raw_bit_vector::RawBitVector;
impl super::Chunks {
#[cfg(feature = "rayon")]
pub fn new(rbv: &RawBitVector) -> Chunks {
let n = rbv.len();
let chunk_size: u16 = Chunks::calc_chunk_size(n);
let chunks_cnt: usize = Chunks::calc_chunks_cnt(n) as usize;
let mut chunks: Vec<Chunk> = Vec::with_capacity(chunks_cnt);
(0..chunks_cnt)
.into_par_iter()
.map(|number_of_chunk| {
let this_chunk_size: u16 = if number_of_chunk == chunks_cnt - 1 {
let chunk_size_or_0 = (n % chunk_size as u64) as u16;
if chunk_size_or_0 == 0 {
chunk_size
} else {
chunk_size_or_0
}
} else {
chunk_size
};
let chunk_rbv = rbv.clone_sub(
number_of_chunk as u64 * chunk_size as u64,
this_chunk_size as u64,
);
let popcnt_in_chunk = chunk_rbv.popcount();
Chunk::new(
popcnt_in_chunk,
this_chunk_size,
rbv,
number_of_chunk as u64,
)
})
.collect_into_vec(&mut chunks);
for i_chunk in 0..chunks_cnt {
chunks[i_chunk].value += if i_chunk == 0 {
0
} else {
chunks[i_chunk - 1].value
}
}
Chunks {
chunks,
chunks_cnt: chunks_cnt as u64,
}
}
#[cfg(not(feature = "rayon"))]
pub fn new(rbv: &RawBitVector) -> Chunks {
let n = rbv.len();
let chunk_size: u16 = Chunks::calc_chunk_size(n);
let chunks_cnt: u64 = Chunks::calc_chunks_cnt(n);
let mut chunks: Vec<Chunk> = Vec::with_capacity(chunks_cnt as usize);
let mut comulative_popcount = 0;
for i_chunk in 0..chunks_cnt {
let this_chunk_size: u16 = if i_chunk == chunks_cnt - 1 {
let chunk_size_or_0 = (n % chunk_size as u64) as u16;
if chunk_size_or_0 == 0 {
chunk_size
} else {
chunk_size_or_0
}
} else {
chunk_size
};
let chunk_rbv = rbv.clone_sub(i_chunk * chunk_size as u64, this_chunk_size as u64);
let popcnt_in_chunk = chunk_rbv.popcount();
comulative_popcount += popcnt_in_chunk;
chunks.push(Chunk::new(
comulative_popcount,
this_chunk_size,
rbv,
i_chunk,
));
}
Chunks { chunks, chunks_cnt }
}
pub fn calc_chunk_size(n: u64) -> u16 {
let lg2 = (n as f64).log2() as u16;
let sz = lg2 * lg2;
if sz == 0 {
1
} else {
sz
}
}
pub fn calc_chunks_cnt(n: u64) -> u64 {
let chunk_size = Chunks::calc_chunk_size(n);
n / (chunk_size as u64) + if n % (chunk_size as u64) == 0 { 0 } else { 1 }
}
pub fn access(&self, i: u64) -> &Chunk {
assert!(
i <= self.chunks_cnt,
"i = {} must be smaller then {} (self.chunks_cnt())",
i,
self.chunks_cnt
);
&self.chunks[i as usize]
}
}
#[cfg(test)]
mod new_success_tests {
use super::Chunks;
use crate::internal_data_structure::raw_bit_vector::RawBitVector;
struct Input<'a> {
byte_slice: &'a [u8],
last_byte_len: u8,
expected_chunk_size: u16,
expected_chunks: &'a Vec<u64>,
}
macro_rules! parameterized_tests {
($($name:ident: $value:expr,)*) => {
$(
#[test]
fn $name() {
let input: Input = $value;
let rbv = RawBitVector::new(input.byte_slice, 0, input.last_byte_len);
let n = rbv.len();
let chunks = Chunks::new(&rbv);
assert_eq!(Chunks::calc_chunk_size(n), input.expected_chunk_size);
assert_eq!(Chunks::calc_chunks_cnt(n), input.expected_chunks.len() as u64);
for (i, expected_chunk) in input.expected_chunks.iter().enumerate() {
let chunk = chunks.access(i as u64);
assert_eq!(chunk.value(), *expected_chunk);
}
}
)*
}
}
parameterized_tests! {
t1: Input {
byte_slice: &[0b0000_0000],
last_byte_len: 1,
expected_chunk_size: 1,
expected_chunks: &vec!(0)
},
t2: Input {
byte_slice: &[0b1000_0000],
last_byte_len: 1,
expected_chunk_size: 1,
expected_chunks: &vec!(1)
},
t3: Input {
byte_slice: &[0b0111_0000],
last_byte_len: 4,
expected_chunk_size: 4,
expected_chunks: &vec!(3)
},
t4: Input {
byte_slice: &[0b0111_1101],
last_byte_len: 8,
expected_chunk_size: 9,
expected_chunks: &vec!(6)
},
t5: Input {
byte_slice: &[0b0111_1101, 0b1000_0000],
last_byte_len: 1,
expected_chunk_size: 9,
expected_chunks: &vec!(7)
},
t6: Input {
byte_slice: &[0b0111_1101, 0b1100_0000],
last_byte_len: 2,
expected_chunk_size: 9,
expected_chunks: &vec!(7, 8)
},
bugfix_11: Input {
byte_slice: &[0b1100_0000],
last_byte_len: 2,
expected_chunk_size: 1,
expected_chunks: &vec!(1, 2)
},
bugfix_11110110_11010101_01000101_11101111_10101011_10100101_01100011_00110100_01010101_10010000_01001100_10111111_00110011_00111110_01110101_11011100: Input {
byte_slice: &[0b11110110, 0b11010101, 0b01000101, 0b11101111, 0b10101011, 0b10100101, 0b0_1100011, 0b00110100, 0b01010101, 0b10010000, 0b01001100, 0b10111111, 0b00_110011, 0b00111110, 0b01110101, 0b11011100],
last_byte_len: 8,
expected_chunk_size: 49,
expected_chunks: &vec!(30, 53, 72)
},
}
}