1use super::*;
2
3pub const DIRECT: usize = 8;
5const SLIDE_BLOCK: usize = 1024;
7
8#[inline(always)]
10fn hgw<T: Copy, R: Reduction<T>, const ONE: bool>(
11 lane: &[T], folds: &mut [R::Total], suffix: &mut [R::Total], row: &mut [R::Total], width: usize, inner: usize, ok: &mut bool) {
12 let inner = if ONE { 1 } else { inner };
13 let mut one = [R::unit()];
15 let row = if ONE { &mut one[..] } else { &mut row[..inner] };
16 for (b, block) in lane.chunks(width * inner).enumerate() {
17 let (start, last) = (b * width * inner, block.len() - inner);
18 let s = &mut suffix[start..start + block.len()];
20 for j in 0..inner {
21 row[j] = one_of::<T, R>(block[last + j], ok);
22 s[last + j] = row[j];
23 }
24 for k in (0..last).step_by(inner).rev() {
25 for j in 0..inner {
26 row[j] = chain_of::<T, R>(one_of::<T, R>(block[k + j], ok), row[j], ok);
27 s[k + j] = row[j];
28 }
29 }
30 for j in 0..inner { row[j] = one_of::<T, R>(block[j], ok); }
32 if b == 0 {
33 for k in (inner..block.len()).step_by(inner) { for j in 0..inner { row[j] = chain_of::<T, R>(row[j], one_of::<T, R>(block[k + j], ok), ok); } }
34 folds[..inner].copy_from_slice(row);
35 continue;
36 }
37 let from = start + inner - width * inner;
39 let (windows, earlier) = (&mut folds[from..from + block.len()], &suffix[from..from + block.len()]);
40 for j in 0..inner { windows[j] = merge_of::<T, R>(earlier[j], row[j], ok); }
41 for k in (inner..block.len()).step_by(inner) {
42 for j in 0..inner {
43 row[j] = chain_of::<T, R>(row[j], one_of::<T, R>(block[k + j], ok), ok);
44 windows[k + j] = merge_of::<T, R>(earlier[k + j], row[j], ok);
45 }
46 }
47 if block.len() == width * inner { folds[start..start + inner].copy_from_slice(row); }
49 }
50}
51
52pub fn sliding<T: Copy + Sync, R: Reduction<T>>(data: &[T], [outer, len, inner]: [usize; 3], width: usize) -> (Vec<R::Total>, bool) {
54 assert_eq!(data.len(), outer * len * inner, "the data must fill its dimensions");
55 assert!((1..=len.max(1)).contains(&width), "a window lies within its lane");
56 let finished = |(totals, fits)| {
57 if fits { crate::events::taken(crate::events::Route::SlidingFold, data.len()); }
58 (totals, fits)
59 };
60 let count = (len + 1).saturating_sub(width);
61 if outer * count * inner == 0 { return finished((Vec::new(), true)); }
62 if width == len && inner == 1 { return finished(along::<T, R>(data, [outer, len, inner])); }
64 let mut ok = true;
65 if width <= DIRECT {
66 let block = (SLIDE_BLOCK / inner).max(1);
68 let mut out = Vec::with_capacity(outer * count * inner);
69 for lane in data.chunks_exact(len * inner) {
70 for r in (0..count).step_by(block) {
71 let rows = block.min(count - r);
72 ok &= rows_folded::<T, R>(&mut out, width, |i| &lane[(r + i) * inner..(r + i + rows) * inner]);
73 }
74 }
75 return finished((out, ok));
76 }
77 let mut out = vec![R::unit(); outer * count * inner];
78 let lanes = data.chunks_exact(len * inner).zip(out.chunks_exact_mut(count * inner));
79 let (mut suffix, mut row) = (vec![R::unit(); len * inner], vec![R::unit(); inner]);
80 for (lane, folds) in lanes {
81 if inner == 1 { hgw::<T, R, true>(lane, folds, &mut suffix, &mut row, width, inner, &mut ok) }
82 else { hgw::<T, R, false>(lane, folds, &mut suffix, &mut row, width, inner, &mut ok) }
83 }
84 finished((out, ok))
85}
86
87pub fn sliding_2d<T: Copy + Sync, R: Reduction<T>>(
89 data: &[T], [outer, len1, mid, len2, inner]: [usize; 5], [w1, w2]: [usize; 2], [e1, e2]: [usize; 2]) -> Option<(Vec<R::Total>, bool)> {
90 assert_eq!(data.len(), outer * len1 * mid * len2 * inner, "the data must fill its dimensions");
91 assert!(w1 > 0 && w2 > 0 && e1 > 0 && e2 > 0, "windows hold items and start in order");
92 if w1 > DIRECT || w2 > DIRECT { return None; }
93 let (c1, c2) = ((len1 + e1).saturating_sub(w1) / e1, (len2 + e2).saturating_sub(w2) / e2);
94 if outer * c1 * mid * c2 * inner == 0 { return Some((Vec::new(), true)); }
95 let (row, plane) = (len2 * inner, mid * len2 * inner);
96 let mut out = Vec::with_capacity(outer * c1 * mid * c2 * inner);
97 let (mut band, mut ok) = (Vec::with_capacity(plane), true);
98 for lane in data.chunks_exact(len1 * plane) {
99 for i in 0..c1 {
100 band.clear();
101 ok &= rows_folded::<T, R>(&mut band, w1, |a| &lane[(e1 * i + a) * plane..(e1 * i + a + 1) * plane]);
102 for m in band.chunks_exact(row) {
103 let at = out.len();
104 if e2 == 1 {
106 out.extend_from_slice(&m[..c2 * inner]);
107 for b in 1..w2 { ok &= merges_of::<T, R>(&mut out[at..], &m[b * inner..]); }
108 } else {
109 for j in 0..c2 { out.extend_from_slice(&m[e2 * j * inner..(e2 * j + 1) * inner]); }
110 for b in 1..w2 {
111 for j in 0..c2 { ok &= merges_of::<T, R>(&mut out[at + j * inner..at + (j + 1) * inner], &m[(e2 * j + b) * inner..]); }
112 }
113 }
114 }
115 }
116 }
117 if ok { crate::events::taken(crate::events::Route::SlidingFold, data.len()); }
118 Some((out, ok))
119}
120
121struct Pick<R>(std::marker::PhantomData<R>);
123
124impl<T: Copy + PartialEq + Send + Sync, R: Reduction<T, Total = T>> Reduction<(T, usize)> for Pick<R> {
125 type Total = (T, usize);
126 #[inline(always)]
127 fn unit() -> (T, usize) { (R::unit(), 0) }
128 #[inline(always)]
129 fn one((x, row): (T, usize)) -> ((T, usize), bool) { ((R::one(x).0, row), true) }
130 #[inline(always)]
131 fn step(acc: (T, usize), x: (T, usize)) -> (T, usize) { Self::merge(acc, Self::one(x).0).0 }
132 #[inline(always)]
134 fn merge(a: (T, usize), b: (T, usize)) -> ((T, usize), bool) { (if R::merge(a.0, b.0).0 == a.0 { a } else { b }, true) }
135 fn slice(x: &[(T, usize)]) -> ((T, usize), bool) { (x.iter().fold(Self::unit(), |t, &v| Self::step(t, v)), true) }
136 fn scan(x: &[(T, usize)], start: Option<(T, usize)>, out: &mut Vec<(T, usize)>) -> bool {
137 let mut total = start;
138 for &v in x {
139 let t = total.map_or_else(|| Self::one(v).0, |t| Self::step(t, v));
140 out.push(t);
141 total = Some(t);
142 }
143 true
144 }
145}
146
147#[derive(Clone, Copy, Debug)]
149pub enum Picks { Windows(usize), Lanes, Running }
150
151pub fn picks<T: Copy + PartialEq + Send + Sync, R: Reduction<T, Total = T>>(data: &[T], shape: [usize; 3], of: Picks) -> Vec<usize> {
153 let [outer, len, inner] = shape;
154 match of {
155 Picks::Windows(width) => {
156 let pairs: Vec<(T, usize)> = data.iter().enumerate().map(|(k, &x)| (x, k / inner.max(1) % len.max(1))).collect();
157 sliding::<(T, usize), Pick<R>>(&pairs, shape, width).0.into_iter().map(|(_, row)| row).collect()
158 }
159 Picks::Lanes if inner == 1 => along::<T, R>(data, shape).0.into_iter().enumerate().map(|(o, total)| {
161 let row = first_where(&data[o * len..][..len], |x| R::one(x).0 == total);
162 if row == len { 0 } else { row }
163 }).collect(),
164 Picks::Lanes => {
166 let mut rows = vec![0; outer * inner];
167 if len > 0 && inner > 0 {
168 for (block, lanes) in data.chunks_exact(len * inner).zip(rows.chunks_exact_mut(inner)) {
169 let mut totals: Vec<T> = block[..inner].iter().map(|&x| R::one(x).0).collect();
170 for (k, items) in block.chunks_exact(inner).enumerate().skip(1) {
171 for ((row, total), &x) in lanes.iter_mut().zip(&mut totals).zip(items) {
172 let next = R::merge(*total, R::one(x).0).0;
173 *row = moved(*row, *total, next, k);
174 *total = next;
175 }
176 }
177 }
178 }
179 rows
180 }
181 Picks::Running => {
183 let mut totals = Vec::with_capacity(data.len());
184 scan_along::<T, R>(data, shape, None, &mut totals);
185 let mut rows = vec![0; data.len()];
186 for at in 0..data.len() { let k = at / inner % len; if k > 0 { rows[at] = moved(rows[at - inner], totals[at - inner], totals[at], k) } }
187 rows
188 }
189 }
190}
191
192pub fn view_picks(x: View<'_>, dims: [usize; 3], of: Picks, max: bool) -> Option<Vec<usize>> {
194 fn picked<T: Copy + PartialEq + Send + Sync>(x: &[T], dims: [usize; 3], of: Picks, max: bool) -> Vec<usize> where Max: Reduction<T, Total = T>,
195 Min: Reduction<T, Total = T> { if max { picks::<T, Max>(x, dims, of) } else { picks::<T, Min>(x, dims, of) } }
196 Some(match x {
197 View::Booleans(x) => picked(x, dims, of, max), View::Integers(x) => with_ints!(x, |x| picked(x, dims, of, max)),
198 View::Floats(x) => with_floats!(x, |x| picked(x, dims, of, max)), _ => return None
199 })
200}