use super::delta_tables;
use super::gamma::{GammaReadParam, GammaWriteParam, len_gamma_param};
use crate::traits::*;
#[must_use]
#[inline(always)]
pub fn len_delta_param<const USE_DELTA_TABLE: bool, const USE_GAMMA_TABLE: bool>(n: u64) -> usize {
debug_assert!(n < u64::MAX);
if USE_DELTA_TABLE {
if n < delta_tables::LEN.len() as u64 {
return delta_tables::LEN[n as usize] as usize;
}
}
let λ = (n + 1).ilog2();
λ as usize + len_gamma_param::<USE_GAMMA_TABLE>(λ as _)
}
#[must_use]
#[inline(always)]
pub fn len_delta(n: u64) -> usize {
#[cfg(target_arch = "arm")]
return len_delta_param::<false, false>(n);
#[cfg(not(target_arch = "arm"))]
return len_delta_param::<false, true>(n);
}
pub trait DeltaRead<E: Endianness>: BitRead<E> {
fn read_delta(&mut self) -> Result<u64, Self::Error>;
}
pub trait DeltaReadParam<E: Endianness>: GammaReadParam<E> {
fn read_delta_param<const USE_DELTA_TABLE: bool, const USE_GAMMA_TABLE: bool>(
&mut self,
) -> Result<u64, Self::Error>;
}
#[inline(always)]
fn default_read_delta<E: Endianness, B: GammaReadParam<E>, const USE_GAMMA_TABLE: bool>(
backend: &mut B,
) -> Result<u64, B::Error> {
let len = backend.read_gamma_param::<USE_GAMMA_TABLE>()?;
debug_assert!(len < 64);
Ok(backend.read_bits(len as usize)? + (1 << len) - 1)
}
impl<B: GammaReadParam<BE>> DeltaReadParam<BE> for B {
#[inline(always)]
fn read_delta_param<const USE_DELTA_TABLE: bool, const USE_GAMMA_TABLE: bool>(
&mut self,
) -> Result<u64, B::Error> {
const {
if USE_DELTA_TABLE {
delta_tables::check_read_table(B::PEEK_BITS)
}
}
if USE_DELTA_TABLE {
let (len_with_flag, value_or_gamma) = delta_tables::read_table_be(self);
if len_with_flag > 0 {
return Ok(value_or_gamma);
} else if len_with_flag < 0 {
let gamma_len = value_or_gamma;
debug_assert!(gamma_len < 64);
return Ok(self.read_bits(gamma_len as usize)? + (1 << gamma_len) - 1);
}
}
default_read_delta::<BE, _, USE_GAMMA_TABLE>(self)
}
}
impl<B: GammaReadParam<LE>> DeltaReadParam<LE> for B {
#[inline(always)]
fn read_delta_param<const USE_DELTA_TABLE: bool, const USE_GAMMA_TABLE: bool>(
&mut self,
) -> Result<u64, B::Error> {
const {
if USE_DELTA_TABLE {
delta_tables::check_read_table(B::PEEK_BITS)
}
}
if USE_DELTA_TABLE {
let (len_with_flag, value_or_gamma) = delta_tables::read_table_le(self);
if len_with_flag > 0 {
return Ok(value_or_gamma);
} else if len_with_flag < 0 {
let gamma_len = value_or_gamma;
debug_assert!(gamma_len < 64);
return Ok(self.read_bits(gamma_len as usize)? + (1 << gamma_len) - 1);
}
}
default_read_delta::<LE, _, USE_GAMMA_TABLE>(self)
}
}
pub trait DeltaWrite<E: Endianness>: BitWrite<E> {
fn write_delta(&mut self, n: u64) -> Result<usize, Self::Error>;
}
pub trait DeltaWriteParam<E: Endianness>: GammaWriteParam<E> {
fn write_delta_param<const USE_DELTA_TABLE: bool, const USE_GAMMA_TABLE: bool>(
&mut self,
n: u64,
) -> Result<usize, Self::Error>;
}
impl<B: GammaWriteParam<BE>> DeltaWriteParam<BE> for B {
#[inline(always)]
#[allow(clippy::collapsible_if)]
fn write_delta_param<const USE_DELTA_TABLE: bool, const USE_GAMMA_TABLE: bool>(
&mut self,
n: u64,
) -> Result<usize, Self::Error> {
if USE_DELTA_TABLE {
if let Some(len) = delta_tables::write_table_be(self, n)? {
return Ok(len);
}
}
default_write_delta::<BE, _, USE_GAMMA_TABLE>(self, n)
}
}
impl<B: GammaWriteParam<LE>> DeltaWriteParam<LE> for B {
#[inline(always)]
#[allow(clippy::collapsible_if)]
fn write_delta_param<const USE_DELTA_TABLE: bool, const USE_GAMMA_TABLE: bool>(
&mut self,
n: u64,
) -> Result<usize, Self::Error> {
if USE_DELTA_TABLE {
if let Some(len) = delta_tables::write_table_le(self, n)? {
return Ok(len);
}
}
default_write_delta::<LE, _, USE_GAMMA_TABLE>(self, n)
}
}
#[inline(always)]
fn default_write_delta<E: Endianness, B: GammaWriteParam<E>, const USE_GAMMA_TABLE: bool>(
backend: &mut B,
mut n: u64,
) -> Result<usize, B::Error> {
debug_assert!(n < u64::MAX);
n += 1;
let λ = n.ilog2();
#[cfg(feature = "checks")]
{
n ^= 1 << λ;
}
Ok(backend.write_gamma_param::<USE_GAMMA_TABLE>(λ as _)? + backend.write_bits(n, λ as _)?)
}