use std::cell::RefCell;
use std::collections::HashMap;
#[rustfmt::skip]
use ::realfft::num_traits::Zero;
use rustfft::Fft;
use rustfft::FftNum;
use rustfft::num_complex::Complex;
pub mod realfft;
pub trait DynFft<T> {
fn fft(&self) -> Box<[Complex<T>]>;
}
pub trait DynIfft<T> {
fn ifft(&self) -> Box<[Complex<T>]>;
}
pub trait DynFftMut<T> {
fn fft_mut(&mut self);
}
pub trait DynIfftMut<T> {
fn ifft_mut(&mut self);
}
trait StaticScratchFft<T: FftNum>: Fft<T> {
fn process_with_static_scratch(&self, buffer: &mut [Complex<T>]);
}
impl<T: FftNum + Default, U: ?Sized + Fft<T>> StaticScratchFft<T> for U {
fn process_with_static_scratch(&self, buffer: &mut [Complex<T>]) {
generic_singleton::get_or_init_thread_local!(
|| RefCell::new(HashMap::<usize, Box<[Complex<T>]>>::new()),
|map| {
let len = self.get_inplace_scratch_len();
let mut map = map.borrow_mut();
let scratch = map
.entry(len)
.or_insert_with(|| vec![Complex::default(); len].into_boxed_slice());
self.process_with_scratch(buffer, scratch);
}
);
}
}
impl<T: FftNum + Default + Zero> DynFft<T> for [T] {
fn fft(&self) -> Box<[Complex<T>]> {
let mut buffer = Vec::with_capacity(self.len());
for sample in self {
buffer.push(Complex::new(*sample, T::zero()));
}
crate::with_fft_algorithm::<T>(self.len(), |algorithm| {
algorithm.process_with_static_scratch(&mut buffer);
});
buffer.into_boxed_slice()
}
}
impl<T: FftNum + Default> DynFft<T> for [Complex<T>] {
fn fft(&self) -> Box<[Complex<T>]> {
let mut buffer: Box<[Complex<T>]> = self.into();
crate::with_fft_algorithm::<T>(self.len(), |fft| {
fft.process_with_static_scratch(&mut buffer);
});
buffer
}
}
impl<T: FftNum + Default> DynIfft<T> for [Complex<T>] {
fn ifft(&self) -> Box<[Complex<T>]> {
let mut buffer: Box<[Complex<T>]> = self.into();
crate::with_inverse_fft_algorithm::<T>(self.len(), |fft| {
fft.process_with_static_scratch(&mut buffer);
});
buffer
}
}
impl<T: FftNum + std::default::Default> DynFftMut<T> for [Complex<T>] {
fn fft_mut(&mut self) {
crate::with_fft_algorithm::<T>(self.len(), |fft| fft.process_with_static_scratch(self));
}
}
impl<T: FftNum + std::default::Default> DynIfftMut<T> for [Complex<T>] {
fn ifft_mut(&mut self) {
crate::with_inverse_fft_algorithm::<T>(self.len(), |fft| {
fft.process_with_static_scratch(self);
});
}
}