use core::{array::from_fn, marker::PhantomData};
use crate::{
constants::{LUT_SIZE_1BIT, LUT_SIZE_2BIT, LUT_SIZE_4BIT, MAX_DICT_ENTRIES},
float::AlpFloat,
};
pub trait AlpDecoder<F: AlpFloat>: Copy {
fn decode_offset(&self, off: u64) -> F;
#[inline(always)]
fn decode_int(&self, _val: F::Int) -> F {
F::ZERO
}
#[inline(always)]
fn build_lut_1(&self) -> [F; LUT_SIZE_1BIT] {
[self.decode_offset(0), self.decode_offset(1)]
}
#[inline(always)]
fn build_lut_2(&self) -> [F; LUT_SIZE_2BIT] {
[
self.decode_offset(0),
self.decode_offset(1),
self.decode_offset(2),
self.decode_offset(3),
]
}
#[inline(always)]
fn build_lut_4(&self) -> [F; LUT_SIZE_4BIT] {
from_fn(|i| self.decode_offset(i as u64))
}
}
#[derive(Copy, Clone)]
pub struct AlpFac1Decoder<F: AlpFloat> {
pub base: F::Int,
pub frac_flt: F,
}
impl<F: AlpFloat> AlpDecoder<F> for AlpFac1Decoder<F> {
#[inline(always)]
fn decode_offset(&self, off: u64) -> F {
F::decode_from_offset_fac1(off, self.base, self.frac_flt)
}
#[inline(always)]
fn decode_int(&self, val: F::Int) -> F {
F::decode_from_int_fac1(val, self.frac_flt)
}
}
#[derive(Copy, Clone)]
pub struct AlpMulDecoder<F: AlpFloat> {
pub base: F::Int,
pub fac_int: i64,
pub frac_flt: F,
}
impl<F: AlpFloat> AlpDecoder<F> for AlpMulDecoder<F> {
#[inline(always)]
fn decode_offset(&self, off: u64) -> F {
F::decode_from_offset(off, self.base, self.fac_int, self.frac_flt)
}
#[inline(always)]
fn decode_int(&self, val: F::Int) -> F {
F::decode_from_int(val, self.fac_int, self.frac_flt)
}
}
#[derive(Copy, Clone)]
pub struct AlpDivDecoder<F: AlpFloat> {
pub base: F::Int,
pub exp_factor: F,
}
impl<F: AlpFloat> AlpDecoder<F> for AlpDivDecoder<F> {
#[inline(always)]
fn decode_offset(&self, off: u64) -> F {
F::decode_from_offset_div(off, self.base, self.exp_factor)
}
#[inline(always)]
fn decode_int(&self, val: F::Int) -> F {
F::decode_from_int_div(val, self.exp_factor)
}
}
#[derive(Copy, Clone)]
pub struct AlpRdConstantDecoder<F: AlpFloat> {
pub high_bits: u64,
pub _phantom: PhantomData<F>,
}
impl<F: AlpFloat> AlpDecoder<F> for AlpRdConstantDecoder<F> {
#[inline(always)]
fn decode_offset(&self, off: u64) -> F {
F::from_u64_raw(self.high_bits | off)
}
}
#[derive(Copy, Clone)]
pub struct AlpDictDecoder<'a, F: AlpFloat> {
pub dict: &'a [F; MAX_DICT_ENTRIES],
}
impl<'a, F: AlpFloat> AlpDecoder<F> for AlpDictDecoder<'a, F> {
#[inline(always)]
fn decode_offset(&self, off: u64) -> F {
unsafe {
*self
.dict
.get_unchecked((off as usize) & (MAX_DICT_ENTRIES - 1))
}
}
}