use crate::{AccessQuad, RankQuad};
use mem_dbg::{MemDbg, MemSize};
use num_traits::int::PrimInt;
use num_traits::AsPrimitive;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Default, Eq, PartialEq, Serialize, MemSize, MemDbg, Deserialize, Debug)]
#[repr(C, align(64))]
struct DataLine {
words: [u128; 4],
}
impl DataLine {
const MASK: u128 = 3;
const REPEATEDSYMB: [u128; 2] = [
u128::MAX, 0,
];
#[inline(always)]
fn normalize(&self, symbol: u8) -> (u128, u128) {
let mask_high = Self::REPEATEDSYMB[(symbol >> 1) as usize];
let mask_low = Self::REPEATEDSYMB[(symbol & 1) as usize];
let word_high_0 = self.words[0] ^ mask_high;
let word_low_0 = self.words[2] ^ mask_low;
let word_high_1 = self.words[1] ^ mask_high;
let word_low_1 = self.words[3] ^ mask_low;
(word_high_0 & word_low_0, word_high_1 & word_low_1)
}
#[inline]
fn set_symbol(&mut self, symbol: u8, i: u8) {
let word_id_high = i >> 7;
let word_id_low = word_id_high + 2;
let cur_shift = i & 127;
let symbol = (symbol as u128) & Self::MASK;
self.words[word_id_high as usize] |= (symbol >> 1) << cur_shift;
self.words[word_id_low as usize] |= (symbol & 1) << cur_shift;
}
}
impl AccessQuad for DataLine {
#[inline(always)]
fn get(&self, i: usize) -> Option<u8> {
assert!(i < 256);
Some(unsafe { self.get_unchecked(i) })
}
#[inline(always)]
unsafe fn get_unchecked(&self, i: usize) -> u8 {
let word_id_high = i >> 7;
let word_id_low = word_id_high + 2;
let cur_shift = i & 127;
let word_high = unsafe { *self.words.get_unchecked(word_id_high) };
let word_low = unsafe { *self.words.get_unchecked(word_id_low) };
((word_high >> (cur_shift) & 1) << 1 | (word_low >> cur_shift) & 1) as u8
}
}
impl RankQuad for DataLine {
#[inline(always)]
fn rank(&self, symbol: u8, i: usize) -> Option<usize> {
if symbol >= 4 || i > 256 {
return None;
}
Some(unsafe { self.rank_unchecked(symbol, i) })
}
#[inline(always)]
unsafe fn rank_unchecked(&self, symbol: u8, i: usize) -> usize {
debug_assert!(symbol <= 3, "Only the four symbols in [0, 3] are possible.");
debug_assert!(i <= 256, "Only positions up to 256 are possible");
let (word_0, word_1) = self.normalize(symbol);
let last_word = i >> 7;
let offset = i & 127;
let mask_full = u128::MAX;
let mask_offset = (1_u128 << offset) - 1;
let mask = if last_word == 0 {
mask_offset
} else {
mask_full
};
let mut rank = (word_0 & mask).count_ones();
let mask = if last_word == 1 {
mask_offset
} else {
mask_full * (last_word == 2) as u128
};
rank += (word_1 & mask).count_ones();
rank as usize
}
}
#[derive(Clone, Default, Eq, PartialEq, Serialize, MemSize, MemDbg, Deserialize, Debug)]
pub struct QVector {
data: Box<[DataLine]>,
position: usize,
}
impl QVector {
pub fn is_empty(&self) -> bool {
self.position == 0
}
pub fn len(&self) -> usize {
self.position >> 1
}
pub fn iter(&self) -> QVectorIterator<&QVector> {
QVectorIterator { i: 0, qv: self }
}
}
impl AccessQuad for QVector {
#[inline(always)]
unsafe fn get_unchecked(&self, i: usize) -> u8 {
debug_assert!(i < self.position / 2);
let line = i >> 8;
let pos_in_last_line = i & 255;
let line = self.data.get_unchecked(line);
line.get_unchecked(pos_in_last_line)
}
#[inline(always)]
fn get(&self, i: usize) -> Option<u8> {
if i >= self.position >> 1 {
return None;
}
unsafe { Some(self.get_unchecked(i)) }
}
}
impl AsRef<QVector> for QVector {
fn as_ref(&self) -> &QVector {
self
}
}
pub struct QVectorIterator<QV: AsRef<QVector>> {
i: usize,
qv: QV,
}
impl<QV: AsRef<QVector>> Iterator for QVectorIterator<QV> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
let qv = self.qv.as_ref();
self.i += 1;
qv.get(self.i - 1)
}
}
impl IntoIterator for QVector {
type IntoIter = QVectorIterator<QVector>;
type Item = u8;
fn into_iter(self) -> Self::IntoIter {
QVectorIterator { i: 0, qv: self }
}
}
impl<'a> IntoIterator for &'a QVector {
type IntoIter = QVectorIterator<&'a QVector>;
type Item = u8;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T> FromIterator<T> for QVector
where
T: PrimInt + AsPrimitive<u8>,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
let mut qvb = QVectorBuilder::default();
qvb.extend(iter);
qvb.build()
}
}
#[derive(Clone, Default, Eq, MemSize, MemDbg, PartialEq)]
pub struct QVectorBuilder {
data: Vec<DataLine>,
position: usize,
}
impl QVectorBuilder {
const N_BITS_WORD: usize = 128 * 4;
pub fn build(self) -> QVector {
QVector {
data: self.data.into_boxed_slice(),
position: self.position,
}
}
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(n: usize) -> Self {
let capacity = (2 * n).div_ceil(Self::N_BITS_WORD);
Self {
data: Vec::with_capacity(capacity),
position: 0,
}
}
pub fn push(&mut self, symbol: u8) {
let pos_in_last_line = (self.position / 2) & 255;
if pos_in_last_line == 0 {
self.data.push(DataLine::default());
}
self.data
.last_mut()
.unwrap()
.set_symbol(symbol, pos_in_last_line as u8);
self.position += 2;
}
}
impl<T> FromIterator<T> for QVectorBuilder
where
T: PrimInt + AsPrimitive<u8>,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
let mut qvb = QVectorBuilder::default();
qvb.extend(iter);
qvb
}
}
impl<T> Extend<T> for QVectorBuilder
where
T: PrimInt + AsPrimitive<u8>,
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
for value in iter {
self.push(value.as_());
}
}
}
pub mod rs_qvector;
#[cfg(test)]
mod tests;