1use crate::buffer::View;
3use crate::search::Key;
4use crate::slice::Arg;
5use crate::structure::{Edge, Walk};
6use std::borrow::Cow;
7use std::mem::MaybeUninit;
8use std::sync::Arc;
9
10pub(crate) fn cycled<T: Copy>(d: &mut Vec<T>, s: &[T], from: usize, n: usize) {
12 if let [x] = *s { return d.resize(d.len() + n, x); }
13 let (start, from) = (d.len(), from % s.len());
14 let first = (s.len() - from).min(n);
15 d.extend_from_slice(&s[from..from + first]);
16 d.extend_from_slice(&s[..(n - first).min(from)]);
17 let mut block = d.len() - start;
18 while d.len() - start < n {
19 let done = d.len() - start;
20 d.extend_from_within(start..start + block.min(n - done));
21 if block * size_of::<T>() < CYCLE_BLOCK { block = d.len() - start; }
22 }
23}
24
25const CYCLE_BLOCK: usize = 32 << 10;
27
28#[inline]
30pub fn repeat<D: Copy, C: Key>(out: &mut Vec<D>, len: usize, counts: &[C], total: usize, item: impl Fn(usize) -> D) {
31 unsafe {
32 crate::slice::appended(out, total, |d| {
33 let mut k = 0;
34 let each = |d: &mut [MaybeUninit<D>], k: &mut usize, x: D, n: usize| {
35 let x = MaybeUninit::new(x);
36 match d[*k..].first_chunk_mut::<4>() { Some(w) if n <= 4 => *w = [x; 4], _ => d[*k..*k + n].fill(x) }
37 *k += n;
38 };
39 if let [n] = *counts { for j in 0..len { each(d, &mut k, item(j), n.key() as usize) } } else {
40 let count_groups = counts.as_chunks::<4>().0;
41 for (g, &c) in count_groups.iter().enumerate().take(len / 4) {
42 let j = 4 * g;
43 if k + 16 > total || c[0].key().max(c[1].key()).max(c[2].key()).max(c[3].key()) as u64 > 4 {
44 for i in 0..4 { each(d, &mut k, item(j + i), c[i].key() as usize) }
45 continue;
46 }
47 let w = &mut d[k..k + 16];
48 let mut o = 0;
49 for i in 0..4 {
50 *w[o..].first_chunk_mut::<4>().expect("each count in the group is at most 4") = [MaybeUninit::new(item(j + i)); 4];
51 o += c[i].key() as usize;
52 }
53 k += o;
54 }
55 for j in len / 4 * 4..len { each(d, &mut k, item(j), counts[j].key() as usize) }
56 }
57 assert_eq!(k, total, "the counts must sum to `total`");
58 })
59 }
60}
61
62#[inline]
64pub fn positions<M: Key, D: Copy>(out: &mut Vec<D>, mask: &[M], total: usize, position: impl Fn(usize) -> D) {
65 unsafe {
66 crate::slice::appended(out, total, |d| {
67 let mut k = 0;
69 for (start, m) in (0..).step_by(64).zip(mask.chunks(64)) {
70 let mut n = 0u8;
72 for x in m { n += x.key() as u8 & 1 }
73 let n = usize::from(n);
74 if n == m.len() { let run = &mut d[k..k + n]; for j in 0..n { run[j].write(position(start + j)); } }
75 else if n > 0 {
76 let (blocks, rest) = m.as_chunks::<8>();
77 let mut at = k;
78 for (b, block) in blocks.iter().enumerate() {
79 let start = start + 8 * b;
80 at = selected(d, at, mask_bits(block), |i| position(start + usize::from(i)));
81 }
82 let (start, last) = (start + 8 * blocks.len(), mask_bits(rest));
83 selected(d, at, last, |i| position(start + usize::from(i)));
84 }
85 k += n;
86 }
87 assert_eq!(k, total, "`total` counts must be 1");
88 })
89 }
90}
91
92const SET: [[u8; 8]; 256] = {
94 let mut set = [[0; 8]; 256];
95 let mut mask = 0;
96 while mask < 256 {
97 let (mut bit, mut k) = (0, 0);
98 while bit < 8 {
99 if mask >> bit & 1 == 1 {
100 set[mask][k] = bit as u8;
101 k += 1;
102 }
103 bit += 1;
104 }
105 mask += 1;
106 }
107 set
108};
109
110#[inline(always)]
112pub(crate) fn mask_bits<M: Key>(m: &[M]) -> u8 {
113 let mut bytes = 0u64;
115 for i in 0..m.len() { bytes |= u64::from(m[i].key() as u8) << (8 * i) }
116 ((bytes & 0x0101_0101_0101_0101).wrapping_mul(0x0102_0408_1020_4080) >> 56) as u8
117}
118
119#[inline(always)]
121pub(crate) fn selected<D: Copy>(d: &mut [MaybeUninit<D>], k: usize, mask: u8, item: impl Fn(u8) -> D) -> usize {
122 let set = &SET[usize::from(mask)];
123 let found = mask.count_ones() as usize;
124 if let Some(w) = d[k..].first_chunk_mut::<8>() { for i in 0..8 { w[i].write(item(set[i])); } }
125 else { for i in 0..found { d[k + i].write(item(set[i])); } }
126 k + found
127}
128
129#[inline]
131pub fn take<S: Copy, D, I: IndexValue>(out: &mut Vec<D>, items: &[S], indices: &[I], f: impl Fn(S) -> D) {
132 out.extend(indices.iter().map(move |&i| f(items[crate::structure::counted_back(i.position(), items.len())])));
133}
134
135#[inline]
137fn put<T: Copy, I: IndexValue>(out: &mut [T], items: &[T], indices: &[I]) {
138 let n = out.len();
139 match items {
140 [x] => { for &i in indices { out[crate::structure::counted_back(i.position(), n)] = *x } }
141 _ => { for (&i, &x) in indices.iter().zip(items) { out[crate::structure::counted_back(i.position(), n)] = x } }
142 }
143}
144
145struct Cell { starts: [usize; CELL], runs: usize, len: usize, rev: bool, fills: u64 }
147impl Cell {
148 #[inline]
149 fn starts(&self) -> &[usize] { &self.starts[..self.runs] }
150 #[inline]
151 fn width(&self) -> usize { self.runs * self.len }
152 fn offsets(&self) -> impl Iterator<Item = usize> + '_ {
154 self.starts().iter().flat_map(move |&s| (0..self.len).map(move |i| s + if self.rev { self.len - 1 - i } else { i }))
155 }
156 #[inline]
158 fn reach(&self) -> usize { self.starts().iter().max().expect("a short cell holds a run") + self.len }
159 fn filled<T: Copy>(&self, out: &mut [T], fill: T) {
161 if self.fills == 0 { return; }
162 for cell in out.chunks_exact_mut(self.width()) {
163 let mut runs = self.fills;
164 while runs != 0 {
165 let j = runs.trailing_zeros() as usize;
166 cell[j * self.len..][..self.len].fill(fill);
167 runs &= runs - 1;
168 }
169 }
170 }
171 #[inline]
173 fn check(&self, at: usize, step: isize, m: usize, n: usize) {
174 let reach = self.reach();
175 if m > 0 { checked_run(at, m, step, n.checked_sub(reach - 1).expect("cell stays in range")); }
176 }
177 #[inline(always)]
179 fn each_run(&self, o: usize, step: isize, m: usize, mut each: impl FnMut(usize, usize)) {
180 let (mut item, mut at) = (0, o);
181 if let [start] = *self.starts() {
182 for _ in 0..m {
183 each(item, at + start);
184 item += self.len;
185 at = at.wrapping_add_signed(step);
186 }
187 return;
188 }
189 for _ in 0..m {
190 for &start in self.starts() {
191 each(item, at + start);
192 item += self.len;
193 }
194 at = at.wrapping_add_signed(step);
195 }
196 }
197 #[inline(always)]
199 fn each_way<const L: usize>(&self, o: usize, step: isize, m: usize, mut each: impl FnMut(usize, usize, bool)) {
200 debug_assert!(L <= self.len, "`runs!` gives an L no longer than the run");
201 let last = self.len - L;
202 let mut blocks = std::convert::identity(#[inline(always)] |item: usize, at: usize, rev: bool| {
204 if L < RUN || last == 0 { return each(item, at, rev); }
205 let mut d = 0;
206 loop {
207 let b = d.min(last);
208 each(item + b, at + if rev { last - b } else { b }, rev);
209 if b == last { break; }
210 d += L;
211 }
212 });
213 if self.rev { self.each_run(o, step, m, |item, at| blocks(item, at, true)) } else { self.each_run(o, step, m, |item, at| blocks(item, at, false)) }
214 }
215 #[inline(always)]
220 unsafe fn each_move<const L: usize, U: Unit>(&self, o: usize, step: isize, m: usize, places: impl Fn(usize, usize) -> (*const U, *mut U)) {
221 self.each_way::<L>(o, step, m, |item, at, rev| {
222 let (from, to) = places(item, at);
223 let mut units = unsafe { from.cast::<[U; L]>().read() };
225 if rev { units.reverse() }
226 unsafe { to.cast::<[U; L]>().write(units) }
227 })
228 }
229}
230
231macro_rules! runs {
233 ($len:expr, $L:ident => $body:expr) => {
234 match $len {
235 1 => { const $L: usize = 1; $body }
236 2 => { const $L: usize = 2; $body }
237 3 => { const $L: usize = 3; $body }
238 4 => { const $L: usize = 4; $body }
239 5 => { const $L: usize = 5; $body }
240 6 => { const $L: usize = 6; $body }
241 7 => { const $L: usize = 7; $body }
242 _ => { const $L: usize = RUN; $body }
243 }
244 };
245}
246
247#[inline]
249fn windows<const L: usize, U: Unit>(slots: &mut [MaybeUninit<U>], s: &[U], o: usize, step: isize, cell: &Cell) {
250 let width = cell.width();
251 let m = slots.len() / width;
252 cell.check(o, step, m, s.len());
253 let (from, to) = (s.as_ptr(), slots.as_mut_ptr().cast::<U>());
254 unsafe { cell.each_move::<L, U>(o, step, m, |item, at| (from.add(at), to.add(item))) }
256}
257
258#[inline]
260fn cells_at<const L: usize, U: Unit>(slots: &mut [MaybeUninit<U>], s: &[U], base: usize, axis: &Steps, cell: &Cell) {
261 let width = cell.width();
262 assert_eq!(slots.len(), axis.len() * width, "a slot for each unit of each cell");
263 let (from, to, reach) = (s.as_ptr(), slots.as_mut_ptr().cast::<U>(), cell.reach());
264 axis.for_each(|r, o| {
265 if let Some(o) = o {
266 assert!(base + o + reach <= s.len(), "cell stays in range");
267 unsafe { cell.each_move::<L, U>(base + o, 0, 1, |item, at| (from.add(at), to.add(r * width + item))) }
269 }
270 });
271}
272
273#[inline]
275fn windows_into<const L: usize, U: Unit>(out: &mut [U], items: &[U], o: usize, step: isize, m: usize, cell: &Cell, k: usize) {
276 let width = cell.width();
277 cell.check(o, step, m, out.len());
278 let to = out.as_mut_ptr();
279 match items {
281 [x] => cell.each_way::<L>(o, step, m, |_, at, _| unsafe { to.add(at).cast::<[U; L]>().write([*x; L]) }),
282 _ => {
283 let from = items[k..][..m * width].as_ptr();
284 unsafe { cell.each_move::<L, U>(o, step, m, |item, at| (from.add(item), to.add(at))) }
286 }
287 }
288}
289
290#[inline]
292pub fn scatter<S: Copy, D>(out: &mut [D], offsets: &[usize], items: &[S], conv: impl Convert<S, D>) {
293 let items = Arg::of(items);
294 for (k, &o) in offsets.iter().enumerate() { if let Some(slot) = out.get_mut(o) { *slot = conv.one(items.nth(k)) } }
295}
296pub fn scatter_walk<S: Item, D: Item>(out: &mut [D], items: &[S], base: usize, steps: &[Steps], conv: impl Convert<S, D>) {
298 let (base, steps) = Steps::simplify(base, steps);
299 if let Some(items) = conv.borrowed(items) { return scatter_into(out, items, base, &steps, &mut 0); }
300 if let [x] = *items { return scatter_into(out, &[conv.one(x)], base, &steps, &mut 0); }
301 let Some((axis, rest)) = steps.split_first() else { return scatter_into(out, &conv.all(items), base, &steps, &mut 0) };
302 if let (&Steps::Stride { start, step, .. }, Some(_)) = (&**axis, short_cells(rest, false)) {
304 if D::cells_from(out, items, &conv, base + start, step, rest) { return; }
305 }
306 let width = Steps::count(rest);
307 let rows = (crate::slice::CHUNK / width.max(1)).max(1);
308 let mut block = Vec::with_capacity(rows * width);
309 for j in (0..axis.len()).step_by(rows) {
310 let count = rows.min(axis.len() - j);
311 block.clear();
312 conv.slice(&mut block, &items[j * width..][..count * width]);
313 let mut k = 0;
314 for piece in axis.pieces(j, count) {
315 let (base, first, rest) = Steps::boxed(base, piece, rest);
316 scatter_axis(out, &block, base, &first, rest, &mut k);
317 }
318 }
319}
320
321fn scatter_into<T: Item>(out: &mut [T], items: &[T], base: usize, steps: &[Cow<Steps>], k: &mut usize) {
323 match steps.split_first() {
324 Some((axis, rest)) => scatter_axis(out, items, base, axis, rest, k),
325 None => {
326 out[base] = nth(items, *k);
327 *k += 1;
328 }
329 }
330}
331
332#[inline]
334fn nth<T: Copy>(items: &[T], k: usize) -> T { if let [x] = items { *x } else { items[k] } }
335
336fn scatter_axis<T: Item>(out: &mut [T], items: &[T], base: usize, axis: &Steps, rest: &[Cow<Steps>], k: &mut usize) {
338 let item = |k: usize| nth(items, k);
339 if rest.is_empty() {
340 if axis.len() == 0 { return; }
341 match *axis {
342 Steps::Table(ref t) => {
343 if !t.put_into(out, base, items, *k) {
344 t.chunks(|j0, run| {
345 for (j, &o) in run.iter().enumerate() { if o != Steps::FILL { out[base + o] = item(*k + j0 + j) } }
346 })
347 }
348 }
349 Steps::Stride { start, len, step: 1 } => row(&mut out[base + start..][..len], items, *k),
350 Steps::Stride { start, len, step: -1 } => {
351 let out = &mut out[base + start + 1 - len..=base + start];
352 match items { [x] => out.fill(*x), _ => { for (o, &x) in out.iter_mut().rev().zip(&items[*k..][..len]) { *o = x } } }
353 }
354 Steps::Stride { start, len, step: 0 } => out[base + start] = item(*k + len - 1),
356 Steps::Stride { start, len, step } => {
357 let out = &mut out[base..];
358 checked_run(start, len, step, out.len());
359 for j in 0..len { unsafe { *out.get_unchecked_mut(start.wrapping_add_signed(step * j as isize)) = item(*k + j) } }
361 }
362 Steps::Rotated { shift, len, stride } => {
363 scatter_axis(out, items, base, &Steps::Stride { start: shift * stride, len: len - shift, step: stride as isize }, rest, k);
364 scatter_axis(out, items, base, &Steps::Stride { start: 0, len: shift, step: stride as isize }, rest, k);
365 return;
366 }
367 Steps::Padded { start, len, size, stride, edge } => {
368 let (before, lo, middle) = padded_parts(start, len, size);
369 let border = |out: &mut [T], from: i128, n: usize, k: &mut usize| {
371 for j in 0..n { if let Some(q) = edged(edge, from + j as i128, size) { out[base + q * stride] = item(*k + j) } }
372 *k += n;
373 };
374 border(out, start, before, k);
375 scatter_axis(out, items, base, &Steps::Stride { start: lo * stride, len: middle, step: stride as isize }, rest, k);
376 border(out, start + (before + middle) as i128, len - before - middle, k);
377 return;
378 }
379 }
380 *k += axis.len();
381 return;
382 }
383 if let [inner] = rest {
384 if let (&Steps::Stride { start: a, len: m, step: 1 }, &Steps::Stride { start: b, len: n, step }) = (axis, &**inner) {
386 if step > 1 && items.len() > 1 {
387 crate::linalg::transpose_into(&items[*k..], n, &mut out[base + a + b..], step as usize, [m, n], |x| x);
388 *k += m * n;
389 return;
390 }
391 }
392 if let Steps::Stride { start: b, len: n, step } = **inner {
393 if step == 1 && n > RUN {
395 axis.for_each(|r, o| { if let Some(o) = o { row(&mut out[base + o + b..][..n], items, *k + r * n) } });
396 *k += axis.len() * n;
397 return;
398 }
399 if let (Steps::Table(t), true) = (axis, step > 1) {
401 t.chunks(|j0, run| placed(out, items, base + b, run, n, step as usize, *k + j0 * n));
402 *k += axis.len() * n;
403 return;
404 }
405 }
406 }
407 if let Some(cell) = short_cells(rest, false) {
409 let width = cell.width();
410 if let Steps::Stride { start: a, len: m, step } = *axis {
411 runs!(cell.len, L => windows_into::<L, T::Unit>(unsafe { written_as(out) }, units(items), base + a, step, m, &cell, *k));
413 *k += m * width;
414 return;
415 }
416 match items {
417 [x] => axis.for_each(|_, o| { if let Some(o) = o { for c in cell.offsets() { out[base + o + c] = *x } } }),
418 _ => axis.for_each(|r, o| {
419 if let Some(o) = o {
420 let items = &items[*k + r * width..][..width];
421 for (&x, c) in items.iter().zip(cell.offsets()) { out[base + o + c] = x }
422 }
423 }),
424 }
425 *k += axis.len() * width;
426 return;
427 }
428 let width = Steps::count(rest);
429 axis.for_each(|_, o| match o { Some(o) => scatter_into(out, items, base + o, rest, k), None => *k += width });
430}
431#[inline]
433fn row<T: Copy>(out: &mut [T], items: &[T], k: usize) {
434 match items { [x] => out.fill(*x), _ => { let items = &items[k..][..out.len()]; for i in 0..items.len() { out[i] = items[i] } } }
435}
436#[derive(Clone, Copy)]
438pub enum Writes<'a> { Offsets(&'a [usize]), Walk { base: usize, steps: &'a [Steps] } }
439
440impl<'a> Writes<'a> {
441 pub fn len(&self) -> usize { match *self { Self::Offsets(offsets) => offsets.len(), Self::Walk { steps, .. } => Steps::count(steps) } }
443 pub fn is_empty(&self) -> bool { self.len() == 0 }
445 pub fn listed(&self) -> Cow<'a, [usize]> {
447 match *self { Self::Offsets(offsets) => Cow::Borrowed(offsets), Self::Walk { base, steps } => Cow::Owned(Steps::combined(base, steps)) }
448 }
449 pub fn runs_while(&self, each: &mut dyn FnMut(usize, &[usize]) -> bool) -> bool {
451 match *self {
452 Self::Offsets(offsets) => each(0, offsets),
453 Self::Walk { base: 0, steps: [Steps::Table(t)] } => t.runs_while(each),
454 Self::Walk { base, steps } => {
455 let (mut run, mut k) = (Vec::with_capacity(TABLE_CHUNK), 0);
456 let ok = Steps::reached(&mut run, base, steps, &mut |run| {
457 run.len() < TABLE_CHUNK || {
458 let ok = each(k, run);
459 k += run.len();
460 run.clear();
461 ok
462 }
463 });
464 ok && (run.is_empty() || each(k, &run))
465 }
466 }
467 }
468 pub fn only_fills(&self) -> bool { self.runs_while(&mut |_, run| run.iter().all(|&o| o == Steps::FILL)) }
470 pub fn write<S: Item, D: Item>(self, out: &mut [D], items: &[S], conv: impl Convert<S, D>) {
472 match self { Self::Offsets(offsets) => scatter(out, offsets, items, conv), Self::Walk { base, steps } => scatter_walk(out, items, base, steps, conv) }
473 }
474 pub fn combine<D: Copy, S: Copy, E: Copy>(self, out: &mut [D], values: Arg<'_, S>, f: impl Fn(D, S) -> (D, Option<E>)) -> Option<E> {
476 let mut failed = None;
477 self.runs_while(&mut |k, run| {
478 failed = combine_run(out, run, values.part(k, run.len()), &f).or(failed);
479 true
480 });
481 failed
482 }
483}
484
485fn combine_run<D: Copy, S: Copy, E: Copy>(out: &mut [D], run: &[usize], values: Arg<'_, S>, f: &impl Fn(D, S) -> (D, Option<E>)) -> Option<E> {
487 let mut failed = None;
488 for (j, &o) in run.iter().enumerate() {
489 if let Some(slot) = out.get_mut(o) {
490 let (r, e) = f(*slot, values.nth(j));
491 *slot = r;
492 failed = e.or(failed)
493 }
494 }
495 failed
496}
497
498pub fn counts_up(xs: &[usize]) -> bool { xs.iter().enumerate().all(|(i, &x)| x == i) }
500
501fn edged(edge: Edge, p: i128, size: usize) -> Option<usize> { edge.position(i64::try_from(p).ok()?, size) }
503
504fn padded_parts(start: i128, len: usize, size: usize) -> (usize, usize, usize) {
506 let (lo, hi) = (start.clamp(0, size as i128), (start + len as i128).clamp(0, size as i128));
507 ((lo - start).clamp(0, len as i128) as usize, lo as usize, (hi - lo).max(0) as usize)
508}
509
510#[derive(Clone, Debug, PartialEq, Eq)]
512pub enum Steps {
513 Stride { start: usize, len: usize, step: isize },
515 Padded { start: i128, len: usize, size: usize, stride: usize, edge: Edge },
517 Rotated { shift: usize, len: usize, stride: usize },
519 Table(Table),
521}
522
523pub trait IndexSource: Send + Sync {
525 fn view(&self) -> View<'_>;
527}
528impl IndexSource for crate::buffer::Buffer { fn view(&self) -> View<'_> { self.view() } }
529
530pub trait IndexValue: Copy {
532 fn position(self) -> i64;
534 fn bounds(values: &[Self]) -> (i64, i64) {
536 values.iter().fold((i64::MAX, i64::MIN), |(lo, hi), &i| { let p = i.position(); (lo.min(p), hi.max(p)) })
538 }
539}
540impl IndexValue for bool {
541 #[inline(always)]
542 fn position(self) -> i64 { self.into() }
543}
544macro_rules! index_values {
545 ($($t:ty),*) => {
546 $(impl IndexValue for $t {
547 #[inline(always)] fn position(self) -> i64 { self.into() }
548 fn bounds(values: &[Self]) -> (i64, i64) { let (lo, hi) = values.iter().fold((<$t>::MAX, <$t>::MIN), |(lo, hi), &i| (lo.min(i), hi.max(i))); (lo.into(), hi.into()) }
550 })*
551 };
552}
553index_values!(i8, i16, i32, i64, u8, u16, u32);
554
555#[derive(Clone, Debug)]
557pub struct Table { all: Positions, start: usize, len: usize }
558
559#[derive(Clone)]
561enum Positions { Listed(Arc<Vec<usize>>), Indices { values: Arc<dyn IndexSource>, size: usize, scale: usize, even: Option<(usize, isize)> } }
562impl std::fmt::Debug for Positions {
563 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
564 match self {
565 Self::Listed(offsets) => f.debug_tuple("Listed").field(offsets).finish(),
566 Self::Indices { size, scale, even, .. } => f.debug_struct("Indices").field("size", size).field("scale", scale).field("even", even).finish(),
567 }
568 }
569}
570
571const TABLE_CHUNK: usize = 256;
573
574macro_rules! with_index_values {
576 ($view:expr, |$x:ident| $body:expr) => {
577 match $view {
578 View::Booleans($x) => $body,
579 View::Integers(ix) => with_ints!(ix, |$x| $body),
580 _ => unreachable!("a table's index values are Booleans or integers"),
581 }
582 };
583}
584pub(crate) use with_index_values;
585
586impl Table {
587 pub fn new(offsets: Vec<usize>) -> Self { Self { start: 0, len: offsets.len(), all: Positions::Listed(Arc::new(offsets)) } }
589 pub fn indices(values: Arc<dyn IndexSource>, size: usize, even: Option<(usize, isize)>) -> Self {
591 let len = values.view().len();
592 Self { start: 0, len, all: Positions::Indices { values, size, scale: 1, even } }
593 }
594 #[inline]
596 pub fn len(&self) -> usize { self.len }
597 #[inline]
599 pub fn listed(&self) -> Option<&[usize]> {
600 match &self.all { Positions::Listed(o) => Some(&o[self.start..self.start + self.len]), Positions::Indices { .. } => None }
601 }
602 #[inline]
604 pub fn get(&self, j: usize) -> Option<usize> {
605 match &self.all {
606 Positions::Listed(o) => Some(o[self.start + j]).filter(|&o| o != Steps::FILL),
607 Positions::Indices { values, size, scale, .. } => Some(index_at(values.view(), self.start + j, *size) * scale),
608 }
609 }
610 #[inline]
612 pub fn chunks(&self, mut each: impl FnMut(usize, &[usize])) { self.runs_while(&mut |j, run| { each(j, run); true }); }
613 #[inline]
615 pub fn all(&self, mut f: impl FnMut(Option<usize>) -> bool) -> bool {
616 self.runs_while(&mut |_, run| run.iter().all(|&o| f((o != Steps::FILL).then_some(o))))
617 }
618 fn runs_while(&self, each: &mut dyn FnMut(usize, &[usize]) -> bool) -> bool {
620 match &self.all {
621 Positions::Listed(o) => each(0, &o[self.start..self.start + self.len]),
622 Positions::Indices { values, size, scale, .. } => converted(values.view(), self.start, self.len, *size, *scale, each),
623 }
624 }
625 pub fn slice(&self, start: usize, len: usize) -> Self { Self { start: self.start + start, len, ..self.clone() } }
627 pub fn scaled(mut self, k: usize) -> Self {
629 if k == 1 { return self; }
630 match &mut self.all {
631 Positions::Listed(o) => { for o in &mut Arc::make_mut(o)[self.start..self.start + self.len] { if *o != Steps::FILL { *o *= k } } }
632 Positions::Indices { scale, .. } => *scale *= k,
633 }
634 self
635 }
636 pub fn fills(&self) -> bool { self.listed().is_some_and(|o| o.contains(&Steps::FILL)) }
638 fn bytes(&self) -> usize { self.listed().map_or(0, |o| o.len() * size_of::<usize>()) }
640 fn span(&self) -> Option<(usize, usize)> { match self.all { Positions::Indices { size, scale, .. } => Some((scale, size)), Positions::Listed(_) => None } }
642 fn write_offsets(&self, base: usize, out: &mut [MaybeUninit<usize>]) {
644 fn positions<I: IndexValue>(values: &[I], size: usize, scale: usize, base: usize, out: &mut [MaybeUninit<usize>]) {
645 let at = |i: I| crate::structure::counted_back(i.position(), size);
646 if scale == 1 { for (slot, &i) in out.iter_mut().zip(values) { slot.write(base + at(i)); } }
648 else { for (slot, &i) in out.iter_mut().zip(values) { slot.write(base + at(i) * scale); } }
649 }
650 let range = self.start..self.start + self.len;
651 match &self.all {
652 Positions::Listed(o) => { for (slot, &o) in out.iter_mut().zip(&o[range]) { slot.write(if o == Steps::FILL { o } else { base + o }); } }
653 Positions::Indices { values, size, scale, .. } => with_index_values!(values.view(), |x| positions(&x[range], *size, *scale, base, out)),
654 }
655 }
656 fn take_into<T: Copy>(&self, d: &mut Vec<T>, s: &[T]) -> bool {
658 let Positions::Indices { ref values, size, scale: 1, .. } = self.all else { return false };
659 let Some(items) = s.get(..size) else { return false };
660 let range = self.start..self.start + self.len;
661 with_index_values!(values.view(), |x| take(d, items, &x[range], |v| v));
662 true
663 }
664 fn put_into<T: Copy>(&self, out: &mut [T], base: usize, items: &[T], k: usize) -> bool {
666 let Positions::Indices { ref values, size, scale: 1, .. } = self.all else { return false };
667 let Some(out) = out.get_mut(base..base + size) else { return false };
668 let items = if let [_] = items { items } else { &items[k..k + self.len] };
669 let range = self.start..self.start + self.len;
670 with_index_values!(values.view(), |x| put(out, items, &x[range]));
671 true
672 }
673 fn stride(&self) -> Option<Steps> {
675 let Positions::Indices { scale, even: Some((first, step)), .. } = self.all else { return None };
676 Some(Steps::Stride { start: first.wrapping_add_signed(step * self.start as isize) * scale, len: self.len, step: step * scale as isize })
677 }
678 pub(crate) fn affine(&self, lens: &[usize], into: &mut Vec<Steps>) -> bool {
680 if lens.is_empty() || self.len == 0 { return false; }
681 let at = into.len();
682 into.extend(lens.iter().map(|&len| Steps::Stride { start: 0, len, step: 0 }));
683 let (strides, range) = (&mut into[at..], self.start..self.start + self.len);
684 let first = match &self.all {
685 Positions::Indices { even: Some(_), .. } => self.stride().map(|flat| {
687 let Steps::Stride { start, step: mut width, .. } = flat else { unreachable!("`stride` gives a stride") };
688 for s in strides.iter_mut().rev() {
689 if let Steps::Stride { len, step, .. } = s {
690 *step = width;
691 width *= *len as isize;
692 }
693 }
694 start
695 }),
696 Positions::Indices { .. } if lens.len() == 1 => None,
697 Positions::Indices { values, size, scale, .. } => with_index_values!(values.view(), |x| stepping(&x[range.clone()], strides, |v| v.position()))
698 .and_then(|first| {
699 let (mut lo, mut hi) = (first, first);
701 for s in strides.iter_mut() {
702 let Steps::Stride { len, step, .. } = s else { unreachable!("`affine` pushes strides") };
703 let reach = *step as i64 * (*len as i64 - 1);
704 if reach < 0 { lo += reach }
705 else { hi += reach }
706 *step *= *scale as isize;
707 }
708 (lo >= 0 || hi < 0).then(|| crate::structure::counted_back(first, *size) * scale)
709 }),
710 Positions::Listed(o) if !o[range.clone()].contains(&Steps::FILL) => stepping(&o[range], strides, |o| o as i64).map(|first| first as usize),
711 Positions::Listed(_) => None,
712 };
713 match first { Some(first) => { Steps::settle(&mut into[at..], first); true } None => { into.truncate(at); false } }
714 }
715 pub(crate) fn edged(&self, size: usize, stride: usize) -> Option<Steps> {
717 if self.len < 2 || size < 2 || stride == 0 { return None; }
718 let (n, step) = (self.len, stride as i128);
719 let follows = |j: usize| match (self.get(j - 1), self.get(j)) {
720 (Some(a), Some(b)) => [step, 0, -step, (1 - size as i128) * step].contains(&(b as i128 - a as i128)), _ => true
721 };
722 if !follows(n - 1) || !follows(n / 2) { return None; }
723 let (mut previous, mut start) = (Steps::FILL, None);
724 self.runs_while(&mut |j0, run| {
725 for (r, &o) in run.iter().enumerate() {
726 if o != Steps::FILL && previous != Steps::FILL && o == previous + stride {
727 start = Some((previous / stride) as i128 + 1 - (j0 + r) as i128);
728 return false;
729 }
730 previous = o;
731 }
732 true
733 });
734 let start = start?;
735 let (before, lo, middle) = padded_parts(start, n, size);
736 if !self.slice(before, middle).runs_while(&mut |j0, run| {
737 run.first().is_none_or(|&o| o == (lo + j0) * stride)
738 && run.iter().zip(run.get(1..).unwrap_or_default()).fold(true, |all, (&a, &b)| all & (b.wrapping_sub(a) == stride))
739 }) { return None; }
740 let edge = Edge::MODES.iter().map(|&(_, e)| e)
741 .find(|&e| (0..before).chain(before + middle..n).all(|j| self.get(j) == edged(e, start + j as i128, size).map(|p| p * stride)))?;
742 Some(Steps::padded(start, n, size, stride, edge))
743 }
744}
745
746fn stepping<T: Copy>(values: &[T], strides: &mut [Steps], position: impl Fn(T) -> i64) -> Option<i64> {
748 let first = position(values[0]);
749 let mut block = values.len();
750 for s in strides.iter_mut() {
751 let Steps::Stride { len, step, .. } = s else { unreachable!("`Table::affine` passes strides") };
752 let width = block / *len;
753 if *len > 1 {
754 let d = position(values[width]) - first;
755 *step = d as isize;
756 let steps = |(&a, &b): (&T, &T)| position(a) - position(b) == d;
757 if !steps((&values[block - 1], &values[block - 1 - width]))
758 || !values[width..block].iter().zip(&values[..block - width]).fold(true, |all, pair| all & steps(pair)) { return None; }
759 }
760 block = width;
761 }
762 Some(first)
763}
764
765impl PartialEq for Table {
766 fn eq(&self, other: &Self) -> bool {
767 if self.len != other.len { return false; }
768 let shared = self.start == other.start && match (&self.all, &other.all) {
770 (Positions::Listed(a), Positions::Listed(b)) => Arc::ptr_eq(a, b),
771 (Positions::Indices { values: a, size: sa, scale: ka, .. }, Positions::Indices { values: b, size: sb, scale: kb, .. }) => {
772 sa == sb && ka == kb && Arc::ptr_eq(a, b)
773 }
774 _ => false,
775 };
776 shared || (0..self.len).all(|j| self.get(j) == other.get(j))
777 }
778}
779impl Eq for Table {}
780
781fn index_at(view: View<'_>, j: usize, size: usize) -> usize { with_index_values!(view, |x| crate::structure::counted_back(x[j].position(), size)) }
783
784fn converted(view: View<'_>, start: usize, len: usize, size: usize, scale: usize, each: &mut dyn FnMut(usize, &[usize]) -> bool) -> bool {
786 fn runs<I: IndexValue>(values: &[I], size: usize, scale: usize, each: &mut dyn FnMut(usize, &[usize]) -> bool) -> bool {
787 let mut run = [0; TABLE_CHUNK];
788 values.chunks(TABLE_CHUNK).enumerate().all(|(c, chunk)| {
789 if scale == 1 { for (o, &i) in run.iter_mut().zip(chunk) { *o = crate::structure::counted_back(i.position(), size); } }
791 else { for (o, &i) in run.iter_mut().zip(chunk) { *o = crate::structure::counted_back(i.position(), size) * scale; } }
792 each(c * TABLE_CHUNK, &run[..chunk.len()])
793 })
794 }
795 with_index_values!(view, |x| runs(&x[start..start + len], size, scale, each))
796}
797
798impl Steps {
799 fn merged(outer: &Self, inner: &Self) -> Option<Self> {
800 let (Self::Stride { start: a, len: m, step: so }, Self::Stride { start: b, len: n, step: si }) = (outer.even()?, inner.even()?) else { return None };
801 (so == si.checked_mul(n as isize)?).then_some(Self::Stride { start: a + b, len: m * n, step: si })
802 }
803}
804
805impl Steps {
806 pub const FILL: usize = usize::MAX;
808 pub fn along(len: usize, stride: usize) -> Self { Self::Stride { start: 0, len, step: stride as isize } }
810 pub fn row_major(lens: &[usize], scale: usize, start: usize) -> impl Iterator<Item = Self> + '_ {
812 lens.iter().zip(crate::layout::strides(lens)).enumerate().map(move |(j, (&len, stride))| Self::Stride { start: if j == 0 { start } else { 0 }, len,
813 step: (scale * stride) as isize })
814 }
815 pub fn table(offsets: Vec<usize>) -> Self { Self::Table(Table::new(offsets)) }
817 pub fn scaled(self, k: usize) -> Self {
819 match self {
820 Self::Stride { start, len, step } => Self::Stride { start: start * k, len, step: step * k as isize },
821 Self::Padded { start, len, size, stride, edge } => Self::Padded { start, len, size, stride: stride * k, edge },
822 Self::Rotated { shift, len, stride } => Self::Rotated { shift, len, stride: stride * k }, Self::Table(table) => Self::Table(table.scaled(k))
823 }
824 }
825 pub fn padded(start: i128, len: usize, size: usize, stride: usize, edge: Edge) -> Self {
827 if edge != Edge::Fill && size == 1 { return Self::Stride { start: 0, len, step: 0 }; }
828 if edge == Edge::Wrap && len == size && size != 0 { return Self::rotated(start.rem_euclid(size as i128) as usize, len, stride); }
829 if start >= 0 && start + len as i128 <= size as i128 { Self::Stride { start: start as usize * stride, len, step: stride as isize } }
830 else { Self::Padded { start, len, size, stride, edge } }
831 }
832 pub fn clipped(start: i128, len: usize, size: usize, stride: usize) -> Self { Self::padded(start, len, size, stride, Edge::Fill) }
834 pub fn rotated(shift: usize, len: usize, stride: usize) -> Self {
836 if len < 2 { return Self::along(len, stride); }
837 let shift = shift % len;
838 if shift == 0 { Self::along(len, stride) } else { Self::Rotated { shift, len, stride } }
839 }
840 #[inline]
842 pub fn len(&self) -> usize {
843 match self { Self::Stride { len, .. } | Self::Padded { len, .. } | Self::Rotated { len, .. } => *len, Self::Table(t) => t.len() }
844 }
845 pub fn footprint(&self) -> usize { size_of::<Self>() + if let Self::Table(t) = self { t.bytes() } else { 0 } }
847 #[inline]
849 pub fn get(&self, j: usize) -> Option<usize> {
850 match *self {
851 Self::Stride { start, step, .. } => Some(start.wrapping_add_signed(step * j as isize)),
852 Self::Padded { start, size, stride, edge, .. } => edged(edge, start + j as i128, size).map(|p| p * stride),
853 Self::Rotated { shift, len, stride } => Some((shift + j) % len * stride), Self::Table(ref t) => t.get(j)
854 }
855 }
856 #[inline]
858 pub fn offsets(&self) -> impl ExactSizeIterator<Item = Option<usize>> + '_ { (0..self.len()).map(|j| self.get(j)) }
859 #[inline(always)]
861 pub fn for_each(&self, mut each: impl FnMut(usize, Option<usize>)) {
862 match *self {
863 Self::Stride { start, len, step } => { for r in 0..len { each(r, Some(start.wrapping_add_signed(step * r as isize))) } }
864 Self::Padded { start, len, size, stride, edge } => {
865 let (before, lo, middle) = padded_parts(start, len, size);
866 let border = |r: usize| edged(edge, start + r as i128, size).map(|p| p * stride);
867 for r in 0..before { each(r, border(r)) }
868 for r in 0..middle { each(before + r, Some((lo + r) * stride)) }
869 for r in before + middle..len { each(r, border(r)) }
870 }
871 Self::Rotated { shift, len, stride } => {
872 for r in 0..len - shift { each(r, Some((shift + r) * stride)) }
873 for r in len - shift..len { each(r, Some((r + shift - len) * stride)) }
874 }
875 Self::Table(ref t) => t.chunks(|j0, run| {
876 for (r, &o) in run.iter().enumerate() { each(j0 + r, (o != Self::FILL).then_some(o)) }
877 }),
878 }
879 }
880 fn pieces(&self, start: usize, len: usize) -> impl Iterator<Item = Cow<'_, Self>> {
882 let pieces = if len == 0 { [None, None] } else {
883 match *self {
884 Self::Stride { start: s, step, .. } => {
885 [Some(Cow::Owned(Self::Stride { start: s.wrapping_add_signed(step * start as isize), len, step })), None]
886 }
887 Self::Padded { start: s, size, stride, edge, .. } => [Some(Cow::Owned(Self::padded(s + start as i128, len, size, stride, edge))), None],
888 Self::Rotated { shift, len: n, stride } => {
889 let first = (shift + start) % n;
890 let head = len.min(n - first);
891 [
892 Some(Cow::Owned(Self::Stride { start: first * stride, len: head, step: stride as isize })),
893 (head < len).then(|| Cow::Owned(Self::Stride { start: 0, len: len - head, step: stride as isize })),
894 ]
895 }
896 Self::Table(ref t) if start == 0 && len == t.len() => [Some(Cow::Borrowed(self)), None],
897 Self::Table(ref t) => [Some(Cow::Owned(Self::Table(t.slice(start, len)))), None],
898 }
899 };
900 pieces.into_iter().flatten()
901 }
902 pub fn count(steps: &[impl std::borrow::Borrow<Self>]) -> usize { steps.iter().map(|s| s.borrow().len()).product() }
904 pub fn combined(base: usize, steps: &[impl std::borrow::Borrow<Self>]) -> Vec<usize> {
906 let mut out = Vec::with_capacity(Self::count(steps));
907 Self::reached(&mut out, base, steps, &mut |_| true);
908 out
909 }
910 fn reached<B: std::borrow::Borrow<Self>>(out: &mut Vec<usize>, base: usize, steps: &[B], flush: &mut dyn FnMut(&mut Vec<usize>) -> bool) -> bool {
912 let Some((axis, rest)) = steps.split_first() else { out.push(base); return flush(out); };
913 let axis = axis.borrow();
914 if !rest.is_empty() {
915 let mut ok = true;
916 axis.for_each(|_, o| {
917 if ok { ok = Self::reached(out, if base == Self::FILL { base } else { o.map_or(Self::FILL, |o| base + o) }, rest, flush) }
918 });
919 return ok;
920 }
921 match axis {
922 _ if base == Self::FILL => out.extend(std::iter::repeat_n(Self::FILL, axis.len())),
923 Self::Table(table) => unsafe { crate::slice::appended(out, table.len(), |slots| table.write_offsets(base, slots)) },
924 _ => {
925 let len = axis.len();
926 for r0 in (0..len).step_by(TABLE_CHUNK) {
927 let r1 = len.min(r0 + TABLE_CHUNK);
928 match *axis {
929 Self::Stride { start, step, .. } => out.extend((r0..r1).map(|r| base + start.wrapping_add_signed(step * r as isize))),
930 _ => out.extend((r0..r1).map(|r| axis.get(r).map_or(Self::FILL, |o| base + o))),
931 }
932 if r1 < len && !flush(out) { return false; }
933 }
934 }
935 }
936 flush(out)
937 }
938 pub(crate) fn simplify<B: std::borrow::Borrow<Self>>(mut base: usize, steps: &[B]) -> (usize, Vec<Cow<'_, Self>>) {
940 let mut kept: Vec<Cow<Self>> = Vec::with_capacity(steps.len());
941 for s in steps {
942 let s = s.borrow();
943 if s.len() == 1 && let Some(first) = s.get(0) { base += first; continue; }
944 kept.push(Cow::Borrowed(s));
945 while let [.., outer, inner] = kept.as_slice() {
946 let Some(merged) = Self::merged(outer, inner) else { break };
947 kept.truncate(kept.len() - 2);
948 kept.push(Cow::Owned(merged));
949 }
950 }
951 let innermost = kept.last().and_then(|s| if matches!(**s, Self::Table(_)) { s.even() } else { None });
952 if let (Some(stride), Some(last)) = (innermost, kept.last_mut()) { *last = Cow::Owned(stride); }
953 (base, kept)
954 }
955 pub(crate) fn transposing(outer: &Self, inner: &Self) -> Option<(usize, usize, usize, usize)> {
957 match (outer, inner) {
958 (&Self::Stride { start: a, len: m, step: 1 }, &Self::Stride { start: b, len: n, step }) if step > 1 => Some((a + b, m, n, step as usize)), _ => None
959 }
960 }
961 fn boxed<'a>(base: usize, piece: Cow<'a, Self>, rest: &'a [Cow<'a, Self>]) -> (usize, Cow<'a, Self>, &'a [Cow<'a, Self>]) {
963 let (base, piece, rest) = match (piece.len() == 1).then(|| piece.get(0)).flatten().zip(rest.split_first()) {
964 Some((o, (first, after))) => (base + o, first.clone(), after), None => (base, piece, rest)
965 };
966 match rest.split_first().and_then(|(inner, after)| Some((Self::merged(&piece, inner)?, after))) {
967 Some((merged, after)) => (base, Cow::Owned(merged), after),
968 None if rest.is_empty() && matches!(*piece, Self::Table(_)) => (base, piece.even().map_or(piece, Cow::Owned), rest), None => (base, piece, rest)
969 }
970 }
971 pub(crate) fn settle(strides: &mut [Self], first: usize) {
973 let mut rest = first;
974 for s in strides.iter_mut().skip(1) {
975 if let Self::Stride { start, len, step } = s {
976 *start = if *step < 0 { step.unsigned_abs() * (*len - 1) } else { 0 };
977 rest -= *start;
978 }
979 }
980 if let Some(Self::Stride { start, .. }) = strides.first_mut() { *start = rest; }
981 }
982 pub(crate) fn even(&self) -> Option<Self> {
984 match self {
985 Self::Stride { .. } => Some(self.clone()),
986 Self::Table(t) => {
987 let Some(offsets) = t.listed() else { return t.stride() };
988 let &[first, second, ..] = offsets else { return None };
989 let step = second.wrapping_sub(first) as isize;
990 (first != Self::FILL && offsets.windows(2).all(|p| p[1] != Self::FILL && p[1].wrapping_sub(p[0]) as isize == step)).then_some(Self::Stride {
991 start: first, len: offsets.len(), step })
992 }
993 _ => None,
994 }
995 }
996 #[inline]
998 pub fn reach(base: usize, steps: &[impl std::borrow::Borrow<Self>], mut i: usize) -> Option<usize> {
999 let mut offset = base;
1000 for s in steps.iter().rev() {
1001 let s = s.borrow();
1002 offset += s.get(i % s.len())?;
1003 i /= s.len();
1004 }
1005 Some(offset)
1006 }
1007 pub fn furthest(base: usize, steps: &[impl std::borrow::Borrow<Self>]) -> Option<usize> {
1009 steps.iter().try_fold(base, |at, s| {
1010 let furthest = match *s.borrow() {
1011 ref s if s.len() == 0 => return None, Self::Stride { start, len, step } => start.wrapping_add_signed(step.max(0) * (len - 1) as isize),
1012 Self::Padded { size, stride, .. } => size.saturating_sub(1) * stride, Self::Rotated { len, stride, .. } => (len - 1) * stride,
1013 Self::Table(ref t) => t.span().map_or_else(
1014 || (0..t.len()).filter_map(|j| t.get(j)).max().unwrap_or(0), |(scale, size)| size.saturating_sub(1) * scale)
1015 };
1016 Some(at + furthest)
1017 })
1018 }
1019 #[inline]
1021 pub fn run(base: usize, steps: &[impl std::borrow::Borrow<Self>], start: usize, n: usize) -> Option<(usize, isize)> {
1022 if n == 0 { return None; }
1023 let (mut width, mut stride) = (1usize, None);
1024 for axis in steps.iter().rev() {
1025 let axis = axis.borrow();
1026 let len = axis.len();
1027 if len == 0 { return None; }
1028 if len == 1 { axis.get(0)?; continue; }
1029 let (i, end) = ((start / width) % len, ((start + n - 1) / width) % len);
1030 let fits = start % (width * len) + n <= width * len;
1031 let step = match *axis {
1032 Self::Stride { step, .. } => step,
1033 Self::Padded { start: s, size, stride, .. } if fits && s + i as i128 >= 0 && s + (end + 1) as i128 <= size as i128 => stride as isize,
1034 Self::Rotated { shift, stride, .. } if fits && (shift + i) % len + end - i < len => stride as isize, _ => return None
1035 };
1036 if let Some(s) = stride { if step != s * width as isize { return None; } }
1037 else { stride = Some(step); }
1038 width *= len;
1039 if fits { return Some((Self::reach(base, steps, start)?, stride.unwrap())); }
1040 }
1041 (n == 1).then(|| (Self::reach(base, steps, start).expect("singleton run has no fill"), 1))
1042 }
1043 pub fn regular(steps: &[Self]) -> (usize, isize) {
1045 let (mut width, mut stride) = (1, None);
1046 for axis in steps.iter().rev() {
1047 if axis.len() == 1 { continue; }
1048 let step = match *axis {
1049 Self::Stride { step, .. } => step, Self::Padded { stride, .. } | Self::Rotated { stride, .. } => stride as isize, Self::Table(_) => break
1050 };
1051 if stride.is_some_and(|s: isize| step != s * width as isize) { break; }
1052 stride.get_or_insert(step);
1053 width *= axis.len();
1054 }
1055 (width, stride.unwrap_or(1))
1056 }
1057 pub fn contiguous(steps: &[Self]) -> usize { match Self::regular(steps) { (width, 1) => width, _ => 1 } }
1059 pub fn skips(&self) -> bool {
1061 match *self {
1062 Self::Stride { step, .. } => step.unsigned_abs() > 1, Self::Padded { stride, .. } | Self::Rotated { stride, .. } => stride > 1,
1063 Self::Table(_) => false
1064 }
1065 }
1066 pub fn fills(&self) -> bool { match self { Self::Padded { edge, .. } => *edge == Edge::Fill, Self::Table(t) => t.fills(), _ => false } }
1068 pub fn affine(&self) -> Option<(usize, isize)> { match *self { Self::Stride { start, step, .. } => Some((start, step)), _ => None } }
1070 pub fn in_order(tables: &[Self]) -> bool {
1072 let mut stride = 1;
1073 tables.iter().rev().all(|s| match *s {
1074 Self::Stride { start: 0, len, step } => {
1075 let ordered = len <= 1 || step == stride as isize;
1076 stride *= len;
1077 ordered
1078 }
1079 Self::Table(ref t) => {
1080 let (mut j, at) = (0, stride);
1081 stride *= t.len();
1082 t.all(|o| {
1083 let ordered = o == Some(j * at);
1084 j += 1;
1085 ordered
1086 })
1087 }
1088 _ => false,
1089 })
1090 }
1091 pub fn spreads(&self) -> bool {
1093 match *self {
1094 Self::Stride { len, step, .. } => step == 0 && len > 1, Self::Padded { .. } => true, Self::Rotated { .. } => false,
1095 _ => { let mut seen = crate::hashing::HashSet::default(); !self.offsets().all(|o| o.is_some_and(|o| seen.insert(o))) }
1096 }
1097 }
1098 pub fn per_axis(tables: &[Self], shape: &[usize]) -> Option<(usize, Vec<Self>)> {
1100 let (mut base, tables) = Self::simplify(0, tables);
1101 let (mut steps, mut a) = (Vec::with_capacity(shape.len()), 0);
1102 let ones = |steps: &mut Vec<Self>, a: &mut usize| {
1103 while *a < shape.len() && shape[*a] == 1 {
1104 steps.push(Self::Stride { start: 0, len: 1, step: 0 });
1105 *a += 1;
1106 }
1107 };
1108 for t in &tables {
1109 if t.len() == 1 { base += t.get(0)?; continue; }
1110 ones(&mut steps, &mut a);
1111 let (first, mut n) = (a, 1);
1112 while a < shape.len() && n < t.len() {
1113 n *= shape[a];
1114 a += 1;
1115 }
1116 if n != t.len() { return None; }
1117 match (&shape[first..a], &**t) {
1118 ([_], _) => steps.push(t.clone().into_owned()),
1119 (group, &Self::Stride { start, step, .. }) => {
1120 let (at, mut width) = (steps.len(), n);
1121 for &len in group {
1122 width /= len;
1123 steps.push(Self::Stride { start: 0, len, step: step * width as isize });
1124 }
1125 Self::settle(&mut steps[at..], start);
1126 }
1127 _ => return None,
1128 }
1129 }
1130 ones(&mut steps, &mut a);
1131 (a == shape.len()).then_some((base, steps))
1132 }
1133 pub fn with_base(base: usize, steps: Vec<Self>) -> Vec<Self> {
1135 if base == 0 { steps } else { std::iter::once(Self::Stride { start: base, len: 1, step: 0 }).chain(steps).collect() }
1136 }
1137 fn by_axes(outer: &[Self], shape: &[usize]) -> Vec<usize> {
1139 let strides = crate::layout::strides(shape);
1140 let (_, merged) = Self::simplify(0, outer);
1141 let mut lens = Vec::with_capacity(shape.len());
1142 for e in &merged {
1143 if let Self::Stride { len, step, .. } = **e && let Some(a) = (0..shape.len()).find(|&a| shape[a] > 1 && strides[a] as isize == step)
1144 && len > shape[a] {
1145 let (mut first, mut n) = (a + 1, 1);
1146 while first > 0 && n < len {
1147 first -= 1;
1148 n *= shape[first];
1149 }
1150 if n == len { lens.extend_from_slice(&shape[first..=a]); continue; }
1151 }
1152 lens.push(e.len());
1153 }
1154 lens
1155 }
1156 pub fn through(outer: &[Self], shape: &[usize], mut base: usize, inner: &[Self]) -> Option<(usize, Vec<Self>)> {
1158 let lens: Vec<usize> = outer.iter().map(Self::len).collect();
1159 let Walk { base: at, steps: outer, along: axes, strides } =
1160 Walk::new(outer, &lens, shape).or_else(|| Walk::new(outer, &Self::by_axes(outer, shape), shape))?;
1161 let mut walks = vec![0usize; shape.len()];
1162 for &a in axes.iter().flatten() { walks[a] += 1; }
1163 if walks.iter().zip(inner).any(|(&w, r)| w > 1 && !matches!(r, Self::Stride { .. })) { return None; }
1165 let (mut first, mut taken) = (vec![None; shape.len()], vec![0; outer.len()]);
1167 for (k, &axis) in axes.iter().enumerate() {
1168 let Some(a) = axis else { continue };
1169 let f = *first[a].get_or_insert(k);
1170 let Self::Stride { start: r0, step: s, .. } = inner[a] else { continue };
1171 if f == k { taken[k] = r0; }
1172 else if let (true, &Self::Stride { start, len, step }) = (s < 0, &outer[k]) {
1173 taken[k] = s.unsigned_abs() * ((start + len.saturating_sub(1) * step.max(0) as usize) / strides[a]);
1174 taken[f] = taken[f].checked_sub(taken[k])?;
1175 }
1176 }
1177 let mut steps = Vec::with_capacity(outer.len());
1178 for (k, (e, &axis)) in outer.iter().zip(&axes).enumerate() {
1179 steps.push(match axis {
1180 None => { if e.fills() { e.clone() } else { Self::Stride { start: 0, len: e.len(), step: 0 } } }
1181 Some(a) => e.read_through(strides[a], &inner[a], first[a] == Some(k), taken[k], &mut base)?,
1182 });
1183 }
1184 for (a, p) in crate::layout::coordinates(at, shape) { if walks[a] == 0 { base += inner[a].get(p)?; } }
1185 Some((base, steps))
1186 }
1187 pub fn rereads(outer: &[Self], shape: &[usize]) -> bool {
1189 let Some(walk) = Walk::new(outer, &outer.iter().map(Self::len).collect::<Vec<_>>(), shape) else { return false };
1190 let mut walked = vec![false; shape.len()];
1191 walk.along.iter().flatten().any(|&a| std::mem::replace(&mut walked[a], true))
1192 }
1193 fn read_through(&self, unit: usize, r: &Self, first: bool, r0: usize, base: &mut usize) -> Option<Self> {
1195 if first && matches!(*self, Self::Stride { start: 0, len, step } if step == unit as isize && len == r.len()) {
1196 return Some(match *r { Self::Stride { len, step, .. } => Self::Stride { start: r0, len, step }, _ => r.clone() });
1197 }
1198 if let Self::Stride { step: s, .. } = *r {
1199 match *self {
1200 Self::Stride { start, len, step } => {
1201 let start = usize::try_from(r0 as isize + (start / unit) as isize * s).ok()?;
1202 return Some(Self::Stride { start, len, step: step / unit as isize * s });
1203 }
1204 Self::Rotated { shift, len, .. } if s >= 0 => { *base += r0; return Some(Self::rotated(shift, len, s as usize)); }
1205 Self::Padded { start, len, size, edge, .. } if s >= 0 => { *base += r0; return Some(Self::padded(start, len, size, s as usize, edge)); }
1206 _ => {}
1207 }
1208 }
1209 if first && let (&Self::Stride { start, len, step }, &Self::Padded { start: p, size, stride, edge, .. }) = (self, r) && step == unit as isize {
1211 return Some(Self::padded(p + (start / unit) as i128, len, size, stride, edge));
1212 }
1213 if first && let (&Self::Rotated { shift, len, stride }, &Self::Padded { start, len: m, size, stride: s, edge: Edge::Fill }) = (self, r)
1215 && stride == unit && len == m {
1216 let a = (-start - shift as i128).rem_euclid(len as i128);
1217 if a + size as i128 <= len as i128 { return Some(Self::padded(-a, len, size, s, Edge::Fill)); }
1218 }
1219 (first && (matches!(self, Self::Table(_)) || matches!(r, Self::Table(_)))).then(|| {
1220 let read = |p: usize| match *r { Self::Stride { step, .. } => Some(r0.wrapping_add_signed(step * p as isize)), _ => r.get(p) };
1221 let mut table = Vec::with_capacity(self.len());
1222 self.for_each(|_, o| table.push(o.and_then(|o| read(o / unit)).unwrap_or(Self::FILL)));
1223 Self::table(table)
1224 })
1225 }
1226 pub(crate) fn axis_of(&self, shape: &[usize], strides: &[usize]) -> Option<Option<usize>> {
1228 let zero = match *self {
1229 Self::Stride { start, len, step } => len == 0 || start == 0 && (step == 0 || len == 1),
1230 Self::Rotated { stride, .. } | Self::Padded { stride, .. } => stride == 0,
1231 Self::Table(ref t) => t.span().map_or_else(|| t.all(|o| o == Some(0)), |(scale, size)| scale == 0 || size <= 1),
1232 };
1233 if zero { return Some(None); }
1234 let fits = |a: usize| {
1235 let (s, n) = (strides[a], shape[a]);
1236 let at = |o: usize| o % s == 0 && o / s < n;
1237 match *self {
1238 Self::Stride { start, len, step } => step.unsigned_abs() % s == 0 && at(start) && at(start.wrapping_add_signed(step * (len as isize - 1))),
1239 Self::Rotated { stride, len, .. } => stride == s && len <= n,
1240 Self::Padded { stride, size, .. } => stride == s && size <= n,
1241 Self::Table(ref t) => {
1242 t.span().map_or_else(|| t.all(|o| o.is_none_or(at)), |(scale, size)| size <= 1 || scale % s == 0 && (size - 1) * scale / s < n)
1243 }
1244 }
1245 };
1246 (0..shape.len()).find(|&a| shape[a] > 1 && fits(a)).map(Some)
1247 }
1248}
1249
1250pub trait Convert<S: Copy, D> {
1252 fn one(&self, x: S) -> D;
1254 fn slice(&self, d: &mut Vec<D>, s: &[S]) {
1256 unsafe {
1257 crate::slice::appended(d, s.len(), |slots| {
1258 let slots = &mut slots[..s.len()];
1259 for i in 0..s.len() { slots[i].write(self.one(s[i])); }
1260 })
1261 }
1262 }
1263 fn all(&self, s: &[S]) -> Vec<D> {
1265 let mut d = Vec::with_capacity(s.len());
1266 self.slice(&mut d, s);
1267 d
1268 }
1269 fn same<'a>(&self, _d: &'a mut Vec<D>) -> Option<&'a mut Vec<S>> { None }
1271 fn borrowed<'a>(&self, _s: &'a [S]) -> Option<&'a [D]> { None }
1273}
1274impl<S: Copy, D, F: Fn(S) -> D> Convert<S, D> for F {
1275 #[inline]
1276 fn one(&self, x: S) -> D { self(x) }
1277}
1278pub struct Same;
1280impl<T: Copy> Convert<T, T> for Same {
1281 #[inline]
1282 fn one(&self, x: T) -> T { x }
1283 fn same<'a>(&self, d: &'a mut Vec<T>) -> Option<&'a mut Vec<T>> { Some(d) }
1284 fn borrowed<'a>(&self, s: &'a [T]) -> Option<&'a [T]> { Some(s) }
1285}
1286
1287pub unsafe trait Item: Copy + Send + Sync {
1292 type Unit: Unit;
1294 #[inline]
1296 fn cells_from<S: Item, C: Convert<S, Self>>(_out: &mut [Self], _items: &[S], _conv: &C, _at: usize, _step: isize, _rest: &[Cow<'_, Steps>]) -> bool {
1297 false
1298 }
1299 #[inline]
1301 fn cells_into_f64<C: Convert<Self, f64>>(_out: &mut [f64], _items: &[Self], _conv: &C, _at: usize, _step: isize, _rest: &[Cow<'_, Steps>]) -> bool { false }
1302}
1303pub unsafe trait Unit: Copy + Send + Sync + 'static {}
1308macro_rules! units {
1309 ($($u:ty),+; $($t:ty: $tu:ty $(=> $body:ident)?),+) => {
1310 $(unsafe impl Unit for $u {})+
1312 $(
1313 unsafe impl Item for $t { type Unit = $tu; $(units!(@$body);)? }
1315 const _: () = assert!(size_of::<$t>() == size_of::<$tu>() && align_of::<$t>() == align_of::<$tu>());
1316 )+
1317 };
1318 (@into_f64) => {
1320 #[inline]
1321 fn cells_into_f64<C: Convert<Self, f64>>(out: &mut [f64], items: &[Self], conv: &C, at: usize, step: isize, rest: &[Cow<'_, Steps>]) -> bool { converted_cells(out, items, conv, at, step, rest) }
1322 };
1323 (@from) => {
1325 #[inline]
1326 fn cells_from<S: Item, C: Convert<S, Self>>(out: &mut [Self], items: &[S], conv: &C, at: usize, step: isize, rest: &[Cow<'_, Steps>]) -> bool { S::cells_into_f64(out, items, conv, at, step, rest) }
1327 };
1328}
1329units!(u8, u16, u32, u64, [u32; 2], [u64; 2];
1331 bool: u8 => into_f64, u8: u8 => into_f64, i16: u16 => into_f64, i32: u32 => into_f64, i64: u64 => into_f64, half::f16: u16, f32: u32, f64: u64 => from,
1332 num_complex::Complex32: [u32; 2], num_complex::Complex64: [u64; 2], char: u32);
1333
1334fn units<T: Item>(items: &[T]) -> &[T::Unit] {
1336 unsafe { std::slice::from_raw_parts(items.as_ptr().cast(), items.len()) }
1338}
1339
1340unsafe fn written_as<A, B>(items: &mut [A]) -> &mut [B] {
1345 const { assert!(size_of::<A>() == size_of::<B>() && align_of::<A>() == align_of::<B>()) };
1346 unsafe { std::slice::from_raw_parts_mut(items.as_mut_ptr().cast(), items.len()) }
1348}
1349
1350pub fn interleave<T: Item>(out: &mut Vec<T>, parts: &[(&[T], usize)], rows: usize) {
1352 assert!(parts.iter().all(|&(items, n)| items.len() == rows * n), "each part holds one lane for every row");
1353 let width = parts.iter().map(|&(_, n)| n).sum::<usize>();
1354 let parts: Vec<(&[T::Unit], usize)> = parts.iter().map(|&(items, n)| (units(items), n)).collect();
1355 unsafe {
1356 crate::slice::appended(out, rows * width, |slots| {
1357 let slots = written_as::<MaybeUninit<T>, MaybeUninit<T::Unit>>(slots);
1359 match *parts {
1360 [(a, n), (b, m)] if n == m && (1..=RUN).contains(&n) => runs!(n, L => lane_pairs::<L, T::Unit>(slots, [a, b])),
1361 _ => lane_items(slots, &parts, width),
1362 }
1363 })
1364 }
1365}
1366
1367#[inline]
1369fn lane_pairs<const L: usize, U: Unit>(slots: &mut [MaybeUninit<U>], [a, b]: [&[U]; 2]) {
1370 let (a, b, mut to) = (a.as_ptr().cast::<[U; L]>(), b.as_ptr().cast::<[U; L]>(), slots.as_mut_ptr().cast::<[U; L]>());
1371 for r in 0..slots.len() / (2 * L) {
1372 unsafe {
1374 to.write(a.add(r).read());
1375 to.add(1).write(b.add(r).read());
1376 to = to.add(2)
1377 }
1378 }
1379}
1380
1381fn lane_items<U: Unit>(slots: &mut [MaybeUninit<U>], parts: &[(&[U], usize)], width: usize) {
1383 if width == 0 { return; }
1384 for (r, row) in slots.chunks_exact_mut(width).enumerate() {
1385 let mut at = 0;
1386 for &(items, n) in parts {
1387 for (slot, &u) in row[at..at + n].iter_mut().zip(&items[r * n..][..n]) { slot.write(u); }
1388 at += n;
1389 }
1390 }
1391}
1392
1393fn converted_cells<S: Copy, D, C: Convert<S, D>>(out: &mut [D], items: &[S], conv: &C, at: usize, step: isize, rest: &[Cow<'_, Steps>]) -> bool {
1395 fn cells<const L: usize, S: Copy, D, C: Convert<S, D>>(out: &mut [D], items: &[S], conv: &C, at: usize, step: isize, cell: &Cell) {
1396 let width = cell.width();
1397 let m = items.len() / width;
1398 cell.check(at, step, m, out.len());
1399 let (from, to) = (items.as_ptr(), out.as_mut_ptr());
1400 cell.each_way::<L>(at, step, m, |item, at, rev| {
1401 let (mut run, out) = unsafe { (from.add(item).cast::<[S; L]>().read(), &mut *to.add(at).cast::<[D; L]>()) };
1403 if rev { run.reverse() }
1404 for i in 0..L { out[i] = conv.one(run[i]) }
1405 });
1406 }
1407 let Some(cell) = short_cells(rest, false) else { return false };
1408 runs!(cell.len, L => cells::<L, S, D, C>(out, items, conv, at, step, &cell));
1409 true
1410}
1411
1412#[inline]
1414pub fn walk<S: Item, D>(out: &mut Vec<D>, s: &[S], base: usize, steps: &[Steps], fill: S, conv: impl Convert<S, D>) {
1415 let n = Steps::count(steps);
1416 let (base, steps) = Steps::simplify(base, steps);
1417 walked(out, &conv, n, |d, from, m| if m == n { walk_into(d, s, fill, base, &steps) } else { range_into(d, s, fill, base, &steps, from, m) })
1418}
1419
1420#[inline]
1422pub(crate) fn walk_plan<S: Item, D>(out: &mut Vec<D>, s: &[S], base: usize, plan: &[Cow<Steps>], fill: S, from: usize, n: usize, conv: impl Convert<S, D>) {
1423 walked(out, &conv, n, |d, at, m| match Steps::run(base, plan, from + at, m) {
1424 Some((start, step)) => walk_axis(d, s, fill, 0, &Steps::Stride { start, len: m, step }, &[]), None => range_into(d, s, fill, base, plan, from + at, m)
1425 })
1426}
1427
1428const SPLIT: usize = 1 << 16;
1430
1431fn walked<S: Item, D, C: Convert<S, D>>(out: &mut Vec<D>, conv: &C, n: usize, walk: impl Fn(&mut Vec<S>, usize, usize) + Sync) {
1433 use crate::slice::CHUNK;
1434 match conv.same(out) {
1435 Some(out) if n >= SPLIT && !crate::parallel::serial() => {
1436 crate::parallel::extended(out, n, CHUNK, &|range, slots| {
1437 let mut block = Vec::with_capacity(CHUNK);
1438 for from in range.clone().step_by(CHUNK) {
1439 block.clear();
1440 walk(&mut block, from, CHUNK.min(range.end - from));
1441 slots.copy(&block);
1442 }
1443 true
1444 });
1445 }
1446 Some(out) => { out.reserve(n); walk(out, 0, n) }
1447 None => {
1448 out.reserve(n);
1449 let mut block = Vec::with_capacity(n.min(CHUNK));
1450 for from in (0..n).step_by(CHUNK) {
1451 block.clear();
1452 walk(&mut block, from, CHUNK.min(n - from));
1453 conv.slice(out, &block);
1454 }
1455 }
1456 }
1457}
1458
1459fn range_into<T: Item>(d: &mut Vec<T>, s: &[T], fill: T, base: usize, steps: &[Cow<Steps>], from: usize, n: usize) {
1461 if n == 0 { return; }
1462 let Some((axis, rest)) = steps.split_first() else { return d.push(s[base]) };
1463 let width = Steps::count(rest);
1464 let row = |d: &mut Vec<T>, j: usize, at: usize, m: usize| match axis.get(j) {
1465 Some(o) => range_into(d, s, fill, base + o, rest, at, m), None => d.extend(std::iter::repeat_n(fill, m))
1466 };
1467 let (mut j, at, mut left) = (from / width, from % width, n);
1468 if at > 0 {
1469 let m = left.min(width - at);
1470 row(d, j, at, m);
1471 (j, left) = (j + 1, left - m);
1472 }
1473 let whole = left / width;
1474 for piece in axis.pieces(j, whole) {
1475 let (base, first, rest) = Steps::boxed(base, piece, rest);
1476 walk_axis(d, s, fill, base, &first, rest);
1477 }
1478 if left > whole * width { row(d, j + whole, 0, left - whole * width) }
1479}
1480
1481const RUN: usize = 8;
1483const CELL: usize = 64;
1485
1486fn short_cells(rest: &[Cow<Steps>], fills: bool) -> Option<Cell> {
1488 let width = Steps::count(rest);
1489 let (len, rev) = match rest.last().map(|t| &**t) {
1490 Some(&Steps::Stride { len, step: 1, .. }) => (len, false), Some(&Steps::Stride { len, step: -1, .. }) => (len, true), _ => (1, false)
1491 };
1492 if rest.is_empty() || !(1..=CELL).contains(&width) { return None; }
1493 let (mut starts, runs, mut gaps) = ([0; CELL], width / len, 0u64);
1494 for (i, start) in starts[..runs].iter_mut().enumerate() {
1496 match Steps::reach(0, rest, i * len) { Some(o) => *start = o - if rev { len - 1 } else { 0 }, None => gaps |= 1 << i }
1497 }
1498 if gaps != 0 {
1499 let first = (!gaps).trailing_zeros() as usize;
1501 if !fills || first >= runs { return None; }
1502 for j in (0..runs).filter(|j| gaps >> j & 1 == 1) { starts[j] = starts[first] }
1503 }
1504 Some(Cell { starts, runs, len, rev, fills: gaps })
1505}
1506
1507fn walk_into<T: Item>(d: &mut Vec<T>, s: &[T], fill: T, base: usize, steps: &[Cow<Steps>]) {
1509 match steps.split_first() { Some((axis, rest)) => walk_axis(d, s, fill, base, axis, rest), None => d.push(s[base]) }
1510}
1511
1512fn walk_axis<T: Item>(d: &mut Vec<T>, s: &[T], fill: T, base: usize, axis: &Steps, rest: &[Cow<Steps>]) {
1514 if let [inner] = rest {
1515 if let Some((start, m, n, stride)) = Steps::transposing(axis, inner) { return transposed(d, &s[base + start..], m, n, stride); }
1516 if let (Steps::Table(t), &Steps::Stride { start: b, len: n, step }) = (axis, &**inner) {
1518 if step > 1 { t.chunks(|_, run| picked(&mut *d, s, base + b, fill, run, n, step as usize)); return; }
1519 }
1520 if let Steps::Stride { start: b, len: n, step: 1 } = **inner {
1522 if n > RUN {
1523 d.reserve(axis.len() * n);
1524 axis.for_each(|_, o| match o { Some(o) => d.extend_from_slice(&s[base + b + o..][..n]), None => d.extend(std::iter::repeat_n(fill, n)) });
1525 return;
1526 }
1527 }
1528 }
1529 if let Some(cell) = short_cells(rest, true) {
1531 let (width, start) = (cell.width(), d.len());
1532 if let Steps::Stride { start: a, len: m, step } = *axis {
1533 runs!(cell.len, L => unsafe { crate::slice::appended(d, m * width, |slots| windows::<L, T::Unit>(written_as(slots), units(s), base + a, step, &cell)) });
1535 } else if !axis.fills() {
1536 runs!(cell.len, L => unsafe { crate::slice::appended(d, axis.len() * width, |slots| cells_at::<L, T::Unit>(written_as(slots), units(s), base, axis, &cell)) });
1538 } else {
1539 d.resize(start + axis.len() * width, fill);
1540 runs!(cell.len, L => cells_at::<L, T::Unit>(unsafe { written_as(&mut d[start..]) }, units(s), base, axis, &cell));
1541 }
1542 cell.filled(&mut d[start..], fill);
1543 return;
1544 }
1545 if !rest.is_empty() {
1546 let width = Steps::count(rest);
1547 axis.for_each(|_, o| match o { Some(o) => walk_into(d, s, fill, base + o, rest), None => d.extend(std::iter::repeat_n(fill, width)) });
1548 return;
1549 }
1550 if axis.len() == 0 { return; }
1551 let s = s.get(base..).unwrap_or_default();
1553 match *axis {
1554 Steps::Stride { start, len, step: 1 } => d.extend_from_slice(&s[start..start + len]),
1555 Steps::Stride { start, len, step: -1 } => d.extend(s[start + 1 - len..=start].iter().rev().copied()),
1556 Steps::Stride { start, len, step: 0 } => d.extend(std::iter::repeat_n(s[start], len)),
1557 Steps::Stride { start, len, step } => {
1558 checked_run(start, len, step, s.len());
1559 unsafe {
1560 crate::slice::appended(d, len, |slots| {
1561 let item = std::convert::identity(
1562 #[inline(always)]
1563 |i: usize, slot: &mut MaybeUninit<T>| {
1564 slot.write(*s.get_unchecked(start.wrapping_add_signed(step * i as isize)));
1566 },
1567 );
1568 let (blocks, tail) = slots.as_chunks_mut::<4>();
1570 for (i, block) in blocks.iter_mut().enumerate() { for (j, slot) in block.iter_mut().enumerate() { item(i * 4 + j, slot); } }
1571 for (j, slot) in tail.iter_mut().enumerate() { item(blocks.len() * 4 + j, slot); }
1572 })
1573 };
1574 }
1575 Steps::Rotated { shift, len, stride } => {
1576 walk_axis(d, s, fill, 0, &Steps::Stride { start: shift * stride, len: len - shift, step: stride as isize }, &[]);
1577 walk_axis(d, s, fill, 0, &Steps::Stride { start: 0, len: shift, step: stride as isize }, &[]);
1578 }
1579 Steps::Padded { start, len, size, stride, edge } => {
1580 let (before, lo, middle) = padded_parts(start, len, size);
1581 let border = |d: &mut Vec<T>, from: i128, n: usize| match edge {
1583 Edge::Fill => d.extend(std::iter::repeat_n(fill, n)),
1584 Edge::Wrap if size > 0 && stride == 1 => cycled(d, &s[..size], from.rem_euclid(size as i128) as usize, n),
1585 _ => d.extend((0..n).map(|j| edged(edge, from + j as i128, size).map_or(fill, |q| s[q * stride]))),
1586 };
1587 border(d, start, before);
1588 walk_axis(d, s, fill, 0, &Steps::Stride { start: lo * stride, len: middle, step: stride as isize }, &[]);
1589 border(d, start + (before + middle) as i128, len - before - middle);
1590 }
1591 Steps::Table(ref t) => {
1592 if !t.take_into(d, s) {
1593 unsafe {
1594 crate::slice::appended(d, t.len(), |slots| {
1595 t.chunks(|j0, run| {
1596 for (slot, &o) in slots[j0..].iter_mut().zip(run) { slot.write(s.get(o).copied().unwrap_or(fill)); }
1597 })
1598 })
1599 }
1600 }
1601 }
1602 }
1603}
1604
1605fn transposed<T: Copy>(d: &mut Vec<T>, s: &[T], m: usize, n: usize, stride: usize) {
1607 for i0 in (0..m).step_by(8) {
1608 let rows = 8.min(m - i0);
1609 unsafe { crate::slice::appended(d, rows * n, |slots| crate::linalg::transpose_into(&s[i0..], stride, slots, n, [n, rows], MaybeUninit::new)) };
1610 }
1611}
1612
1613fn picked<T: Copy>(d: &mut Vec<T>, s: &[T], base: usize, fill: T, starts: &[usize], n: usize, stride: usize) {
1615 for block in starts.chunks(8) {
1616 let at = d.len();
1617 d.resize(at + block.len() * n, fill);
1618 let out = &mut d[at..];
1619 for j in 0..n {
1620 for (k, &start) in block.iter().enumerate() { if start != Steps::FILL { out[k * n + j] = s[base + start + j * stride]; } }
1621 }
1622 }
1623}
1624
1625fn placed<T: Copy>(out: &mut [T], items: &[T], base: usize, starts: &[usize], n: usize, stride: usize, k: usize) {
1627 for (b, block) in starts.chunks(8).enumerate() {
1628 let k = k + b * 8 * n;
1629 for j in 0..n {
1630 for (c, &start) in block.iter().enumerate() { if start != Steps::FILL { out[base + start + j * stride] = nth(items, k + c * n + j); } }
1631 }
1632 }
1633}
1634
1635fn checked_run(start: usize, len: usize, step: isize, n: usize) {
1637 let end = start.checked_add_signed(step.checked_mul((len - 1) as isize).expect("stride fits")).expect("run stays in range");
1638 assert!(start < n && end < n, "run stays in range");
1639}