use vortex_array::compute::{scalar_at, ScalarAtFn};
use vortex_error::VortexResult;
use vortex_scalar::Scalar;
use crate::alp_rd::array::ALPRDArray;
use crate::ALPRDEncoding;
impl ScalarAtFn<ALPRDArray> for ALPRDEncoding {
fn scalar_at(&self, array: &ALPRDArray, index: usize) -> VortexResult<Scalar> {
let maybe_patched_value = array
.left_parts_patches()
.map(|patches| patches.get_patched(index))
.transpose()?
.flatten();
let left = match maybe_patched_value {
Some(patched_value) => u16::try_from(patched_value)?,
_ => {
let left_code: u16 = scalar_at(array.left_parts(), index)?.try_into()?;
array.left_parts_dict()[left_code as usize]
}
};
if array.is_f32() {
let right: u32 = scalar_at(array.right_parts(), index)?.try_into()?;
let packed = f32::from_bits((left as u32) << array.right_bit_width() | right);
Ok(packed.into())
} else {
let right: u64 = scalar_at(array.right_parts(), index)?.try_into()?;
let packed = f64::from_bits(((left as u64) << array.right_bit_width()) | right);
Ok(packed.into())
}
}
}
#[cfg(test)]
mod test {
use rstest::rstest;
use vortex_array::array::PrimitiveArray;
use vortex_array::compute::scalar_at;
use vortex_scalar::Scalar;
use crate::{ALPRDFloat, RDEncoder};
#[rstest]
#[case(0.1f32, 0.2f32, 3e25f32)]
#[case(0.1f64, 0.2f64, 3e100f64)]
fn test_scalar_at<T: ALPRDFloat + Into<Scalar>>(
#[case] a: T,
#[case] b: T,
#[case] outlier: T,
) {
let array = PrimitiveArray::from(vec![a, b, outlier]);
let encoded = RDEncoder::new(&[a, b]).encode(&array);
assert!(encoded.left_parts_patches().is_some());
assert_eq!(scalar_at(encoded.as_ref(), 0).unwrap(), a.into());
assert_eq!(scalar_at(encoded.as_ref(), 1).unwrap(), b.into());
assert_eq!(scalar_at(encoded.as_ref(), 2).unwrap(), outlier.into());
}
}