use crate::transpose::Transposition;
use crate::util::{DctSample, try_vec, validate_scratch};
use crate::{PxdctError, PxdctExecutor};
use std::sync::Arc;
pub trait MultidimensionalDctExecutor<T> {
fn execute(&self, data: &mut [T]) -> Result<(), PxdctError>;
fn execute_with_scratch(&self, data: &mut [T], scratch: &mut [T]) -> Result<(), PxdctError>;
fn width(&self) -> usize;
fn height(&self) -> usize;
fn scratch_size(&self) -> usize;
}
pub(crate) struct TwoDimensionalDct<T> {
pub(crate) width_executor: Arc<dyn PxdctExecutor<T> + Send + Sync>,
pub(crate) height_executor: Arc<dyn PxdctExecutor<T> + Send + Sync>,
pub(crate) transpose_width_to_height: Arc<dyn Transposition<T> + Send + Sync>,
pub(crate) width: usize,
pub(crate) height: usize,
pub(crate) width_scratch_size: usize,
pub(crate) height_scratch_size: usize,
}
impl<T: DctSample> MultidimensionalDctExecutor<T> for TwoDimensionalDct<T> {
fn execute(&self, data: &mut [T]) -> Result<(), PxdctError> {
let mut scratch = try_vec![T::default(); self.scratch_size()];
self.execute_with_scratch(data, &mut scratch)
}
fn execute_with_scratch(&self, data: &mut [T], scratch: &mut [T]) -> Result<(), PxdctError> {
let full_size = self.width * self.height;
if !data.len().is_multiple_of(full_size) {
return Err(PxdctError::InvalidSizeMultiplier(data.len(), full_size));
}
let scratch = validate_scratch!(scratch, self.scratch_size());
let (scratch, rem_scratch) = scratch.split_at_mut(full_size);
for chunk in data.chunks_exact_mut(full_size) {
let (width_scratch, _) = rem_scratch.split_at_mut(self.width_scratch_size);
self.width_executor
.execute_into_with_scratch(chunk, scratch, width_scratch)?;
self.transpose_width_to_height.transpose(scratch, chunk);
let (height_scratch, _) = rem_scratch.split_at_mut(self.height_scratch_size);
self.height_executor
.execute_with_scratch(chunk, height_scratch)?;
}
Ok(())
}
#[inline]
fn width(&self) -> usize {
self.width
}
#[inline]
fn height(&self) -> usize {
self.height
}
#[inline]
fn scratch_size(&self) -> usize {
self.width * self.height + self.width_scratch_size.max(self.height_scratch_size)
}
}