1use super::*;
2
3pub fn scan_along<T: Copy, R: Reduction<T>>(data: &[T], dims: [usize; 3], seed: Option<&[R::Total]>, out: &mut Vec<R::Total>) -> bool {
5 let start = |i| seed.map(|s| s[if s.len() == 1 { 0 } else { i }]);
6 if let [_, len, 1] = dims && let Some(fits) = R::short_lanes(data, len, start(0), out) { return fits; }
7 rows_scan(data, dims, out, |lane, o| R::scan(lane, start(0), o), |i, x| start(i).map_or_else(|| R::one(x), |s| R::checked(s, x)), R::checked)
8}
9
10pub unsafe fn ordered_scan<T: Copy>(
15 data: &[T], [_, len, inner]: [usize; 3], seed: Option<&[T]>, out: &mut Vec<T>, lane: &dyn Fn(Option<T>, &[T], usize, &mut Vec<T>) -> Option<Kind>,
16 block: &dyn Fn(&[T], &[T], &mut [std::mem::MaybeUninit<T>]) -> Result<(), Kind>) -> Option<Kind> {
17 if inner == 1 { return lane(seed.map(|s| s[0]), data, len, out); }
18 unsafe {
19 appended(out, data.len(), |slots| {
20 let mut failure = None;
21 for (items, outs) in data.chunks(len * inner).zip(slots.chunks_mut(len * inner)) {
22 match seed {
23 Some(s) => failure = failure.or(block(s, &items[..inner], &mut outs[..inner]).err()),
24 None => { for (slot, &x) in outs.iter_mut().zip(&items[..inner]) { slot.write(x); } }
25 }
26 for r in 1..len {
27 let (done, next) = outs.split_at_mut(r * inner);
28 failure = failure.or(block(written(&mut done[(r - 1) * inner..]), &items[r * inner..(r + 1) * inner], &mut next[..inner]).err());
29 }
30 }
31 failure
32 })
33 }
34}
35
36pub fn lanes_scan<T: Copy>(data: &[T], len: usize, out: &mut Vec<T>, first: impl Fn(T) -> (T, bool) + Copy, step: impl Fn(T, T) -> (T, bool) + Copy) -> bool {
38 rows_scan(data, [0, len, 1], out, |lane, out| {
39 let (total, ok) = first(lane[0]);
40 out.push(total);
41 checked_scan(&lane[1..], total, out, step) & ok
42 }, move |_, x| first(x), step)
43}
44
45#[inline(always)]
47fn rows_scan<T: Copy, S: Copy>(
48 data: &[T], [_, len, inner]: [usize; 3], out: &mut Vec<S>, lane: impl Fn(&[T], &mut Vec<S>) -> bool, first: impl Fn(usize, T) -> (S, bool) + Copy,
49 step: impl Fn(S, T) -> (S, bool) + Copy) -> bool {
50 if data.is_empty() { return true; }
51 if inner == 1 && len >= SHORT_LANE { return data.chunks(len).fold(true, |fits, l| lane(l, out) & fits); }
52 if inner == 1 {
53 return unsafe {
54 appended(out, data.len(), |slots| {
55 let whole = data.len() / (LANES * len) * (LANES * len);
56 let (groups, rest) = slots.split_at_mut(whole);
57 side_by_side::<LANES, _, _>(&data[..whole], len, |x| first(0, x), step, |at, s| {
59 groups.get_unchecked_mut(at).write(s);
60 }, |_, _| {}) & side_by_side::<1, _, _>(&data[whole..], len, |x| first(0, x), step, |at, s| {
61 rest.get_unchecked_mut(at).write(s);
62 }, |_, _| {})
63 })
64 };
65 }
66 unsafe {
68 appended(out, data.len(), |slots| {
69 let mut fits = true;
70 let mut at = 0;
71 while at < data.len() {
72 let (row, outs) = (&data[at..at + inner], &mut slots[at..at + inner]);
73 for k in 0..inner {
74 let (t, f) = first(k, row[k]);
75 outs[k].write(t);
76 fits &= f;
77 }
78 let mut r = at + inner;
79 while r < at + len * inner {
80 let (done, rest) = slots.split_at_mut(r);
81 let (before, row, outs) = (written(&mut done[r - inner..]), &data[r..r + inner], &mut rest[..inner]);
82 for k in 0..inner {
83 let (t, f) = step(before[k], row[k]);
84 outs[k].write(t);
85 fits &= f;
86 }
87 r += inner;
88 }
89 at += len * inner;
90 }
91 fits
92 })
93 }
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Eq)]
98pub struct Logical(pub [[bool; 2]; 2]);
99
100impl Logical {
101 #[inline(always)]
103 fn apply(self, r: bool, x: bool) -> bool { let [[f00, f01], [f10, f11]] = self.0; (r & ((x & f11) | (!x & f10))) | (!r & ((x & f01) | (!x & f00))) }
104
105 pub fn scan(self, x: &[bool], start: Option<bool>, out: &mut Vec<bool>) {
109 let Some((&head, rest)) = x.split_first() else { return };
110 let first = self.first(start, head);
111 out.push(first);
112 let [[f00, f01], [f10, f11]] = self.0;
114 let maps = [[f00, f10], [f01, f11]];
115 for v in [false, true] {
116 let [lo, hi] = maps[usize::from(!v)];
117 if maps[usize::from(v)] == [false, true] && lo == hi {
118 let at = first_where(rest, |x| x != v);
119 out.extend(std::iter::repeat_n(first, at));
120 out.extend(std::iter::repeat_n(lo, rest.len() - at));
121 return;
122 }
123 }
124 let bit_maps = self.bit_maps();
125 mapped(rest.len(), first, |start| bit_maps(packed(rest, start)), out);
126 }
127
128 #[inline(always)]
130 fn first(self, start: Option<bool>, x: bool) -> bool { start.map_or(x, |s| self.apply(s, x)) }
131
132 #[inline(always)]
134 fn bit_maps(self) -> impl Fn(u64) -> (u64, u64) + Copy {
135 let [[f00, f01], [f10, f11]] = self.0;
136 let word = |b: bool| if b { u64::MAX } else { 0 };
137 let (s0, t0, s1, t1) = (word(f00 != f10), word(f00), word(f01 != f11), word(f01));
139 move |bits| ((bits & s1) | (!bits & s0), (bits & t1) | (!bits & t0))
140 }
141
142 pub(super) fn short_lanes(self, data: &[bool], len: usize, start: Option<bool>, out: &mut Vec<bool>) {
144 let (bit_maps, word) = (self.bit_maps(), |b: bool| if b { u64::MAX } else { 0 });
145 let (yes, no) = (word(self.first(start, true)), word(self.first(start, false)));
146 let starts = (0..64).step_by(len).fold(0u64, |p, k| p | 1 << k);
147 let (shift, at) = (64 % len, std::cell::Cell::new(0));
148 mapped(data.len(), false, |from| {
149 let (bits, k) = (packed(data, from), at.get());
150 at.set(if k >= shift { k - shift } else { k + len - shift });
151 let (places, (s, t)) = (starts << k, bit_maps(bits));
152 (s & !places, (t & !places) | ((bits & yes) | (!bits & no)) & places)
153 }, out);
154 }
155}
156
157#[inline(always)]
159fn pack(block: &[bool; 64]) -> u64 {
160 let mut bits = 0;
161 for (k, b) in block.as_chunks::<8>().0.iter().enumerate() {
162 let bytes = (0..8).fold(0u64, |w, i| w | u64::from(b[i]) << (8 * i));
163 bits |= (bytes.wrapping_mul(0x0102_0408_1020_4080) >> 56) << (8 * k);
164 }
165 bits
166}
167
168#[inline(always)]
170fn unpack<S>(r: u64, out: &mut [std::mem::MaybeUninit<S>; 64]) where bool: Source<S> {
171 let mut block = [false; 64];
172 for (k, lanes) in block.as_chunks_mut::<8>().0.iter_mut().enumerate() {
173 let bits = (r >> (8 * k) & 0xff).wrapping_mul(0x0101_0101_0101_0101) & 0x8040_2010_0804_0201;
174 let bytes = ((bits + 0x7f7f_7f7f_7f7f_7f7f) >> 7 & 0x0101_0101_0101_0101).to_le_bytes();
175 *lanes = std::array::from_fn(|j| bytes[j] != 0);
176 }
177 crate::slice::pairs_into(Arg::Many(&block), Arg::One(()), 64, out, |b, ()| (b.read(), true));
178}
179
180#[inline(always)]
182fn composed(mut s: u64, mut t: u64, carry: bool) -> u64 {
183 for k in [1, 2, 4, 8, 16, 32] {
184 t ^= s & (t << k);
185 s &= (s << k) | ((1u64 << k) - 1);
186 }
187 (s & if carry { u64::MAX } else { 0 }) ^ t
188}
189
190#[inline(always)]
192fn packed(x: &[bool], start: usize) -> u64 {
193 match x[start..].first_chunk::<64>() {
194 Some(block) => pack(block),
195 None => {
196 let mut block = [false; 64];
197 block[..x.len() - start].copy_from_slice(&x[start..]);
198 pack(&block)
199 }
200 }
201}
202
203#[inline(always)]
205fn mapped<S: Copy>(n: usize, mut carry: bool, maps: impl Fn(usize) -> (u64, u64), out: &mut Vec<S>) where bool: Source<S> {
206 unsafe {
207 appended(out, n, |slots| {
208 let (outs, last) = slots.as_chunks_mut::<64>();
209 for (i, o) in outs.iter_mut().enumerate() {
210 let (s, t) = maps(64 * i);
211 let r = composed(s, t, carry);
212 unpack(r, o);
213 carry = r >> 63 != 0;
214 }
215 if !last.is_empty() {
216 let (s, t) = maps(n - last.len());
217 let r = composed(s, t, carry);
218 for (k, slot) in last.iter_mut().enumerate() { slot.write(Source::<S>::read(r >> k & 1 != 0)); }
219 }
220 })
221 };
222}
223
224pub fn comparison_scan<T: Element + PartialEq, S: Element>(
226 data: &[T], len: usize, start: Option<T>, step: impl Fn(T, T) -> (T, Option<Kind>) + Copy, read: impl Fn(T) -> S + Copy,
227 bulk: impl Fn(T, &[T], &mut Vec<bool>) -> Option<bool> + Copy, out: &mut Vec<S>) -> bool where bool: Source<T> + Source<S> {
228 if len < SHORT_LANE { return false; }
229 let (zero, one, before) = (false.read(), true.read(), out.len());
230 let (mut low, mut high) = (Vec::new(), Vec::new());
231 for lane in data.chunks(len) {
232 let (first, used) = match start { Some(seed) => (step(seed, lane[0]), 1), None => { out.push(read(lane[0])); (step(lane[0], lane[1]), 2) } };
233 let (first, failed) = first;
234 if failed.is_some() { out.truncate(before); return false; }
235 out.push(read(first));
236 let rest = &lane[used..];
237 low.clear();
238 high.clear();
239 let transitions = |carry, dest: &mut Vec<bool>| {
240 if let Some(valid) = bulk(carry, rest, dest) { return valid; }
241 unsafe {
242 appended(dest, rest.len(), |slots| {
243 let mut valid = true;
244 for (&x, slot) in rest.iter().zip(slots) {
245 let (value, failed) = step(carry, x);
246 slot.write(value != zero);
247 valid &= failed.is_none();
248 }
249 valid
250 })
251 }
252 };
253 if !(transitions(zero, &mut low) & transitions(one, &mut high)) { out.truncate(before); return false; }
254 mapped(rest.len(), first != zero, |at| { let (l, h) = (packed(&low, at), packed(&high, at)); (l ^ h, l) }, out);
255 }
256 true
257}
258
259pub(super) fn negated_cells<T: Element, R: Reduction<T, Total = T>>(
261 items: &[T], dims: [usize; 3], seed: Option<&[T]>, out: &mut Vec<T>, neg: impl Fn(T) -> T + Copy) {
262 let start = |i| seed.map(|s| s[if s.len() == 1 { 0 } else { i }]);
263 let lane = |lane: &[T], out: &mut Vec<T>| {
264 let (total, rest) = match start(0) { Some(s) => (s, lane), None => { out.push(lane[0]); (lane[0], &lane[1..]) } };
265 grouped(rest, Some(total), out, neg, R::step, |x| x, T::DTYPE.is_integral());
266 true
267 };
268 rows_scan(items, dims, out, lane, |i, x| (start(i).map_or(x, |s| R::step(s, neg(x))), true), |t, x| (R::step(t, neg(x)), true));
269}