use std::mem::{MaybeUninit, transmute};
use crate::Elem;
use crate::ops::NumOps;
pub struct SliceWriter<'a, T> {
buf: &'a mut [MaybeUninit<T>],
n_init: usize,
}
impl<'a, T: Elem> SliceWriter<'a, T> {
pub fn new(buf: &'a mut [MaybeUninit<T>]) -> Self {
SliceWriter { buf, n_init: 0 }
}
pub fn write_vec<O: NumOps<T>>(&mut self, ops: O, xs: O::Simd) {
let written = ops.store_uninit(xs, &mut self.buf[self.n_init..]);
self.n_init += written.len();
}
pub fn write_scalar(&mut self, x: T) {
self.buf[self.n_init].write(x);
self.n_init += 1;
}
pub fn into_mut_slice(self) -> &'a mut [T] {
let init = &mut self.buf[0..self.n_init];
unsafe { transmute::<&mut [MaybeUninit<T>], &mut [T]>(init) }
}
}
#[cfg(test)]
mod tests {
use std::mem::MaybeUninit;
use crate::ops::NumOps;
use crate::{Isa, SimdOp, SliceWriter};
#[test]
fn test_slice_writer() {
struct MemCopy<'src, 'dest> {
src: &'src [f32],
dest: &'dest mut [MaybeUninit<f32>],
}
impl<'src, 'dest> SimdOp for MemCopy<'src, 'dest> {
type Output = &'dest mut [f32];
fn eval<I: Isa>(self, isa: I) -> &'dest mut [f32] {
let ops = isa.f32();
let mut src_chunks = self.src.chunks_exact(ops.len());
let mut dest_writer = SliceWriter::new(self.dest);
for chunk in src_chunks.by_ref() {
let xs = ops.load(chunk);
dest_writer.write_vec(ops, xs);
}
for x in src_chunks.remainder() {
dest_writer.write_scalar(*x);
}
dest_writer.into_mut_slice()
}
}
let len = 17;
let src: Vec<_> = (0..len).map(|x| x as f32).collect();
let mut dest = Vec::with_capacity(src.len());
let copied = MemCopy {
src: &src,
dest: dest.spare_capacity_mut(),
}
.dispatch();
assert_eq!(copied, src);
}
}