yum/vfft
git clone https://git.yummers.dev/yum/vfft
c1d59be
master
1use num:: complex:: Complex ; 2use num:: traits::{ Float , FloatConst }; 3 4// Evaluates the base-`k` logarithm of `n`. 5// Precondition: `n` is a power of `k`. 6pub const fn log_k_of < const K : usize >( mut n : usize ) ->usize { 7let mut res =0 ; 8while n >1 { 9 n /=K ; 10 res +=1 ; 11} 12 res 13} 14 15pub fn is_power_of_k ( n : usize , k : usize ) ->bool { 16match n{ 170 =>false , 181 =>true , 19 _ => n % k ==0 &&is_power_of_k ( n / k, k), 20} 21} 22 23pub fn usize_to_float < T : Float >( value : usize ) ->T { 24 num:: cast ( value). unwrap () 25} 26 27// Calculates the "twiddle factors" for an n-element FFT, aka all of the nth roots of unity. 28pub fn precompute_twiddles < T : Float +FloatConst >( n : usize ) ->Vec < Complex < T >> { 29let mut result =vec! [ Complex ::< T >:: new ( T :: zero (), T :: zero ()); n]; 30 31let n_f64 =usize_to_float ::< f64 >( n); 32for iin 0 ..n{ 33let tw_f64 =Complex ::< f64 >:: cis ( -f64:: TAU () * usize_to_float ::< f64 >( i) /( n_f64)); 34 result[ i] =Complex :: new ( T :: from ( tw_f64. re ). unwrap (), T :: from ( tw_f64. im ). unwrap ()); 35} 36 37 result 38} 39 40// A FIFO data structure that stores a fixed number of elements. When it fills 41// up, pushing overwrites the oldest element. 42pub struct RingBuffer < T : Clone +Default > { 43data : Vec < T >, 44// Start points to the oldest element. End points to the next available 45// slot. 46start : usize , 47end : usize , 48// The number of elements currently in the buffer. 49n_elems : usize , 50} 51 52impl < T : Clone +Default > RingBuffer < T > { 53pub fn new ( capacity : usize ) ->Self { 54assert! ( capacity >0 ); 55Self { 56data : vec! [ T :: default (); capacity], 57start : 0 , 58end : 0 , 59n_elems : 0 , 60} 61} 62 63fn advance ( & self , index : usize ) ->usize { 64( index +1 ) %self . data . len () 65} 66 67// Pop one element. Returns an error if the buffer is empty. 68pub fn pop ( & mut self ) -> anyhow:: Result < & T > { 69if self . n_elems ==0 { 70 std:: hint:: cold_path (); 71return Err ( anyhow:: anyhow!( "RingBuffer is empty" )); 72} 73let result =& self . data [ self . start ]; 74self . start =self . advance ( self . start ); 75self . n_elems -=1 ; 76Ok ( result) 77} 78 79// Pop elements until `cb` return false. If `cb` returns an error, we 80// propagate it immediately and do not remove the element. 81pub fn pop_each ( 82& mut self , 83mut cb : impl FnMut ( & T ) -> anyhow:: Result < bool >, 84) -> anyhow:: Result <()> { 85while self . n_elems >0 { 86let keep_going =cb ( & self . data [ self . start ]) ?; 87self . pop () ?; 88if !keep_going{ 89break ; 90} 91} 92Ok (()) 93} 94 95// Push one element. 96pub fn push ( & mut self , value : T ) { 97self . data [ self . end ] = value; 98self . end =self . advance ( self . end ); 99if self . n_elems ==self . data . len () { 100self . start =self . advance ( self . start ); 101} else { 102self . n_elems +=1 ; 103} 104} 105 106// Push a slice of elements. 107pub fn push_slice ( & mut self , values : & [ T ]) { 108let capacity =self . data . len (); 109// Ensure that `values` is not longer than our ringbuf capacity. 110let values =& values[ values. len (). saturating_sub ( capacity) ..]; 111 112// Calculate number of elements to copy over after the end pointer. 113let n_after_end = values. len (). min ( capacity -self . end ); 114let values_after_end =& values[ ..n_after_end]; 115self . data [ self . end ..self . end + n_after_end]. clone_from_slice ( values_after_end); 116 117let values_before_start =& values[ n_after_end..]; 118self . data [ ..values_before_start. len ()]. clone_from_slice ( values_before_start); 119 120let n_overwritten = values. len (). saturating_sub ( capacity -self . n_elems ); 121self . start =( self . start + n_overwritten) % capacity; 122self . end =( self . end + values. len ()) % capacity; 123self . n_elems += values. len () - n_overwritten; 124} 125} 126 127# [ cfg ( test )] 128mod tests{ 129use super :: * ; 130 131# [ test ] 132fn ringbuf_tests () { 133// Sanity. 134{ 135let mut rb =RingBuffer ::< i32 >:: new ( 3 ); 136assert! ( rb. pop (). is_err ()); 137 rb. push ( 1 ); 138assert_eq! ( * rb. pop (). unwrap (), 1 ); 139 rb. push ( 2 ); 140 rb. push ( 3 ); 141 rb. push ( 4 ); 142assert_eq! ( * rb. pop (). unwrap (), 2 ); 143assert_eq! ( * rb. pop (). unwrap (), 3 ); 144assert_eq! ( * rb. pop (). unwrap (), 4 ); 145assert! ( rb. pop (). is_err ()); 146 rb. push_slice ( & [ 5 , 6 , 7 , 8 ]); 147assert_eq! ( * rb. pop (). unwrap (), 6 ); 148assert_eq! ( * rb. pop (). unwrap (), 7 ); 149assert_eq! ( * rb. pop (). unwrap (), 8 ); 150assert! ( rb. pop (). is_err ()); 151} 152// Callback access. 153{ 154let mut rb =RingBuffer ::< i32 >:: new ( 3 ); 155 rb. push ( 1 ); 156 rb. push ( 2 ); 157 rb. push ( 3 ); 158 rb. push ( 4 ); 159let mut iter =2 ; 160assert! ( 161 rb. pop_each ( |x|{ 162assert_eq! ( * x, iter); 163 iter +=1 ; 164Ok ( true ) 165}) 166. is_ok () 167); 168} 169// Size-1 edge cases. 170{ 171let mut rb =RingBuffer ::< i32 >:: new ( 1 ); 172 rb. push ( 1 ); 173assert_eq! ( * rb. pop (). unwrap (), 1 ); 174assert! ( rb. pop (). is_err ()); 175} 176} 177}