use crate::ring_buffer::single_buffer::generic_buffer::{
Buffer, F64Buffer, MirrorBuffer, RingBuffer,
};
use std::simd::Simd;
impl<const N: usize> Buffer<Simd<f64, N>> {
fn to_simd_buffer(f64_buffers: &[&[f64]], capacity: usize, mirror: bool) -> Self {
let count = f64_buffers[0].len().min(capacity);
let mut simd_vals =
Vec::<Simd<f64, N>>::with_capacity(if mirror { capacity * 2 } else { capacity });
for i in 0..capacity {
let mut vals = [0.0; N];
for j in 0..N {
vals[j] = unsafe { *f64_buffers.get_unchecked(j).get_unchecked(i) };
}
simd_vals.push(Simd::from_array(vals));
}
if mirror {
simd_vals.extend_from_within(..);
}
Self {
vals: simd_vals,
index: 0,
prev_idx: capacity - 1, capacity,
count: count,
}
}
pub fn to_f64_buffers(&self) -> Vec<F64Buffer> {
let mut vals = Vec::with_capacity(N);
for _ in 0..N {
vals.push(Vec::with_capacity(self.capacity));
}
for simd_val in self.vals.iter() {
let val = simd_val.to_array();
for j in 0..N {
vals[j].push(val[j]);
}
}
let mut buffers = Vec::with_capacity(N);
for val in vals.into_iter() {
buffers.push(F64Buffer {
vals: val,
prev_idx: self.prev_idx,
capacity: self.capacity,
count: self.count,
index: self.index,
});
}
buffers
}
}
pub trait SimdRingBuffer<const N: usize>: RingBuffer<Simd<f64, N>> {
fn from_f64_buffers(f64_buffers: Vec<&Buffer<f64>>) -> Self;
}
impl<const N: usize> SimdRingBuffer<N> for Buffer<Simd<f64, N>> {
fn from_f64_buffers(buffers: Vec<&Buffer<f64>>) -> Self {
debug_assert_eq!(buffers.len(), N, "Number of buffers must match SIMD width");
let capacity = buffers[0].get_capacity();
let ordered_vecs: Vec<Vec<f64>> = buffers.iter().map(|buf| buf.to_ordered_vec()).collect();
let slices: Vec<&[f64]> = ordered_vecs.iter().map(|vec| vec.as_slice()).collect();
Self::to_simd_buffer(&slices, capacity, false)
}
}
pub trait SimdMirrorBuffer<const N: usize>: MirrorBuffer<Simd<f64, N>> {
fn from_f64_buffers(f64_slices: Vec<&Buffer<f64>>) -> Self;
}
#[cfg(feature = "portable_simd")]
impl<const N: usize> SimdMirrorBuffer<N> for Buffer<Simd<f64, N>> {
fn from_f64_buffers(buffers: Vec<&Buffer<f64>>) -> Self {
debug_assert_eq!(buffers.len(), N, "Number of buffers must match SIMD width");
let capacity = buffers[0].get_capacity();
let slices: Vec<&[f64]> = buffers
.iter()
.map(|buf| <Buffer<f64> as MirrorBuffer<f64>>::get_slice(buf))
.collect();
Self::to_simd_buffer(&slices, capacity, true) }
}
pub trait FlatSimdBuffer<const N: usize> {
fn from_f64_buffers(buffers: Vec<&Buffer<f64>>) -> &Self;
fn to_f64_buffers(&self, periods: [usize; N]) -> Vec<F64Buffer>;
}
impl<const N: usize> FlatSimdBuffer<N> for Buffer {
fn from_f64_buffers(buffers: Vec<&Buffer<f64>>) -> &Self {
let mut i = 0;
for (j, buffer) in buffers.iter().skip(1).enumerate() {
if buffer.capacity > buffers[i].capacity {
i = j;
}
}
buffers[i]
}
fn to_f64_buffers(&self, periods: [usize; N]) -> Vec<F64Buffer> {
let mut buffers = Vec::with_capacity(N);
for period in periods {
if period != self.capacity {
let vals = self.to_ordered_by_period(period);
buffers.push(Buffer {
index: 0,
prev_idx: vals.len() - 1,
count: vals.len() - 1,
capacity: vals.len(),
vals,
});
}
}
buffers
}
}
pub type SimdBuffer<const N: usize> = Buffer<Simd<f64, N>>;