#[derive(Debug)]
pub struct FourRussiansMSB {
macro_bit_array: u8,
micro_arrays: u64,
}
impl FourRussiansMSB {
pub fn build(query: u64) -> Self {
let macro_bit_array = Self::generate_macro_bit_array(query);
FourRussiansMSB {
macro_bit_array,
micro_arrays: query,
}
}
fn generate_macro_bit_array(query: u64) -> u8 {
let high_bit_mask =
0b10000000_10000000_10000000_10000000_10000000_10000000_10000000_10000000u64;
let is_high_bit_set = query & high_bit_mask;
let packed_ones =
0b00000001_00000001_00000001_00000001_00000001_00000001_00000001_00000001u64;
let mut are_lower_bits_set = query | high_bit_mask;
are_lower_bits_set -= packed_ones;
are_lower_bits_set &= high_bit_mask;
let is_block_active = is_high_bit_set | are_lower_bits_set;
let packer = 0b10000001_00000010_00000100_00001000_00010000_00100000_010000001u64;
let mut macro_bit_array = is_block_active as u128 * packer as u128;
macro_bit_array >>= 49;
if is_block_active >> 56 == 0 {
macro_bit_array &= 0b0111_1111;
} else {
macro_bit_array |= 0b1000_0000;
macro_bit_array &= 0b1111_1111;
}
macro_bit_array as u8
}
pub fn get_msb(&self) -> u8 {
let block_id = self.msb_by_rank(self.macro_bit_array);
let block_start = (block_id - 1) * 8;
let msb_block = self.get_msb_block(block_start); let msb = self.msb_by_rank(msb_block);
let in_block_location = msb - 1;
block_start + in_block_location
}
fn get_msb_block(&self, block_start: u8) -> u8 {
let block_mask = 0b1111_1111u64;
let mut block = self.micro_arrays >> block_start;
block &= block_mask;
block as u8
}
fn msb_by_rank(&self, query: u8) -> u8 {
let tiled_query = Self::parallel_tile_128(query);
let packed_keys =
0b000000001_000000010_000000100_000001000_000010000_000100000_001000000_010000000u128;
let mut difference = tiled_query - packed_keys;
let sentinel_mask =
0b100000000_100000000_100000000_100000000_100000000_100000000_100000000_100000000u128;
difference &= sentinel_mask;
difference.count_ones() as u8
}
pub fn parallel_tile_128(query: u8) -> u128 {
let multiplier =
0b100000000_100000000_100000000_100000000_100000000_100000000_100000000_1000000001u128;
let tiled_query = query as u128 * multiplier;
let sentinel_mask =
0b100000000_100000000_100000000_100000000_100000000_100000000_100000000_100000000u128;
tiled_query | sentinel_mask
}
}
pub fn get_msb_idx_of(query: u64) -> u8 {
FourRussiansMSB::build(query).get_msb()
}
pub fn lcp_len_of(a: u64, b: u64) -> u64 {
63 - get_msb_idx_of(a ^ b) as u64
}