diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ec6319..a33e600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## [6.4] +Released 12th June 2025 +### Added + - Implemented a new code path for out-of-place FFTs where the input vector is immutable: `Fft::process_immutable_with_scratch` (Thanks to @michaelciraci) (#157) +### Changed + - Refactored some RustFFT internals. Gives a small reduction in binary size, among other benefits (#161) + - Upgraded to 2021 edition (#162) + + ## [6.3] Released 17th April 2025 ### Changed diff --git a/Cargo.toml b/Cargo.toml index 468e619..b2f882c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "rustfft" -version = "6.3.0" +version = "6.4.0" authors = ["Allen Welkie ", "Elliott Mahler "] -edition = "2018" +edition = "2021" rust-version = "1.61" description = "High-performance FFT library written in pure Rust." diff --git a/benches/bench_rustfft.rs b/benches/bench_rustfft.rs index 387c5f3..af9c642 100644 --- a/benches/bench_rustfft.rs +++ b/benches/bench_rustfft.rs @@ -203,7 +203,7 @@ fn bench_good_thomas(b: &mut Bencher, width: usize, height: usize) { let width_fft = planner.plan_fft_forward(width); let height_fft = planner.plan_fft_forward(height); - let fft : Arc> = Arc::new(GoodThomasAlgorithm::new(width_fft, height_fft)); + let fft : Arc> = Arc::new(GoodThomasAlgorithm::new(width_fft, height_fft)); let mut buffer = vec![Complex::zero(); width * height]; let mut scratch = vec![Complex::zero(); fft.get_inplace_scratch_len()]; @@ -228,7 +228,7 @@ fn bench_good_thomas_setup(b: &mut Bencher, width: usize, height: usize) { let height_fft = planner.plan_fft_forward(height); b.iter(|| { - let fft : Arc> = Arc::new(GoodThomasAlgorithm::new(Arc::clone(&width_fft), Arc::clone(&height_fft))); + let fft : Arc> = Arc::new(GoodThomasAlgorithm::new(Arc::clone(&width_fft), Arc::clone(&height_fft))); test::black_box(fft); }); } @@ -251,7 +251,7 @@ fn bench_mixed_radix_setup(b: &mut Bencher, width: usize, height: usize) { let height_fft = planner.plan_fft_forward(height); b.iter(|| { - let fft : Arc> = Arc::new(MixedRadix::new(Arc::clone(&width_fft), Arc::clone(&height_fft))); + let fft : Arc> = Arc::new(MixedRadix::new(Arc::clone(&width_fft), Arc::clone(&height_fft))); test::black_box(fft); }); } @@ -274,7 +274,7 @@ fn bench_small_mixed_radix_setup(b: &mut Bencher, width: usize, height: usize) { let height_fft = planner.plan_fft_forward(height); b.iter(|| { - let fft : Arc> = Arc::new(MixedRadixSmall::new(Arc::clone(&width_fft), Arc::clone(&height_fft))); + let fft : Arc> = Arc::new(MixedRadixSmall::new(Arc::clone(&width_fft), Arc::clone(&height_fft))); test::black_box(fft); }); } @@ -294,7 +294,7 @@ fn bench_mixed_radix(b: &mut Bencher, width: usize, height: usize) { let width_fft = planner.plan_fft_forward(width); let height_fft = planner.plan_fft_forward(height); - let fft : Arc> = Arc::new(MixedRadix::new(width_fft, height_fft)); + let fft : Arc> = Arc::new(MixedRadix::new(width_fft, height_fft)); let mut buffer = vec![Complex{re: 0_f32, im: 0_f32}; fft.len()]; let mut scratch = vec![Complex{re: 0_f32, im: 0_f32}; fft.get_inplace_scratch_len()]; @@ -310,7 +310,7 @@ fn bench_mixed_radix(b: &mut Bencher, width: usize, height: usize) { #[bench] fn mixed_radix_2048_3(b: &mut Bencher) { bench_mixed_radix(b, 2048, 3); } #[bench] fn mixed_radix_2048_2187(b: &mut Bencher) { bench_mixed_radix(b, 2048, 2187); } -fn plan_butterfly_fft(len: usize) -> Arc> { +fn plan_butterfly_fft(len: usize) -> Arc> { match len { 2 => Arc::new(Butterfly2::new(FftDirection::Forward)), 3 => Arc::new(Butterfly3::new(FftDirection::Forward)), @@ -332,7 +332,7 @@ fn bench_mixed_radix_small(b: &mut Bencher, width: usize, height: usize) { let width_fft = plan_butterfly_fft(width); let height_fft = plan_butterfly_fft(height); - let fft : Arc> = Arc::new(MixedRadixSmall::new(width_fft, height_fft)); + let fft : Arc> = Arc::new(MixedRadixSmall::new(width_fft, height_fft)); let mut signal = vec![Complex{re: 0_f32, im: 0_f32}; width * height]; let mut spectrum = signal.clone(); @@ -351,7 +351,7 @@ fn bench_good_thomas_small(b: &mut Bencher, width: usize, height: usize) { let width_fft = plan_butterfly_fft(width); let height_fft = plan_butterfly_fft(height); - let fft : Arc> = Arc::new(GoodThomasAlgorithmSmall::new(width_fft, height_fft)); + let fft : Arc> = Arc::new(GoodThomasAlgorithmSmall::new(width_fft, height_fft)); let mut signal = vec![Complex{re: 0_f32, im: 0_f32}; width * height]; let mut spectrum = signal.clone(); @@ -371,7 +371,7 @@ fn bench_raders_scalar(b: &mut Bencher, len: usize) { let mut planner = rustfft::FftPlanner::new(); let inner_fft = planner.plan_fft_forward(len - 1); - let fft : Arc> = Arc::new(RadersAlgorithm::new(inner_fft)); + let fft : Arc> = Arc::new(RadersAlgorithm::new(inner_fft)); let mut buffer = vec![Complex{re: 0_f32, im: 0_f32}; len]; let mut scratch = vec![Complex{re: 0_f32, im: 0_f32}; fft.get_inplace_scratch_len()]; @@ -399,7 +399,7 @@ fn bench_raders_scalar(b: &mut Bencher, len: usize) { fn bench_bluesteins_scalar_prime(b: &mut Bencher, len: usize) { let mut planner = rustfft::FftPlanner::new(); let inner_fft = planner.plan_fft_forward((len * 2 - 1).checked_next_power_of_two().unwrap()); - let fft : Arc> = Arc::new(BluesteinsAlgorithm::new(len, inner_fft)); + let fft : Arc> = Arc::new(BluesteinsAlgorithm::new(len, inner_fft)); let mut buffer = vec![Zero::zero(); len]; let mut scratch = vec![Zero::zero(); fft.get_inplace_scratch_len()]; diff --git a/benches/bench_rustfft_scalar.rs b/benches/bench_rustfft_scalar.rs index 371aebf..76b7d4c 100644 --- a/benches/bench_rustfft_scalar.rs +++ b/benches/bench_rustfft_scalar.rs @@ -279,7 +279,7 @@ fn bench_good_thomas(b: &mut Bencher, width: usize, height: usize) { let width_fft = planner.plan_fft_forward(width); let height_fft = planner.plan_fft_forward(height); - let fft: Arc> = Arc::new(GoodThomasAlgorithm::new(width_fft, height_fft)); + let fft: Arc> = Arc::new(GoodThomasAlgorithm::new(width_fft, height_fft)); let mut buffer = vec![Complex::zero(); width * height]; let mut scratch = vec![Complex::zero(); fft.get_inplace_scratch_len()]; @@ -320,7 +320,7 @@ fn bench_good_thomas_setup(b: &mut Bencher, width: usize, height: usize) { let height_fft = planner.plan_fft_forward(height); b.iter(|| { - let fft: Arc> = Arc::new(GoodThomasAlgorithm::new( + let fft: Arc> = Arc::new(GoodThomasAlgorithm::new( Arc::clone(&width_fft), Arc::clone(&height_fft), )); @@ -368,7 +368,7 @@ fn bench_mixed_radix(b: &mut Bencher, width: usize, height: usize) { let width_fft = planner.plan_fft_forward(width); let height_fft = planner.plan_fft_forward(height); - let fft: Arc> = Arc::new(MixedRadix::new(width_fft, height_fft)); + let fft: Arc> = Arc::new(MixedRadix::new(width_fft, height_fft)); let mut buffer = vec![ Complex { @@ -413,7 +413,7 @@ fn mixed_radix_0032_27(b: &mut Bencher) { //#[bench] fn mixed_radix_2048_3(b: &mut Bencher) { bench_mixed_radix(b, 2048, 3); } //#[bench] fn mixed_radix_2048_2187(b: &mut Bencher) { bench_mixed_radix(b, 2048, 2187); } -fn plan_butterfly_fft(len: usize) -> Arc> { +fn plan_butterfly_fft(len: usize) -> Arc> { match len { 2 => Arc::new(Butterfly2::new(FftDirection::Forward)), 3 => Arc::new(Butterfly3::new(FftDirection::Forward)), @@ -434,7 +434,7 @@ fn bench_mixed_radix_small(b: &mut Bencher, width: usize, height: usize) { let width_fft = plan_butterfly_fft(width); let height_fft = plan_butterfly_fft(height); - let fft: Arc> = Arc::new(MixedRadixSmall::new(width_fft, height_fft)); + let fft: Arc> = Arc::new(MixedRadixSmall::new(width_fft, height_fft)); let mut signal = vec![ Complex { @@ -472,7 +472,7 @@ fn bench_good_thomas_small(b: &mut Bencher, width: usize, height: usize) { let width_fft = plan_butterfly_fft(width); let height_fft = plan_butterfly_fft(height); - let fft: Arc> = Arc::new(GoodThomasAlgorithmSmall::new(width_fft, height_fft)); + let fft: Arc> = Arc::new(GoodThomasAlgorithmSmall::new(width_fft, height_fft)); let mut signal = vec![ Complex { @@ -511,7 +511,7 @@ fn bench_raders_scalar(b: &mut Bencher, len: usize) { let mut planner = rustfft::FftPlannerScalar::new(); let inner_fft = planner.plan_fft_forward(len - 1); - let fft: Arc> = Arc::new(RadersAlgorithm::new(inner_fft)); + let fft: Arc> = Arc::new(RadersAlgorithm::new(inner_fft)); let mut buffer = vec![ Complex { @@ -553,7 +553,7 @@ fn bench_raders_scalar(b: &mut Bencher, len: usize) { fn bench_bluesteins_scalar_prime(b: &mut Bencher, len: usize) { let mut planner = rustfft::FftPlannerScalar::new(); let inner_fft = planner.plan_fft_forward((len * 2 - 1).checked_next_power_of_two().unwrap()); - let fft: Arc> = Arc::new(BluesteinsAlgorithm::new(len, inner_fft)); + let fft: Arc> = Arc::new(BluesteinsAlgorithm::new(len, inner_fft)); let mut buffer = vec![Zero::zero(); len]; let mut scratch = vec![Zero::zero(); fft.get_inplace_scratch_len()]; diff --git a/src/lib.rs b/src/lib.rs index c2154db..2bcb30d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ //! //! ### Usage //! -//! The recommended way to use RustFFT is to create a [`FftPlanner`](crate::FftPlanner) instance and then call its +//! The recommended way to use RustFFT is to create a [`FftPlanner`] instance and then call its //! [`plan_fft`](crate::FftPlanner::plan_fft) method. This method will automatically choose which FFT algorithms are best //! for a given size and initialize the required buffers and precomputed data. //! @@ -26,7 +26,7 @@ //! let mut buffer = vec![Complex{ re: 0.0f32, im: 0.0f32 }; 1234]; //! fft.process(&mut buffer); //! ``` -//! The planner returns trait objects of the [`Fft`](crate::Fft) trait, allowing for FFT sizes that aren't known +//! The planner returns trait objects of the [`Fft`] trait, allowing for FFT sizes that aren't known //! until runtime. //! //! RustFFT also exposes individual FFT algorithms. For example, if you know beforehand that you need a power-of-two FFT, you can @@ -42,9 +42,9 @@ //! fft.process(&mut buffer); //! ``` //! -//! For the vast majority of situations, simply using the [`FftPlanner`](crate::FftPlanner) will be enough, but +//! For the vast majority of situations, simply using the [`FftPlanner`] will be enough, but //! advanced users may have better insight than the planner into which algorithms are best for a specific size. See the -//! [`algorithm`](crate::algorithm) module for a complete list of scalar algorithms implemented by RustFFT. +//! [`algorithm`] module for a complete list of scalar algorithms implemented by RustFFT. //! //! Users should beware, however, that bypassing the planner will disable all AVX, SSE, Neon, and WASM SIMD optimizations. //!