use std::marker::PhantomData;
use mem_dbg::*;
use value_traits::slices::SliceByValue;
use crate::bits::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::{BitVecOps, BitVecOpsMut};
use crate::traits::{RankUnchecked, SuccUnchecked};
type DenseIndex = Rank9<BitVec<Box<[usize]>>>;
#[doc(hidden)]
#[derive(Debug, Clone, MemDbg, MemSize)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SparseIndex<D> {
ef: EliasFano<SelectZeroAdaptConst<BitVec<D>, D, 12, 3>>,
first_invalid_pos: usize,
}
#[derive(Debug, Clone, MemDbg, MemSize)]
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<[usize]>>> {
PartialArrayBuilder {
builder: BitVec::new(len).into(),
values: vec![],
len,
min_next_pos: 0,
}
}
impl<T> PartialArrayBuilder<T, BitVec<Box<[usize]>>> {
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;
}
pub fn build(self) -> PartialArray<T, Rank9<BitVec<Box<[usize]>>>> {
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> {
PartialArrayBuilder {
builder: EliasFanoBuilder::new(num_values, len),
values: vec![],
len,
min_next_pos: 0,
}
}
impl<T> PartialArrayBuilder<T, EliasFanoBuilder> {
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) };
self.values.push(value);
self.min_next_pos = position + 1;
}
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<[usize]>>> {
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> {
fn extend<I: IntoIterator<Item = (usize, T)>>(&mut self, iter: I) {
for (pos, val) in iter {
self.set(pos, val);
}
}
}
#[derive(Debug, Clone, MemDbg, MemSize)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PartialArray<T, P, V: AsRef<[T]> = 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: AsRef<[usize]>, V: AsRef<[T]>> PartialArray<T, SparseIndex<D>, V> {
#[inline(always)]
pub fn len(&self) -> usize {
self.index.ef.upper_bound()
}
#[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 position >= self.index.first_invalid_pos {
return None;
}
let (index, pos) = unsafe { self.index.ef.succ_unchecked::<false>(position) };
if pos != position {
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: AsRef<[usize]>, V: AsRef<[T]>> SliceByValue
for PartialArray<T, SparseIndex<D>, 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()
}
}