rustymath_kernels/operation/map/
io.rs1use super::*;
2use crate::{buffer::Cast, parallel::Slots};
3
4#[derive(Clone, Copy)]
5pub(crate) enum Inputs<'a, 'b> { Mapped(&'a [crate::agreement::Read<'b>]), Ready(&'a [View<'b>]) }
6
7impl<'a, 'b> Inputs<'a, 'b> {
8 pub(crate) fn len(self) -> usize { match self { Self::Mapped(x) => x.len(), Self::Ready(x) => x.len() } }
9 pub(crate) fn selected(self, k: usize) -> Self { match self { Self::Mapped(x) => Self::Mapped(&x[k..k + 1]), Self::Ready(x) => Self::Ready(&x[k..k + 1]) } }
10 pub(crate) fn real(self) -> bool {
11 let real = |v: View<'_>| !matches!(v.dtype(), DType::Complex(_));
12 match self { Self::Mapped(x) => x.iter().all(|r| r.sources.iter().all(|s| real(s.view))), Self::Ready(x) => x.iter().all(|&v| real(v)) }
13 }
14 pub(crate) fn in_place<F: Cast>(self, range: &std::ops::Range<usize>) -> bool {
15 match self { Self::Mapped(x) => x.iter().all(|r| r.in_place::<F>(range)), Self::Ready(x) => x.iter().all(|&v| F::of(v).is_some()) }
16 }
17 pub(crate) fn part<'s, F: Cast, const N: usize>(
18 self, range: std::ops::Range<usize>, checked: bool, scratch: &'s mut [Vec<F>; N]) -> Result<[Arg<'s, F>; N], Error> where 'a: 's, 'b: 's {
19 let mut args = [Arg::Many(&[]); N];
20 for (k, (arg, scratch)) in args.iter_mut().zip(scratch).enumerate() {
21 *arg = match self {
22 Self::Mapped(x) => x[k].part(range.clone(), checked, scratch)?,
23 Self::Ready(x) => {
24 let view = if x[k].len() == 1 { x[k] } else { x[k].slice(range.clone()) };
25 match F::of(view) {
26 Some(items) => Arg::of(items),
27 None => {
28 scratch.clear();
29 F::extend_cast(view, view.len(), checked, scratch)?;
30 Arg::of(scratch)
31 }
32 }
33 }
34 };
35 }
36 Ok(args)
37 }
38}
39
40pub enum MapOutput<'a, 'b> {
42 Buffer(&'a mut Buffer), F16(&'a mut Slots<'b, half::f16>), F32(&'a mut Slots<'b, f32>), F64(&'a mut Slots<'b, f64>), Bool(&'a mut Slots<'b, bool>),
43 U8(&'a mut Slots<'b, u8>), I16(&'a mut Slots<'b, i16>), I32(&'a mut Slots<'b, i32>), I64(&'a mut Slots<'b, i64>),
44 C32(&'a mut Slots<'b, num_complex::Complex32>), C64(&'a mut Slots<'b, num_complex::Complex64>), Char(&'a mut Slots<'b, char>)
45}
46
47pub(crate) trait OutputItem: Element { fn slots<'s, 'b>(output: &'s mut MapOutput<'_, 'b>) -> Option<&'s mut Slots<'b, Self>>; }
48
49macro_rules! outputs {
50 ($($v:ident: $t:ty),+ $(,)?) => {
51 impl MapOutput<'_, '_> {
52 fn dtype(&self) -> DType { match self { Self::Buffer(b) => b.dtype(), $(Self::$v(_) => <$t>::DTYPE),+ } }
53 fn copy(&mut self, view: View<'_>) {
54 match self { Self::Buffer(b) => { b.extend_from(view, 0..view.len()); }, $(Self::$v(s) => s.copy(<$t>::of(view).expect("result conversion has the destination's dtype"))),+ }
55 }
56 pub(crate) fn fill(&mut self, n: usize) {
57 match self {
58 Self::Buffer(b) => with_dtype!(b.dtype(), T => { let v = T::vec_mut(b).expect("a buffer has its dtype"); v.resize(v.len() + n, T::FILL); }),
59 $(Self::$v(s) => { s.pairs(Arg::One(<$t>::FILL), Arg::One(()), n, |x, ()| (x, true)); }),+
60 }
61 }
62 }
63 $(impl OutputItem for $t {
64 fn slots<'s, 'b>(output: &'s mut MapOutput<'_, 'b>) -> Option<&'s mut Slots<'b, Self>> {
65 match output { MapOutput::$v(s) => Some(s), _ => None }
66 }
67 }
68 impl<'a, 'b> From<&'a mut Slots<'b, $t>> for MapOutput<'a, 'b> {
69 fn from(slots: &'a mut Slots<'b, $t>) -> Self { MapOutput::$v(slots) }
70 })+
71 };
72}
73outputs!(F16: half::f16, F32: f32, F64: f64, Bool: bool, U8: u8, I16: i16, I32: i32, I64: i64,
74 C32: num_complex::Complex32, C64: num_complex::Complex64, Char: char);
75
76pub(crate) struct Output<'a, 'b> { pub target: MapOutput<'a, 'b>, pub dtype: DType, pub checked: bool }
77
78impl Output<'_, '_> {
79 pub(crate) fn write<O: OutputItem>(&mut self, n: usize, apply: &(dyn Fn(std::ops::Range<usize>, &mut Slots<'_, O>) -> bool + Sync)) -> Result<(), Error> {
81 let checked = self.checked;
82 if let MapOutput::Buffer(buffer) = &mut self.target {
83 if let Some(values) = O::vec_mut(buffer) { crate::parallel::extended(values, n, crate::CHUNK, apply); } else {
84 with_dtype!(buffer.dtype(), T => {
85 let values = T::vec_mut(buffer).expect("a buffer has its dtype");
86 crate::parallel::extended(values, n, crate::CHUNK, &|part, slots| {
87 converted::<O>(&mut slots.into(), part, checked, apply).map_err(crate::error::record).is_ok()
88 });
89 });
90 }
91 return Ok(());
92 }
93 if let Some(slots) = O::slots(&mut self.target) { apply(0..n, slots); return Ok(()); }
94 converted(&mut self.target, 0..n, checked, apply)
95 }
96}
97
98fn converted<O: OutputItem>(
99 target: &mut MapOutput<'_, '_>, range: std::ops::Range<usize>, checked: bool, apply: &(dyn Fn(std::ops::Range<usize>, &mut Slots<'_, O>) -> bool + Sync)
100) -> Result<(), Error> {
101 let mut scratch = Vec::<O>::new();
102 for at in (range.start..range.end).step_by(crate::CHUNK) {
103 let n = crate::CHUNK.min(range.end - at);
104 scratch.clear();
105 Slots::append(&mut scratch, n, |slots| apply(at..at + n, slots));
106 match Buffer::cast_results(O::view(&scratch), target.dtype(), checked) {
107 Ok(buffer) => target.copy(buffer.view()), Err(error) => { target.fill(range.end - at); return Err(error); }
108 }
109 }
110 Ok(())
111}