use crate::mla::fmla;
use crate::util::DctSample;
use crate::{PxdctError, PxdctExecutor};
use num_traits::AsPrimitive;
use std::marker::PhantomData;
#[derive(Debug, Clone)]
pub(crate) struct Dct4Butterfly3<T> {
_phantom_data: PhantomData<T>,
}
impl<T: DctSample> Default for Dct4Butterfly3<T>
where
f64: AsPrimitive<T>,
{
fn default() -> Self {
Self {
_phantom_data: PhantomData {},
}
}
}
impl<T: DctSample> Dct4Butterfly3<T>
where
f64: AsPrimitive<T>,
{
#[inline(always)]
pub(crate) fn exec(&self, data: &mut [T; 3]) {
let identity = T::FRAC_1_SQRT_2;
let a = data[1] * identity;
let c = (data[0] + data[2]) * identity;
let s = (data[0] - data[2]) * identity;
let u0 = fmla(c, T::SQRT_3_OVER_2, s * T::HALF);
let mut v0 = fmla(c, T::HALF, -s * T::SQRT_3_OVER_2);
let mut u1 = u0 * T::HALF;
v0 *= T::SQRT_3_OVER_2;
u1 = u1 - a;
data[0] = u0 + a;
data[1] = u1 - v0;
data[2] = v0 + u1;
}
}
impl<T: DctSample> PxdctExecutor<T> for Dct4Butterfly3<T>
where
f64: AsPrimitive<T>,
{
fn execute(&self, data: &mut [T]) -> Result<(), PxdctError> {
if !data.len().is_multiple_of(3) {
return Err(PxdctError::InvalidSizeMultiplier(data.len(), self.length()));
}
for chunk in data.chunks_exact_mut(3) {
self.exec((&mut chunk[..3]).try_into().unwrap());
}
Ok(())
}
fn length(&self) -> usize {
3
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::PxdctExecutor;
use crate::butterflies::gen_test_butterfly;
use crate::tests::naive_dct4;
use rand::Rng;
gen_test_butterfly!(test_bf_dct4_3, f64, Dct4Butterfly3, 3, 1e-7, naive_dct4);
}