1use std::mem::{MaybeUninit, transmute};
2
3use crate::Elem;
4use crate::ops::BitOps;
5
6pub struct SliceWriter<'a, T> {
9 buf: &'a mut [MaybeUninit<T>],
10 n_init: usize,
11}
12
13impl<'a, T: Elem> SliceWriter<'a, T> {
14 pub fn new(buf: &'a mut [MaybeUninit<T>]) -> Self {
16 SliceWriter { buf, n_init: 0 }
17 }
18
19 pub fn write_vec<O: BitOps<T>>(&mut self, ops: O, xs: O::Simd) {
24 let written = ops.store_uninit(xs, &mut self.buf[self.n_init..]);
25 self.n_init += written.len();
26 }
27
28 pub fn write_vecs<O: BitOps<T>, const N: usize>(&mut self, ops: O, xs: [O::Simd; N]) {
37 let written = ops.store_many_uninit(xs, &mut self.buf[self.n_init..]);
38 self.n_init += written.len();
39 }
40
41 pub fn write_scalar(&mut self, x: T) {
45 self.buf[self.n_init].write(x);
46 self.n_init += 1;
47 }
48
49 pub fn into_mut_slice(self) -> &'a mut [T] {
51 let init = &mut self.buf[0..self.n_init];
52
53 unsafe { transmute::<&mut [MaybeUninit<T>], &mut [T]>(init) }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use std::mem::MaybeUninit;
61
62 use crate::ops::BitOps;
63 use crate::{Isa, SimdOp, SliceWriter};
64
65 #[test]
66 fn test_slice_writer() {
67 struct MemCopy<'src, 'dest> {
68 src: &'src [f32],
69 dest: &'dest mut [MaybeUninit<f32>],
70 }
71
72 impl<'src, 'dest> SimdOp for MemCopy<'src, 'dest> {
73 type Output = &'dest mut [f32];
74
75 fn eval<I: Isa>(self, isa: I) -> &'dest mut [f32] {
76 let ops = isa.f32();
77
78 let mut src_chunks = self.src.chunks_exact(ops.len());
79 let mut dest_writer = SliceWriter::new(self.dest);
80
81 for chunk in src_chunks.by_ref() {
82 let xs = ops.load(chunk);
83 dest_writer.write_vec(ops, xs);
84 }
85
86 for x in src_chunks.remainder() {
87 dest_writer.write_scalar(*x);
88 }
89
90 dest_writer.into_mut_slice()
91 }
92 }
93
94 let len = 17;
97 let src: Vec<_> = (0..len).map(|x| x as f32).collect();
98 let mut dest = Vec::with_capacity(src.len());
99
100 let copied = MemCopy {
101 src: &src,
102 dest: dest.spare_capacity_mut(),
103 }
104 .dispatch();
105 assert_eq!(copied, src);
106 }
107}