use crate::twiddles::{generate_twiddles, generate_twiddles_simd_32, generate_twiddles_simd_64};
#[derive(Copy, Clone)]
pub enum Direction {
Forward = 1,
Reverse = -1,
}
macro_rules! impl_planner_for {
($struct_name:ident, $precision:ident, $generate_twiddles_simd_fn:ident) => {
pub struct $struct_name {
/// The real components of the twiddle factors
pub twiddles_re: Vec<$precision>,
pub twiddles_im: Vec<$precision>,
}
impl $struct_name {
pub fn new(num_points: usize, _direction: Direction) -> Self {
assert!(num_points > 0 && num_points.is_power_of_two());
if num_points <= 4 {
return Self {
twiddles_re: vec![],
twiddles_im: vec![],
};
}
let dist = num_points >> 1;
let (twiddles_re, twiddles_im) = if dist >= 8 * 2 {
$generate_twiddles_simd_fn(dist, Direction::Forward)
} else {
generate_twiddles(dist, Direction::Forward)
};
assert_eq!(twiddles_re.len(), twiddles_im.len());
Self {
twiddles_re,
twiddles_im,
}
}
pub(crate) fn num_twiddles(&self) -> usize {
assert_eq!(self.twiddles_re.len(), self.twiddles_im.len());
self.twiddles_re.len()
}
}
};
}
impl_planner_for!(Planner64, f64, generate_twiddles_simd_64);
impl_planner_for!(Planner32, f32, generate_twiddles_simd_32);
#[cfg(test)]
mod tests {
use super::*;
macro_rules! test_no_twiddles {
($test_name:ident, $planner:ty) => {
#[test]
fn $test_name() {
for num_points in [2, 4] {
let planner = <$planner>::new(num_points, Direction::Forward);
assert!(planner.twiddles_im.is_empty() && planner.twiddles_re.is_empty());
}
}
};
}
test_no_twiddles!(no_twiddles_64, Planner64);
test_no_twiddles!(no_twiddles_32, Planner32);
}