use std::marker::PhantomData;
use mem_dbg::*;
use value_traits::slices::SliceByValue;
use crate::bits::{BitFieldVec, BitVec};
use crate::dict::EliasFanoBuilder;
use crate::dict::elias_fano::EliasFano;
use crate::panic_if_out_of_bounds;
use crate::rank_sel::{Rank9, SelectZeroAdaptConst};
use crate::traits::Backend;
use crate::traits::TryIntoUnaligned;
use crate::traits::Unaligned;
use crate::traits::{BitVecOps, BitVecOpsMut};
use crate::traits::{RankUnchecked, SuccUnchecked};
type DenseIndex = Rank9<BitVec<Box<[u64]>>>;
#[doc(hidden)]
#[derive(Debug, Clone, MemSize, MemDbg)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SparseIndex<D, L = BitFieldVec<Box<[u64]>>> {
ef: EliasFano<u64, SelectZeroAdaptConst<BitVec<D>, Box<[usize]>, 12, 3>, L>,
first_invalid_pos: usize,
}
#[derive(Debug, Clone, MemSize, MemDbg)]
pub struct PartialArrayBuilder<T, B> {
builder: B,
values: Vec<T>,
len: usize,
min_next_pos: usize,
}
pub fn new_dense<T>(len: usize) -> PartialArrayBuilder<T, BitVec<Box<[u64]>>> {
let n_of_words = len.div_ceil(64);
let bit_vec = unsafe { BitVec::from_raw_parts(vec![0u64; n_of_words].into_boxed_slice(), len) };
PartialArrayBuilder {
builder: bit_vec,
values: vec![],
len,
min_next_pos: 0,
}
}
impl<T> PartialArrayBuilder<T, BitVec<Box<[u64]>>> {
pub fn set(&mut self, position: usize, value: T) {
if position < self.min_next_pos {
panic!(
"Positions must be set in increasing order: got {} after {}",
position,
self.min_next_pos - 1
);
}
panic_if_out_of_bounds!(position, self.len);
unsafe {
self.builder.set_unchecked(position, true);
}
self.values.push(value);
self.min_next_pos = position + 1;
}
#[must_use]
pub fn build(self) -> PartialArray<T, Rank9<BitVec<Box<[u64]>>>> {
let (bit_vec, values) = (self.builder, self.values);
let rank9 = Rank9::new(bit_vec);
let values = values.into_boxed_slice();
PartialArray {
index: rank9,
values,
_marker: PhantomData,
}
}
}
pub fn new_sparse<T>(
len: usize,
num_values: usize,
) -> PartialArrayBuilder<T, EliasFanoBuilder<u64>> {
PartialArrayBuilder {
builder: EliasFanoBuilder::<u64>::new(num_values, len as u64),
values: vec![],
len,
min_next_pos: 0,
}
}
impl<T> PartialArrayBuilder<T, EliasFanoBuilder<u64>> {
pub fn set(&mut self, position: usize, value: T) {
if position < self.min_next_pos {
panic!(
"Positions must be set in increasing order: got {} after {}",
position,
self.min_next_pos - 1
);
}
panic_if_out_of_bounds!(position, self.len);
unsafe { self.builder.push_unchecked(position as u64) };
self.values.push(value);
self.min_next_pos = position + 1;
}
#[must_use]
pub fn build(self) -> PartialArray<T, SparseIndex<Box<[usize]>>> {
let (builder, values) = (self.builder, self.values);
let ef_dict = builder.build_with_dict();
let values = values.into_boxed_slice();
PartialArray {
index: SparseIndex {
ef: ef_dict,
first_invalid_pos: self.min_next_pos,
},
values,
_marker: PhantomData,
}
}
}
impl<T> Extend<(usize, T)> for PartialArrayBuilder<T, BitVec<Box<[u64]>>> {
fn extend<I: IntoIterator<Item = (usize, T)>>(&mut self, iter: I) {
for (pos, val) in iter {
self.set(pos, val);
}
}
}
impl<T> Extend<(usize, T)> for PartialArrayBuilder<T, EliasFanoBuilder<u64>> {
fn extend<I: IntoIterator<Item = (usize, T)>>(&mut self, iter: I) {
for (pos, val) in iter {
self.set(pos, val);
}
}
}
#[derive(Debug, Clone, MemSize, MemDbg)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PartialArray<T, P, V = Box<[T]>> {
index: P,
values: V,
_marker: PhantomData<T>,
}
impl<T, P, V: AsRef<[T]>> PartialArray<T, P, V> {
#[inline(always)]
pub fn num_values(&self) -> usize {
self.values.as_ref().len()
}
}
impl<T, V: AsRef<[T]>> PartialArray<T, DenseIndex, V> {
#[inline(always)]
pub fn len(&self) -> usize {
self.index.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, position: usize) -> Option<&T> {
panic_if_out_of_bounds!(position, self.len());
unsafe { self.get_unchecked(position) }
}
pub unsafe fn get_unchecked(&self, position: usize) -> Option<&T> {
if !unsafe { self.index.get_unchecked(position) } {
return None;
}
let value_index = unsafe { self.index.rank_unchecked(position) };
Some(unsafe { self.values.as_ref().get_unchecked(value_index) })
}
}
impl<T, D: Backend<Word = usize> + AsRef<[usize]>, L: SliceByValue<Value = u64>, V: AsRef<[T]>>
PartialArray<T, SparseIndex<D, L>, V>
where
for<'b> &'b L: crate::traits::IntoUncheckedIterator<Item = u64>,
{
#[inline(always)]
pub fn len(&self) -> usize {
self.index.ef.upper_bound() as usize
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.index.ef.upper_bound() == 0
}
pub fn get(&self, position: usize) -> Option<&T> {
panic_if_out_of_bounds!(position, self.len());
unsafe { self.get_unchecked(position) }
}
pub unsafe fn get_unchecked(&self, position: usize) -> Option<&T> {
if position >= self.index.first_invalid_pos {
return None;
}
let (index, pos) = unsafe { self.index.ef.succ_unchecked::<false>(position as u64) };
if pos != position as u64 {
None
} else {
Some(unsafe { self.values.as_ref().get_unchecked(index) })
}
}
}
impl<T: Clone, V: AsRef<[T]>> SliceByValue for PartialArray<T, DenseIndex, V> {
type Value = Option<T>;
fn len(&self) -> usize {
self.len()
}
unsafe fn get_value_unchecked(&self, position: usize) -> Self::Value {
unsafe { self.get_unchecked(position) }.cloned()
}
}
impl<
T: Clone,
D: Backend<Word = usize> + AsRef<[usize]>,
L: SliceByValue<Value = u64>,
V: AsRef<[T]>,
> SliceByValue for PartialArray<T, SparseIndex<D, L>, V>
where
for<'b> &'b L: crate::traits::IntoUncheckedIterator<Item = u64>,
{
type Value = Option<T>;
fn len(&self) -> usize {
self.len()
}
unsafe fn get_value_unchecked(&self, position: usize) -> Self::Value {
unsafe { self.get_unchecked(position) }.cloned()
}
}
impl<D> TryIntoUnaligned for SparseIndex<D> {
type Unaligned = SparseIndex<D, Unaligned<BitFieldVec<Box<[u64]>>>>;
fn try_into_unaligned(
self,
) -> Result<Self::Unaligned, crate::traits::UnalignedConversionError> {
Ok(SparseIndex {
ef: self.ef.try_into_unaligned()?,
first_invalid_pos: self.first_invalid_pos,
})
}
}
impl<T, P: TryIntoUnaligned, V> TryIntoUnaligned for PartialArray<T, P, V> {
type Unaligned = PartialArray<T, P::Unaligned, V>;
fn try_into_unaligned(
self,
) -> Result<Self::Unaligned, crate::traits::UnalignedConversionError> {
Ok(PartialArray {
index: self.index.try_into_unaligned()?,
values: self.values,
_marker: PhantomData,
})
}
}