use crate::qvector::rs_qvector::RSSupport;
use crate::utils::prefetch_read_NTA;
use crate::AccessQuad;
use crate::QVector;
use mem_dbg::MemDbg;
use mem_dbg::MemSize;
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, Serialize, Deserialize, MemSize, MemDbg, PartialEq)]
pub struct RSSupportPlain<const B_SIZE: usize = 256> {
superblocks: Box<[SuperblockPlain]>,
select_samples: [Box<[u32]>; 4],
}
impl<const B_SIZE: usize> RSSupport for RSSupportPlain<B_SIZE> {
const BLOCK_SIZE: usize = B_SIZE;
fn new(qv: &QVector) -> Self {
assert!(qv.len() < (1 << std::cmp::min(43, usize::BITS - 4)));
assert!(
(Self::BLOCK_SIZE == 256) | (Self::BLOCK_SIZE == 512),
"Block size is either 256 or 512 symbols."
);
let mut superblock_counters = [0; 4];
let mut block_counters = [0; 4];
let mut occs = [0; 4];
let mut select_samples: [Vec<u32>; 4] = [Vec::new(), Vec::new(), Vec::new(), Vec::new()];
let superblock_size: usize = Self::BLOCKS_IN_SUPERBLOCK * Self::BLOCK_SIZE;
let n_superblocks = (qv.len() + superblock_size) / superblock_size;
let mut superblocks = Vec::<SuperblockPlain>::with_capacity(n_superblocks);
for i in 0..qv.len() + 1 {
if i % superblock_size == 0 {
superblocks.push(SuperblockPlain::new(&superblock_counters));
block_counters = [0; 4]; }
if i % Self::BLOCK_SIZE == 0 {
let block_id = (i / Self::BLOCK_SIZE) % Self::BLOCKS_IN_SUPERBLOCK;
superblocks
.last_mut()
.unwrap()
.set_block_counters(block_id, &block_counters);
for symbol in 0..4u8 {
debug_assert_eq!(
block_counters[symbol as usize],
superblocks
.last()
.unwrap()
.get_block_counter(symbol, block_id)
);
}
}
if i < qv.len() {
let symbol = unsafe { qv.get_unchecked(i) as usize };
if occs[symbol] % Self::SELECT_NUM_SAMPLES == 0 {
debug_assert!(Self::superblock_index(i) <= u32::MAX as usize);
debug_assert!(Self::superblock_index(i) < superblocks.len());
select_samples[symbol].push(Self::superblock_index(i) as u32);
}
superblock_counters[symbol] += 1;
block_counters[symbol] += 1;
occs[symbol] += 1;
}
}
let next_block_id = (qv.len() / Self::BLOCK_SIZE) % Self::BLOCKS_IN_SUPERBLOCK + 1;
if next_block_id < Self::BLOCKS_IN_SUPERBLOCK {
superblocks
.last_mut()
.unwrap()
.set_block_counters(next_block_id, &block_counters);
}
for sample in &mut select_samples {
if sample.is_empty() {
sample.push(0);
}
sample.push(superblocks.len() as u32 - 1); }
Self {
superblocks: superblocks.into_boxed_slice(),
select_samples: select_samples
.into_iter()
.map(|sample| sample.into_boxed_slice())
.collect::<Vec<_>>()
.try_into()
.unwrap(), }
}
#[inline(always)]
fn rank_block(&self, symbol: u8, i: usize) -> usize {
debug_assert!(symbol <= 3, "Symbols are in [0, 3].");
let superblock_index = Self::superblock_index(i);
let block_index = Self::block_index(i);
unsafe {
self.superblocks
.get_unchecked(superblock_index)
.get_rank(symbol, block_index & 7)
}
}
#[inline(always)]
fn select_block(&self, symbol: u8, i: usize) -> (usize, usize) {
let sampled_i = (i - 1) / Self::SELECT_NUM_SAMPLES;
let mut first_sblock_id = self.select_samples[symbol as usize][sampled_i] as usize;
let last_sblock_id = 1 + self.select_samples[symbol as usize][sampled_i + 1] as usize;
let step = f64::sqrt((last_sblock_id - first_sblock_id) as f64) as usize + 1;
while first_sblock_id < last_sblock_id {
if self.superblocks[first_sblock_id].get_superblock_counter(symbol) >= i {
break;
}
first_sblock_id += step;
}
first_sblock_id -= step;
while first_sblock_id < last_sblock_id {
if self.superblocks[first_sblock_id].get_superblock_counter(symbol) >= i {
break;
}
first_sblock_id += 1;
}
first_sblock_id -= 1;
let mut position = first_sblock_id * Self::BLOCK_SIZE * Self::BLOCKS_IN_SUPERBLOCK; let mut rank = self.superblocks[first_sblock_id].get_superblock_counter(symbol);
let (block_id, block_rank) =
self.superblocks[first_sblock_id].block_predecessor(symbol, i - rank);
position += block_id * Self::BLOCK_SIZE;
rank += block_rank;
(position, rank)
}
#[inline(always)]
fn prefetch(&self, pos: usize) {
let superblock_index = Self::superblock_index(pos);
prefetch_read_NTA(&self.superblocks, superblock_index);
}
}
impl<const B_SIZE: usize> RSSupportPlain<B_SIZE> {
const SELECT_NUM_SAMPLES: usize = 1 << 13;
const BLOCKS_IN_SUPERBLOCK: usize = 8;
#[inline(always)]
fn superblock_index(i: usize) -> usize {
i / (Self::BLOCK_SIZE * Self::BLOCKS_IN_SUPERBLOCK)
}
#[inline(always)]
fn block_index(i: usize) -> usize {
i / Self::BLOCK_SIZE
}
}
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, MemSize, MemDbg, PartialEq)]
#[repr(C, align(64))]
struct SuperblockPlain {
counters: [u128; 4],
}
impl SuperblockPlain {
const BLOCKS_IN_SUPERBLOCK: usize = 8;
fn new(sbc: &[usize; 4]) -> Self {
let mut counters = [0u128; 4];
for symbol in 0..4 {
counters[symbol] = (sbc[symbol] as u128) << 84;
}
Self { counters }
}
#[inline(always)]
fn get_rank(&self, symbol: u8, block_id: usize) -> usize {
let data = unsafe { *self.counters.get_unchecked(symbol as usize) };
let sb = (data >> 84) as usize;
let not_first = (block_id > 0) as usize;
let b = ((data >> ((block_id - not_first) * 12)) as usize & 0b111111111111) * not_first;
sb + b
}
fn get_superblock_counter(&self, symbol: u8) -> usize {
(unsafe { *self.counters.get_unchecked(symbol as usize) } >> 84) as usize
}
fn set_block_counters(&mut self, block_id: usize, counters: &[usize; 4]) {
assert!(block_id < 8);
for &counter in counters.iter() {
assert!(counter < (1 << 12));
}
if block_id == 0 {
return;
}
for (symbol, &counter) in counters.iter().enumerate() {
self.counters[symbol] |= (counter as u128) << ((block_id - 1) * 12);
}
}
fn get_block_counter(&self, symbol: u8, block_id: usize) -> usize {
debug_assert!(block_id < Self::BLOCKS_IN_SUPERBLOCK);
if block_id == 0 {
0
} else {
(self.counters[symbol as usize] >> ((block_id - 1) * 12) & 0b111111111111) as usize
}
}
#[inline(always)]
pub fn block_predecessor(&self, symbol: u8, target: usize) -> (usize, usize) {
let mut cnt = self.counters[symbol as usize];
let mut prev_cnt = 0;
for block_id in 1..Self::BLOCKS_IN_SUPERBLOCK {
let curr_cnt = (cnt & 0b111111111111) as usize;
if curr_cnt >= target {
return (block_id - 1, prev_cnt);
}
cnt >>= 12;
prev_cnt = curr_cnt;
}
(Self::BLOCKS_IN_SUPERBLOCK - 1, prev_cnt)
}
}