#![cfg(target_pointer_width = "64")]
use std::io::{Read, Write};
use anyhow::{anyhow, Result};
use num_traits::ToPrimitive;
use crate::int_vectors::prelude::*;
use crate::mii_sequences::{EliasFano, EliasFanoBuilder};
use crate::Serializable;
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct PrefixSummedEliasFano {
ef: EliasFano,
}
impl PrefixSummedEliasFano {
pub fn from_slice<T>(vals: &[T]) -> Result<Self>
where
T: ToPrimitive,
{
if vals.is_empty() {
return Err(anyhow!("vals must not be empty."));
}
let mut universe = 0;
for x in vals {
universe += x
.to_usize()
.ok_or_else(|| anyhow!("vals must consist only of values castable into usize."))?;
}
let mut b = EliasFanoBuilder::new(universe + 1, vals.len())?;
let mut cur = 0;
for x in vals {
cur += x.to_usize().unwrap();
b.push(cur)?;
}
Ok(Self { ef: b.build() })
}
pub const fn iter(&self) -> Iter {
Iter::new(self)
}
pub fn len(&self) -> usize {
self.ef.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn sum(&self) -> usize {
self.ef.universe() - 1
}
}
impl Build for PrefixSummedEliasFano {
fn build_from_slice<T>(vals: &[T]) -> Result<Self>
where
T: ToPrimitive,
Self: Sized,
{
Self::from_slice(vals)
}
}
impl NumVals for PrefixSummedEliasFano {
fn num_vals(&self) -> usize {
self.len()
}
}
impl Access for PrefixSummedEliasFano {
fn access(&self, pos: usize) -> Option<usize> {
self.ef.delta(pos)
}
}
impl Serializable for PrefixSummedEliasFano {
fn serialize_into<W: Write>(&self, writer: W) -> Result<usize> {
self.ef.serialize_into(writer)
}
fn deserialize_from<R: Read>(reader: R) -> Result<Self> {
let ef = EliasFano::deserialize_from(reader)?;
Ok(Self { ef })
}
fn size_in_bytes(&self) -> usize {
self.ef.size_in_bytes()
}
}
pub struct Iter<'a> {
efl: &'a PrefixSummedEliasFano,
pos: usize,
}
impl<'a> Iter<'a> {
pub const fn new(efl: &'a PrefixSummedEliasFano) -> Self {
Self { efl, pos: 0 }
}
}
impl Iterator for Iter<'_> {
type Item = usize;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.pos < self.efl.len() {
let x = self.efl.access(self.pos).unwrap();
self.pos += 1;
Some(x)
} else {
None
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.efl.len(), Some(self.efl.len()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_slice_uncastable() {
let e = PrefixSummedEliasFano::from_slice(&[u128::MAX]);
assert_eq!(
e.err().map(|x| x.to_string()),
Some("vals must consist only of values castable into usize.".to_string())
);
}
#[test]
fn test_serialize() {
let mut bytes = vec![];
let seq = PrefixSummedEliasFano::from_slice(&[5, 14, 334, 10]).unwrap();
let size = seq.serialize_into(&mut bytes).unwrap();
let other = PrefixSummedEliasFano::deserialize_from(&bytes[..]).unwrap();
assert_eq!(seq, other);
assert_eq!(size, bytes.len());
assert_eq!(size, seq.size_in_bytes());
}
}