use crate::multicore_support::{Chunk, Complexity, MultiCoreSettings};
use crate::numbers::*;
use crate::simd_extensions::*;
use std;
use std::cmp;
use std::fmt;
use std::mem;
use std::ops::*;
use std::result;
use crate::{array_to_complex, array_to_complex_mut};
mod requirements;
pub use self::requirements::*;
mod to_from_vec_conversions;
pub use self::to_from_vec_conversions::*;
mod support_core;
pub use self::support_core::*;
#[cfg(any(feature = "std", test))]
mod support_std;
#[cfg(any(feature = "std", test))]
pub use self::support_std::*;
#[cfg(feature = "std")]
mod support_std_par;
#[cfg(feature = "std")]
pub use self::support_std_par::*;
mod vec_impl_and_indexers;
pub use self::vec_impl_and_indexers::*;
mod complex;
pub use self::complex::*;
mod real;
pub use self::real::*;
mod time_freq;
pub use self::time_freq::*;
mod rededicate_and_relations;
pub use self::rededicate_and_relations::*;
mod checks_and_results;
pub use self::checks_and_results::*;
mod general;
pub use self::general::*;
mod buffer;
pub use self::buffer::*;
use super::meta;
pub type TransRes<T> = result::Result<T, (ErrorReason, T)>;
pub type VoidResult = result::Result<(), ErrorReason>;
pub type ScalarResult<T> = result::Result<T, ErrorReason>;
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum DataDomain {
Time,
Frequency,
}
pub trait NumberSpace: fmt::Debug + cmp::PartialEq + Clone {
fn is_complex(&self) -> bool;
fn to_complex(&mut self);
fn to_real(&mut self);
}
pub trait Domain: fmt::Debug + cmp::PartialEq + Clone {
fn domain(&self) -> DataDomain;
fn to_freq(&mut self);
fn to_time(&mut self);
}
pub trait RealNumberSpace: NumberSpace {}
pub trait ComplexNumberSpace: NumberSpace {}
pub trait TimeDomain: Domain {}
pub trait FrequencyDomain: Domain {}
pub trait PosEq<O> {}
pub struct DspVec<S, T, N, D>
where
S: ToSlice<T>,
T: RealNumber,
N: NumberSpace,
D: Domain,
{
pub data: S,
delta: T,
domain: D,
number_space: N,
valid_len: usize,
multicore_settings: MultiCoreSettings,
}
#[derive(Clone, Copy)]
pub struct TypeMetaData<T, N, D> {
delta: T,
domain: D,
number_space: N,
multicore_settings: MultiCoreSettings,
}
impl<S, T, N, D> fmt::Debug for DspVec<S, T, N, D>
where
S: ToSlice<T>,
T: RealNumber,
D: Domain,
N: NumberSpace,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"DspVec {{ points: {}, domain: {:?}, number_space: {:?} }}",
self.valid_len, self.domain, self.number_space
)
}
}
fn swap_array_halves<T>(data: &mut [T], forward: bool)
where
T: Copy,
{
let len = data.len();
if len % 2 == 0 {
let (lo, up) = data.split_at_mut(len / 2);
for (lo, up) in lo.iter_mut().zip(up.iter_mut()) {
mem::swap(lo, up);
}
} else {
let step = if forward { len / 2 } else { len / 2 + 1 };
let mut temp = data[0];
let mut pos = step;
for _ in 0..len {
let pos_new = (pos + step) % len;
mem::swap(&mut temp, &mut data[pos]);
pos = pos_new;
}
}
}
fn complex_to_array<T>(complex: &[Complex<T>]) -> &[T]
where
T: RealNumber,
{
super::transmute_slice(complex)
}
fn complex_to_array_mut<T>(complex: &mut [Complex<T>]) -> &mut [T]
where
T: RealNumber,
{
super::transmute_slice_mut(complex)
}
impl<S: ToSliceMut<T>, T: RealNumber> DspVec<S, T, meta::RealOrComplex, meta::TimeOrFreq> {
pub fn is_erroneous(&self) -> bool {
self.valid_len == 0 && self.delta.is_nan()
}
}
impl<S, T, N, D> DspVec<S, T, N, D>
where
S: ToSliceMut<T>,
T: RealNumber,
N: NumberSpace,
D: Domain,
{
fn mark_vector_as_invalid(&mut self) {
self.valid_len = 0;
self.delta = T::nan();
}
#[inline]
fn pure_real_operation<A, F>(&mut self, op: F, argument: A, complexity: Complexity)
where
A: Sync + Copy + Send,
F: Fn(T, A) -> T + 'static + Sync,
{
{
let len = self.valid_len;
let array = self.data.to_slice_mut();
Chunk::execute_partial(
complexity,
&self.multicore_settings,
&mut array[0..len],
1,
argument,
move |array, argument| {
for num in array {
*num = op(*num, argument);
}
},
);
}
}
#[inline]
fn pure_complex_operation<A, F>(&mut self, op: F, argument: A, complexity: Complexity)
where
A: Sync + Copy + Send,
F: Fn(Complex<T>, A) -> Complex<T> + 'static + Sync,
{
{
let len = self.valid_len;
let array = self.data.to_slice_mut();
Chunk::execute_partial(
complexity,
&self.multicore_settings,
&mut array[0..len],
2,
argument,
move |array, argument| {
let array = array_to_complex_mut(array);
for num in array {
*num = op(*num, argument);
}
},
);
}
}
#[inline]
fn simd_real_operationf<Reg: SimdGeneric<T>, F, G>(
&mut self,
reg: RegType<Reg>,
simd_op: F,
scalar_op: G,
argument: T,
complexity: Complexity,
) where
F: Fn(Reg, Reg) -> Reg + 'static + Sync,
G: Fn(T, Reg) -> T + 'static + Sync,
{
self.simd_real_operation(reg, simd_op, scalar_op, Reg::splat(argument), complexity);
}
#[inline]
fn simd_real_operation<Reg: SimdGeneric<T>, A, F, G>(
&mut self,
_: RegType<Reg>,
simd_op: F,
scalar_op: G,
argument: A,
complexity: Complexity,
) where
A: Sync + Copy + Send,
F: Fn(Reg, A) -> Reg + 'static + Sync,
G: Fn(T, A) -> T + 'static + Sync,
{
{
let data_length = self.valid_len;
let array = self.data.to_slice_mut();
let partition = Reg::calc_data_alignment_reqs(&array[0..data_length]);
Chunk::execute_partial(
complexity,
&self.multicore_settings,
partition.center_mut(array),
Reg::LEN,
argument,
move |array, argument| {
let array = Reg::array_to_regs_mut(array);
for reg in array {
*reg = simd_op(*reg, argument);
}
},
);
for num in partition.edge_iter_mut(&mut array[0..data_length]) {
*num = scalar_op(*num, argument);
}
}
}
#[inline]
fn simd_complex_operationf<Reg: SimdGeneric<T>, F, G>(
&mut self,
reg: RegType<Reg>,
simd_op: F,
scalar_op: G,
argument: Complex<T>,
complexity: Complexity,
) where
F: Fn(Reg, Reg) -> Reg + 'static + Sync,
G: Fn(Complex<T>, Reg) -> Complex<T> + 'static + Sync,
{
self.simd_complex_operation(
reg,
simd_op,
scalar_op,
Reg::from_complex(argument),
complexity,
)
}
#[inline]
fn simd_complex_operation<Reg: SimdGeneric<T>, A, F, G>(
&mut self,
_: RegType<Reg>,
simd_op: F,
scalar_op: G,
argument: A,
complexity: Complexity,
) where
A: Sync + Copy + Send,
F: Fn(Reg, A) -> Reg + 'static + Sync,
G: Fn(Complex<T>, A) -> Complex<T> + 'static + Sync,
{
{
let data_length = self.valid_len;
let array = self.data.to_slice_mut();
let partition = Reg::calc_data_alignment_reqs(&array[0..data_length]);
Chunk::execute_partial(
complexity,
&self.multicore_settings,
partition.center_mut(array),
Reg::LEN,
argument,
move |array, argument| {
let array = Reg::array_to_regs_mut(array);
for reg in array {
*reg = simd_op(*reg, argument);
}
},
);
for num in partition.cedge_iter_mut(array_to_complex_mut(&mut array[0..data_length])) {
*num = scalar_op(*num, argument);
}
}
}
#[inline]
fn pure_complex_to_real_operation<A, F, B>(
&mut self,
buffer: &mut B,
op: F,
argument: A,
complexity: Complexity,
) where
A: Sync + Copy + Send,
F: Fn(Complex<T>, A) -> T + 'static + Sync,
B: for<'a> Buffer<'a, S, T>,
{
{
let data_length = self.len();
let mut result = buffer.borrow(data_length / 2);
{
let array = self.data.to_slice_mut();
let temp = result.to_slice_mut();
Chunk::from_src_to_dest(
complexity,
&self.multicore_settings,
&array[0..data_length],
2,
&mut temp[0..data_length / 2],
1,
argument,
move |array, range, target, argument| {
let array = array_to_complex(&array[range.start..range.end]);
for pair in array.iter().zip(target) {
let (src, dest) = pair;
*dest = op(*src, argument);
}
},
);
self.valid_len = data_length / 2;
}
result.trade(&mut self.data);
}
}
#[inline]
fn pure_complex_to_real_operation_inplace<A, F>(&mut self, op: F, argument: A)
where
A: Sync + Copy + Send,
F: Fn(Complex<T>, A) -> T + 'static + Sync,
{
{
let data_length = self.len();
let array = self.data.to_slice_mut();
for i in 0..data_length / 2 {
let input = Complex::new(array[2 * i], array[2 * i + 1]);
array[i] = op(input, argument);
}
self.valid_len /= 2;
}
}
#[inline]
fn simd_complex_to_real_operation<Reg: SimdGeneric<T>, A, F, G, B>(
&mut self,
_: RegType<Reg>,
buffer: &mut B,
simd_op: F,
scalar_op: G,
argument: A,
complexity: Complexity,
) where
A: Sync + Copy + Send,
F: Fn(Reg, A) -> Reg + 'static + Sync,
G: Fn(Complex<T>, A) -> T + 'static + Sync,
B: for<'a> Buffer<'a, S, T>,
{
let data_length = self.len();
let mut result = buffer.borrow(data_length / 2);
{
let array = self.data.to_slice_mut();
let temp = result.to_slice_mut();
let partition = Reg::calc_data_alignment_reqs(&array[0..data_length]);
Chunk::from_src_to_dest(
complexity,
&self.multicore_settings,
partition.center(&array),
Reg::LEN,
partition.rcenter_mut(temp),
Reg::LEN / 2,
argument,
move |array, range, target, argument| {
let array = Reg::array_to_regs(&array[range.start..range.end]);
let mut j = 0;
for reg in array {
let result = simd_op(*reg, argument);
result.store_half(target, j);
j += Reg::LEN / 2;
}
},
);
let array = array_to_complex(&array[0..data_length]);
for (src, dest) in partition
.cedge_iter(array)
.zip(partition.redge_iter_mut(temp))
{
*dest = scalar_op(*src, argument);
}
self.valid_len /= 2;
}
result.trade(&mut self.data);
}
#[inline]
fn swap_halves_priv(&mut self, forward: bool) {
let len = self.len();
if len == 0 {
return;
}
if self.is_complex() {
let data = self.data.to_slice_mut();
let data = array_to_complex_mut(&mut data[0..len]);
swap_array_halves(data, forward);
} else {
let data = self.data.to_slice_mut();
swap_array_halves(&mut data[0..len], forward);
}
}
#[inline]
fn multiply_window_priv<TT, CMut, FA, F>(
&mut self,
is_symmetric: bool,
convert_mut: CMut,
function_arg: FA,
fun: F,
) where
CMut: Fn(&mut [T]) -> &mut [TT],
FA: Copy + Sync + Send,
F: Fn(FA, usize, usize) -> TT + 'static + Sync,
TT: Zero + Mul<Output = TT> + Copy + Send + Sync + From<T>,
{
if !is_symmetric {
{
let len = self.len();
let points = self.points();
let data = self.data.to_slice_mut();
let converted = convert_mut(&mut data[0..len]);
Chunk::execute_with_range(
Complexity::Medium,
&self.multicore_settings,
converted,
1,
function_arg,
move |array, range, arg| {
let mut j = range.start;
for num in array {
*num = (*num) * fun(arg, j, points);
j += 1;
}
},
);
}
} else {
{
let len = self.len();
let points = self.points();
let data = self.data.to_slice_mut();
let converted = convert_mut(&mut data[0..len]);
Chunk::execute_sym_pairs_with_range(
Complexity::Medium,
&self.multicore_settings,
converted,
1,
function_arg,
move |array1, range, array2, _, arg| {
assert!(array1.len() >= array2.len());
let mut j = range.start;
let len1 = array1.len();
let len_diff = len1 - array2.len();
{
let iter1 = array1.iter_mut();
let iter2 = array2.iter_mut().rev();
for (num1, num2) in iter1.zip(iter2) {
let arg = fun(arg, j, points);
*num1 = (*num1) * arg;
*num2 = (*num2) * arg;
j += 1;
}
}
for num1 in &mut array1[len1 - len_diff..len1] {
let arg = fun(arg, j, points);
*num1 = (*num1) * arg;
j += 1;
}
},
);
}
}
}
}
pub struct NoTradeBufferBurrow<'a, T: RealNumber + 'a> {
data: &'a mut [T],
}
impl<'a, T: RealNumber> Deref for NoTradeBufferBurrow<'a, T> {
type Target = [T];
fn deref(&self) -> &[T] {
self.data
}
}
impl<'a, T: RealNumber> DerefMut for NoTradeBufferBurrow<'a, T> {
fn deref_mut(&mut self) -> &mut [T] {
self.data
}
}
impl<'a, S: ToSliceMut<T>, T: RealNumber> BufferBorrow<S, T> for NoTradeBufferBurrow<'a, T> {
fn trade(self, _: &mut S) {
}
}
struct NoTradeBuffer<S, T>
where
S: ToSliceMut<T>,
T: RealNumber,
{
data: S,
data_type: std::marker::PhantomData<T>,
}
impl<S, T> NoTradeBuffer<S, T>
where
S: ToSliceMut<T>,
T: RealNumber,
{
pub fn new(storage: S) -> NoTradeBuffer<S, T> {
NoTradeBuffer {
data: storage,
data_type: std::marker::PhantomData,
}
}
}
impl<'a, S, T> Buffer<'a, S, T> for NoTradeBuffer<S, T>
where
S: ToSliceMut<T>,
T: RealNumber + 'a,
{
type Borrow = NoTradeBufferBurrow<'a, T>;
fn borrow(&'a mut self, len: usize) -> Self::Borrow {
if self.data.len() < len {
panic!("NoTradeBuffer: Out of memory");
}
NoTradeBufferBurrow {
data: &mut self.data.to_slice_mut()[0..len],
}
}
fn alloc_len(&self) -> usize {
self.data.len()
}
}
#[cfg(test)]
mod tests {
use super::swap_array_halves;
#[test]
fn swap_halves_even_test() {
let mut v = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
swap_array_halves(&mut v, false);
assert_eq!(&v[..], &[5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn swap_halves_odd_foward_test() {
let mut v = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
swap_array_halves(&mut v, true);
assert_eq!(&v[..], &[6.0, 7.0, 8.0, 9.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
}
#[test]
fn swap_halves_odd_inverse_test() {
let mut v = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
swap_array_halves(&mut v, false);
assert_eq!(&v[..], &[5.0, 6.0, 7.0, 8.0, 9.0, 1.0, 2.0, 3.0, 4.0]);
}
}