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 { fn eq(&self, other: &Self) -> bool { self.len == other.len && (0..self.len).all(|j| self.get(j) == other.get(j)) } }
766impl Eq for Table {}
767
768fn index_at(view: View<'_>, j: usize, size: usize) -> usize { with_index_values!(view, |x| crate::structure::counted_back(x[j].position(), size)) }
770
771fn converted(view: View<'_>, start: usize, len: usize, size: usize, scale: usize, each: &mut dyn FnMut(usize, &[usize]) -> bool) -> bool {
773 fn runs<I: IndexValue>(values: &[I], size: usize, scale: usize, each: &mut dyn FnMut(usize, &[usize]) -> bool) -> bool {
774 let mut run = [0; TABLE_CHUNK];
775 values.chunks(TABLE_CHUNK).enumerate().all(|(c, chunk)| {
776 if scale == 1 { for (o, &i) in run.iter_mut().zip(chunk) { *o = crate::structure::counted_back(i.position(), size); } }
778 else { for (o, &i) in run.iter_mut().zip(chunk) { *o = crate::structure::counted_back(i.position(), size) * scale; } }
779 each(c * TABLE_CHUNK, &run[..chunk.len()])
780 })
781 }
782 with_index_values!(view, |x| runs(&x[start..start + len], size, scale, each))
783}
784
785impl Steps {
786 fn merged(outer: &Self, inner: &Self) -> Option<Self> {
787 let (Self::Stride { start: a, len: m, step: so }, Self::Stride { start: b, len: n, step: si }) = (outer.even()?, inner.even()?) else { return None };
788 (so == si.checked_mul(n as isize)?).then_some(Self::Stride { start: a + b, len: m * n, step: si })
789 }
790}
791
792impl Steps {
793 pub const FILL: usize = usize::MAX;
795 pub fn along(len: usize, stride: usize) -> Self { Self::Stride { start: 0, len, step: stride as isize } }
797 pub fn row_major(lens: &[usize], scale: usize, start: usize) -> impl Iterator<Item = Self> + '_ {
799 lens.iter().zip(crate::layout::strides(lens)).enumerate().map(move |(j, (&len, stride))| Self::Stride { start: if j == 0 { start } else { 0 }, len,
800 step: (scale * stride) as isize })
801 }
802 pub fn table(offsets: Vec<usize>) -> Self { Self::Table(Table::new(offsets)) }
804 pub fn scaled(self, k: usize) -> Self {
806 match self {
807 Self::Stride { start, len, step } => Self::Stride { start: start * k, len, step: step * k as isize },
808 Self::Padded { start, len, size, stride, edge } => Self::Padded { start, len, size, stride: stride * k, edge },
809 Self::Rotated { shift, len, stride } => Self::Rotated { shift, len, stride: stride * k }, Self::Table(table) => Self::Table(table.scaled(k))
810 }
811 }
812 pub fn padded(start: i128, len: usize, size: usize, stride: usize, edge: Edge) -> Self {
814 if edge != Edge::Fill && size == 1 { return Self::Stride { start: 0, len, step: 0 }; }
815 if edge == Edge::Wrap && len == size && size != 0 { return Self::rotated(start.rem_euclid(size as i128) as usize, len, stride); }
816 if start >= 0 && start + len as i128 <= size as i128 { Self::Stride { start: start as usize * stride, len, step: stride as isize } }
817 else { Self::Padded { start, len, size, stride, edge } }
818 }
819 pub fn clipped(start: i128, len: usize, size: usize, stride: usize) -> Self { Self::padded(start, len, size, stride, Edge::Fill) }
821 pub fn rotated(shift: usize, len: usize, stride: usize) -> Self {
823 if len < 2 { return Self::along(len, stride); }
824 let shift = shift % len;
825 if shift == 0 { Self::along(len, stride) } else { Self::Rotated { shift, len, stride } }
826 }
827 #[inline]
829 pub fn len(&self) -> usize {
830 match self { Self::Stride { len, .. } | Self::Padded { len, .. } | Self::Rotated { len, .. } => *len, Self::Table(t) => t.len() }
831 }
832 pub fn footprint(&self) -> usize { size_of::<Self>() + if let Self::Table(t) = self { t.bytes() } else { 0 } }
834 #[inline]
836 pub fn get(&self, j: usize) -> Option<usize> {
837 match *self {
838 Self::Stride { start, step, .. } => Some(start.wrapping_add_signed(step * j as isize)),
839 Self::Padded { start, size, stride, edge, .. } => edged(edge, start + j as i128, size).map(|p| p * stride),
840 Self::Rotated { shift, len, stride } => Some((shift + j) % len * stride), Self::Table(ref t) => t.get(j)
841 }
842 }
843 #[inline]
845 pub fn offsets(&self) -> impl ExactSizeIterator<Item = Option<usize>> + '_ { (0..self.len()).map(|j| self.get(j)) }
846 #[inline(always)]
848 pub fn for_each(&self, mut each: impl FnMut(usize, Option<usize>)) {
849 match *self {
850 Self::Stride { start, len, step } => { for r in 0..len { each(r, Some(start.wrapping_add_signed(step * r as isize))) } }
851 Self::Padded { start, len, size, stride, edge } => {
852 let (before, lo, middle) = padded_parts(start, len, size);
853 let border = |r: usize| edged(edge, start + r as i128, size).map(|p| p * stride);
854 for r in 0..before { each(r, border(r)) }
855 for r in 0..middle { each(before + r, Some((lo + r) * stride)) }
856 for r in before + middle..len { each(r, border(r)) }
857 }
858 Self::Rotated { shift, len, stride } => {
859 for r in 0..len - shift { each(r, Some((shift + r) * stride)) }
860 for r in len - shift..len { each(r, Some((r + shift - len) * stride)) }
861 }
862 Self::Table(ref t) => t.chunks(|j0, run| {
863 for (r, &o) in run.iter().enumerate() { each(j0 + r, (o != Self::FILL).then_some(o)) }
864 }),
865 }
866 }
867 fn pieces(&self, start: usize, len: usize) -> impl Iterator<Item = Cow<'_, Self>> {
869 let pieces = if len == 0 { [None, None] } else {
870 match *self {
871 Self::Stride { start: s, step, .. } => {
872 [Some(Cow::Owned(Self::Stride { start: s.wrapping_add_signed(step * start as isize), len, step })), None]
873 }
874 Self::Padded { start: s, size, stride, edge, .. } => [Some(Cow::Owned(Self::padded(s + start as i128, len, size, stride, edge))), None],
875 Self::Rotated { shift, len: n, stride } => {
876 let first = (shift + start) % n;
877 let head = len.min(n - first);
878 [
879 Some(Cow::Owned(Self::Stride { start: first * stride, len: head, step: stride as isize })),
880 (head < len).then(|| Cow::Owned(Self::Stride { start: 0, len: len - head, step: stride as isize })),
881 ]
882 }
883 Self::Table(ref t) if start == 0 && len == t.len() => [Some(Cow::Borrowed(self)), None],
884 Self::Table(ref t) => [Some(Cow::Owned(Self::Table(t.slice(start, len)))), None],
885 }
886 };
887 pieces.into_iter().flatten()
888 }
889 pub fn count(steps: &[impl std::borrow::Borrow<Self>]) -> usize { steps.iter().map(|s| s.borrow().len()).product() }
891 pub fn combined(base: usize, steps: &[impl std::borrow::Borrow<Self>]) -> Vec<usize> {
893 let mut out = Vec::with_capacity(Self::count(steps));
894 Self::reached(&mut out, base, steps, &mut |_| true);
895 out
896 }
897 fn reached<B: std::borrow::Borrow<Self>>(out: &mut Vec<usize>, base: usize, steps: &[B], flush: &mut dyn FnMut(&mut Vec<usize>) -> bool) -> bool {
899 let Some((axis, rest)) = steps.split_first() else { out.push(base); return flush(out); };
900 let axis = axis.borrow();
901 if !rest.is_empty() {
902 let mut ok = true;
903 axis.for_each(|_, o| {
904 if ok { ok = Self::reached(out, if base == Self::FILL { base } else { o.map_or(Self::FILL, |o| base + o) }, rest, flush) }
905 });
906 return ok;
907 }
908 match axis {
909 _ if base == Self::FILL => out.extend(std::iter::repeat_n(Self::FILL, axis.len())),
910 Self::Table(table) => unsafe { crate::slice::appended(out, table.len(), |slots| table.write_offsets(base, slots)) },
911 _ => {
912 let len = axis.len();
913 for r0 in (0..len).step_by(TABLE_CHUNK) {
914 let r1 = len.min(r0 + TABLE_CHUNK);
915 match *axis {
916 Self::Stride { start, step, .. } => out.extend((r0..r1).map(|r| base + start.wrapping_add_signed(step * r as isize))),
917 _ => out.extend((r0..r1).map(|r| axis.get(r).map_or(Self::FILL, |o| base + o))),
918 }
919 if r1 < len && !flush(out) { return false; }
920 }
921 }
922 }
923 flush(out)
924 }
925 pub(crate) fn simplify<B: std::borrow::Borrow<Self>>(mut base: usize, steps: &[B]) -> (usize, Vec<Cow<'_, Self>>) {
927 let mut kept: Vec<Cow<Self>> = Vec::with_capacity(steps.len());
928 for s in steps {
929 let s = s.borrow();
930 if s.len() == 1 && let Some(first) = s.get(0) { base += first; continue; }
931 kept.push(Cow::Borrowed(s));
932 while let [.., outer, inner] = kept.as_slice() {
933 let Some(merged) = Self::merged(outer, inner) else { break };
934 kept.truncate(kept.len() - 2);
935 kept.push(Cow::Owned(merged));
936 }
937 }
938 let innermost = kept.last().and_then(|s| if matches!(**s, Self::Table(_)) { s.even() } else { None });
939 if let (Some(stride), Some(last)) = (innermost, kept.last_mut()) { *last = Cow::Owned(stride); }
940 (base, kept)
941 }
942 pub(crate) fn transposing(outer: &Self, inner: &Self) -> Option<(usize, usize, usize, usize)> {
944 match (outer, inner) {
945 (&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
946 }
947 }
948 fn boxed<'a>(base: usize, piece: Cow<'a, Self>, rest: &'a [Cow<'a, Self>]) -> (usize, Cow<'a, Self>, &'a [Cow<'a, Self>]) {
950 let (base, piece, rest) = match (piece.len() == 1).then(|| piece.get(0)).flatten().zip(rest.split_first()) {
951 Some((o, (first, after))) => (base + o, first.clone(), after), None => (base, piece, rest)
952 };
953 match rest.split_first().and_then(|(inner, after)| Some((Self::merged(&piece, inner)?, after))) {
954 Some((merged, after)) => (base, Cow::Owned(merged), after),
955 None if rest.is_empty() && matches!(*piece, Self::Table(_)) => (base, piece.even().map_or(piece, Cow::Owned), rest), None => (base, piece, rest)
956 }
957 }
958 pub(crate) fn settle(strides: &mut [Self], first: usize) {
960 let mut rest = first;
961 for s in strides.iter_mut().skip(1) {
962 if let Self::Stride { start, len, step } = s {
963 *start = if *step < 0 { step.unsigned_abs() * (*len - 1) } else { 0 };
964 rest -= *start;
965 }
966 }
967 if let Some(Self::Stride { start, .. }) = strides.first_mut() { *start = rest; }
968 }
969 pub(crate) fn even(&self) -> Option<Self> {
971 match self {
972 Self::Stride { .. } => Some(self.clone()),
973 Self::Table(t) => {
974 let Some(offsets) = t.listed() else { return t.stride() };
975 let &[first, second, ..] = offsets else { return None };
976 let step = second.wrapping_sub(first) as isize;
977 (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 {
978 start: first, len: offsets.len(), step })
979 }
980 _ => None,
981 }
982 }
983 #[inline]
985 pub fn reach(base: usize, steps: &[impl std::borrow::Borrow<Self>], mut i: usize) -> Option<usize> {
986 let mut offset = base;
987 for s in steps.iter().rev() {
988 let s = s.borrow();
989 offset += s.get(i % s.len())?;
990 i /= s.len();
991 }
992 Some(offset)
993 }
994 pub fn furthest(base: usize, steps: &[impl std::borrow::Borrow<Self>]) -> Option<usize> {
996 steps.iter().try_fold(base, |at, s| {
997 let furthest = match *s.borrow() {
998 ref s if s.len() == 0 => return None, Self::Stride { start, len, step } => start.wrapping_add_signed(step.max(0) * (len - 1) as isize),
999 Self::Padded { size, stride, .. } => size.saturating_sub(1) * stride, Self::Rotated { len, stride, .. } => (len - 1) * stride,
1000 Self::Table(ref t) => (0..t.len()).filter_map(|j| t.get(j)).max().unwrap_or(0)
1001 };
1002 Some(at + furthest)
1003 })
1004 }
1005 #[inline]
1007 pub fn run(base: usize, steps: &[impl std::borrow::Borrow<Self>], start: usize, n: usize) -> Option<(usize, isize)> {
1008 if n == 0 { return None; }
1009 let (mut width, mut stride) = (1usize, None);
1010 for axis in steps.iter().rev() {
1011 let axis = axis.borrow();
1012 let len = axis.len();
1013 if len == 0 { return None; }
1014 if len == 1 { axis.get(0)?; continue; }
1015 let (i, end) = ((start / width) % len, ((start + n - 1) / width) % len);
1016 let fits = start % (width * len) + n <= width * len;
1017 let step = match *axis {
1018 Self::Stride { step, .. } => step,
1019 Self::Padded { start: s, size, stride, .. } if fits && s + i as i128 >= 0 && s + (end + 1) as i128 <= size as i128 => stride as isize,
1020 Self::Rotated { shift, stride, .. } if fits && (shift + i) % len + end - i < len => stride as isize, _ => return None
1021 };
1022 if let Some(s) = stride { if step != s * width as isize { return None; } }
1023 else { stride = Some(step); }
1024 width *= len;
1025 if fits { return Some((Self::reach(base, steps, start)?, stride.unwrap())); }
1026 }
1027 (n == 1).then(|| (Self::reach(base, steps, start).expect("singleton run has no fill"), 1))
1028 }
1029 pub fn regular(steps: &[Self]) -> (usize, isize) {
1031 let (mut width, mut stride) = (1, None);
1032 for axis in steps.iter().rev() {
1033 if axis.len() == 1 { continue; }
1034 let step = match *axis {
1035 Self::Stride { step, .. } => step, Self::Padded { stride, .. } | Self::Rotated { stride, .. } => stride as isize, Self::Table(_) => break
1036 };
1037 if stride.is_some_and(|s: isize| step != s * width as isize) { break; }
1038 stride.get_or_insert(step);
1039 width *= axis.len();
1040 }
1041 (width, stride.unwrap_or(1))
1042 }
1043 pub fn contiguous(steps: &[Self]) -> usize { match Self::regular(steps) { (width, 1) => width, _ => 1 } }
1045 pub fn skips(&self) -> bool {
1047 match *self {
1048 Self::Stride { step, .. } => step.unsigned_abs() > 1, Self::Padded { stride, .. } | Self::Rotated { stride, .. } => stride > 1,
1049 Self::Table(_) => false
1050 }
1051 }
1052 pub fn fills(&self) -> bool { match self { Self::Padded { edge, .. } => *edge == Edge::Fill, Self::Table(t) => t.fills(), _ => false } }
1054 pub fn affine(&self) -> Option<(usize, isize)> { match *self { Self::Stride { start, step, .. } => Some((start, step)), _ => None } }
1056 pub fn in_order(tables: &[Self]) -> bool {
1058 let mut stride = 1;
1059 tables.iter().rev().all(|s| match *s {
1060 Self::Stride { start: 0, len, step } => {
1061 let ordered = len <= 1 || step == stride as isize;
1062 stride *= len;
1063 ordered
1064 }
1065 Self::Table(ref t) => {
1066 let (mut j, at) = (0, stride);
1067 stride *= t.len();
1068 t.all(|o| {
1069 let ordered = o == Some(j * at);
1070 j += 1;
1071 ordered
1072 })
1073 }
1074 _ => false,
1075 })
1076 }
1077 pub fn spreads(&self) -> bool {
1079 match *self {
1080 Self::Stride { len, step, .. } => step == 0 && len > 1, Self::Padded { .. } => true, Self::Rotated { .. } => false,
1081 _ => { let mut seen = crate::hashing::HashSet::default(); !self.offsets().all(|o| o.is_some_and(|o| seen.insert(o))) }
1082 }
1083 }
1084 pub fn per_axis(tables: &[Self], shape: &[usize]) -> Option<(usize, Vec<Self>)> {
1086 let (mut base, tables) = Self::simplify(0, tables);
1087 let (mut steps, mut a) = (Vec::with_capacity(shape.len()), 0);
1088 let ones = |steps: &mut Vec<Self>, a: &mut usize| {
1089 while *a < shape.len() && shape[*a] == 1 {
1090 steps.push(Self::Stride { start: 0, len: 1, step: 0 });
1091 *a += 1;
1092 }
1093 };
1094 for t in &tables {
1095 if t.len() == 1 { base += t.get(0)?; continue; }
1096 ones(&mut steps, &mut a);
1097 let (first, mut n) = (a, 1);
1098 while a < shape.len() && n < t.len() {
1099 n *= shape[a];
1100 a += 1;
1101 }
1102 if n != t.len() { return None; }
1103 match (&shape[first..a], &**t) {
1104 ([_], _) => steps.push(t.clone().into_owned()),
1105 (group, &Self::Stride { start, step, .. }) => {
1106 let (at, mut width) = (steps.len(), n);
1107 for &len in group {
1108 width /= len;
1109 steps.push(Self::Stride { start: 0, len, step: step * width as isize });
1110 }
1111 Self::settle(&mut steps[at..], start);
1112 }
1113 _ => return None,
1114 }
1115 }
1116 ones(&mut steps, &mut a);
1117 (a == shape.len()).then_some((base, steps))
1118 }
1119 pub fn with_base(base: usize, steps: Vec<Self>) -> Vec<Self> {
1121 if base == 0 { steps } else { std::iter::once(Self::Stride { start: base, len: 1, step: 0 }).chain(steps).collect() }
1122 }
1123 fn by_axes(outer: &[Self], shape: &[usize]) -> Vec<usize> {
1125 let strides = crate::layout::strides(shape);
1126 let (_, merged) = Self::simplify(0, outer);
1127 let mut lens = Vec::with_capacity(shape.len());
1128 for e in &merged {
1129 if let Self::Stride { len, step, .. } = **e && let Some(a) = (0..shape.len()).find(|&a| shape[a] > 1 && strides[a] as isize == step)
1130 && len > shape[a] {
1131 let (mut first, mut n) = (a + 1, 1);
1132 while first > 0 && n < len {
1133 first -= 1;
1134 n *= shape[first];
1135 }
1136 if n == len { lens.extend_from_slice(&shape[first..=a]); continue; }
1137 }
1138 lens.push(e.len());
1139 }
1140 lens
1141 }
1142 pub fn through(outer: &[Self], shape: &[usize], mut base: usize, inner: &[Self]) -> Option<(usize, Vec<Self>)> {
1144 let lens: Vec<usize> = outer.iter().map(Self::len).collect();
1145 let Walk { base: at, steps: outer, along: axes, strides } =
1146 Walk::new(outer, &lens, shape).or_else(|| Walk::new(outer, &Self::by_axes(outer, shape), shape))?;
1147 let mut walks = vec![0usize; shape.len()];
1148 for &a in axes.iter().flatten() { walks[a] += 1; }
1149 if walks.iter().zip(inner).any(|(&w, r)| w > 1 && !matches!(r, Self::Stride { .. })) { return None; }
1151 let (mut first, mut taken) = (vec![None; shape.len()], vec![0; outer.len()]);
1153 for (k, &axis) in axes.iter().enumerate() {
1154 let Some(a) = axis else { continue };
1155 let f = *first[a].get_or_insert(k);
1156 let Self::Stride { start: r0, step: s, .. } = inner[a] else { continue };
1157 if f == k { taken[k] = r0; }
1158 else if let (true, &Self::Stride { start, len, step }) = (s < 0, &outer[k]) {
1159 taken[k] = s.unsigned_abs() * ((start + len.saturating_sub(1) * step.max(0) as usize) / strides[a]);
1160 taken[f] = taken[f].checked_sub(taken[k])?;
1161 }
1162 }
1163 let mut steps = Vec::with_capacity(outer.len());
1164 for (k, (e, &axis)) in outer.iter().zip(&axes).enumerate() {
1165 steps.push(match axis {
1166 None => { if e.fills() { e.clone() } else { Self::Stride { start: 0, len: e.len(), step: 0 } } }
1167 Some(a) => e.read_through(strides[a], &inner[a], first[a] == Some(k), taken[k], &mut base)?,
1168 });
1169 }
1170 for (a, p) in crate::layout::coordinates(at, shape) { if walks[a] == 0 { base += inner[a].get(p)?; } }
1171 Some((base, steps))
1172 }
1173 pub fn rereads(outer: &[Self], shape: &[usize]) -> bool {
1175 let Some(walk) = Walk::new(outer, &outer.iter().map(Self::len).collect::<Vec<_>>(), shape) else { return false };
1176 let mut walked = vec![false; shape.len()];
1177 walk.along.iter().flatten().any(|&a| std::mem::replace(&mut walked[a], true))
1178 }
1179 fn read_through(&self, unit: usize, r: &Self, first: bool, r0: usize, base: &mut usize) -> Option<Self> {
1181 if first && matches!(*self, Self::Stride { start: 0, len, step } if step == unit as isize && len == r.len()) {
1182 return Some(match *r { Self::Stride { len, step, .. } => Self::Stride { start: r0, len, step }, _ => r.clone() });
1183 }
1184 if let Self::Stride { step: s, .. } = *r {
1185 match *self {
1186 Self::Stride { start, len, step } => {
1187 let start = usize::try_from(r0 as isize + (start / unit) as isize * s).ok()?;
1188 return Some(Self::Stride { start, len, step: step / unit as isize * s });
1189 }
1190 Self::Rotated { shift, len, .. } if s >= 0 => { *base += r0; return Some(Self::rotated(shift, len, s as usize)); }
1191 Self::Padded { start, len, size, edge, .. } if s >= 0 => { *base += r0; return Some(Self::padded(start, len, size, s as usize, edge)); }
1192 _ => {}
1193 }
1194 }
1195 if first && let (&Self::Stride { start, len, step }, &Self::Padded { start: p, size, stride, edge, .. }) = (self, r) && step == unit as isize {
1197 return Some(Self::padded(p + (start / unit) as i128, len, size, stride, edge));
1198 }
1199 if first && let (&Self::Rotated { shift, len, stride }, &Self::Padded { start, len: m, size, stride: s, edge: Edge::Fill }) = (self, r)
1201 && stride == unit && len == m {
1202 let a = (-start - shift as i128).rem_euclid(len as i128);
1203 if a + size as i128 <= len as i128 { return Some(Self::padded(-a, len, size, s, Edge::Fill)); }
1204 }
1205 (first && (matches!(self, Self::Table(_)) || matches!(r, Self::Table(_)))).then(|| {
1206 let read = |p: usize| match *r { Self::Stride { step, .. } => Some(r0.wrapping_add_signed(step * p as isize)), _ => r.get(p) };
1207 let mut table = Vec::with_capacity(self.len());
1208 self.for_each(|_, o| table.push(o.and_then(|o| read(o / unit)).unwrap_or(Self::FILL)));
1209 Self::table(table)
1210 })
1211 }
1212 pub(crate) fn axis_of(&self, shape: &[usize], strides: &[usize]) -> Option<Option<usize>> {
1214 let zero = match *self {
1215 Self::Stride { start, len, step } => len == 0 || start == 0 && (step == 0 || len == 1),
1216 Self::Rotated { stride, .. } | Self::Padded { stride, .. } => stride == 0,
1217 Self::Table(ref t) => t.span().map_or_else(|| t.all(|o| o == Some(0)), |(scale, size)| scale == 0 || size <= 1),
1218 };
1219 if zero { return Some(None); }
1220 let fits = |a: usize| {
1221 let (s, n) = (strides[a], shape[a]);
1222 let at = |o: usize| o % s == 0 && o / s < n;
1223 match *self {
1224 Self::Stride { start, len, step } => step.unsigned_abs() % s == 0 && at(start) && at(start.wrapping_add_signed(step * (len as isize - 1))),
1225 Self::Rotated { stride, len, .. } => stride == s && len <= n,
1226 Self::Padded { stride, size, .. } => stride == s && size <= n,
1227 Self::Table(ref t) => {
1228 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)
1229 }
1230 }
1231 };
1232 (0..shape.len()).find(|&a| shape[a] > 1 && fits(a)).map(Some)
1233 }
1234}
1235
1236pub trait Convert<S: Copy, D> {
1238 fn one(&self, x: S) -> D;
1240 fn slice(&self, d: &mut Vec<D>, s: &[S]) {
1242 unsafe {
1243 crate::slice::appended(d, s.len(), |slots| {
1244 let slots = &mut slots[..s.len()];
1245 for i in 0..s.len() { slots[i].write(self.one(s[i])); }
1246 })
1247 }
1248 }
1249 fn all(&self, s: &[S]) -> Vec<D> {
1251 let mut d = Vec::with_capacity(s.len());
1252 self.slice(&mut d, s);
1253 d
1254 }
1255 fn same<'a>(&self, _d: &'a mut Vec<D>) -> Option<&'a mut Vec<S>> { None }
1257 fn borrowed<'a>(&self, _s: &'a [S]) -> Option<&'a [D]> { None }
1259}
1260impl<S: Copy, D, F: Fn(S) -> D> Convert<S, D> for F {
1261 #[inline]
1262 fn one(&self, x: S) -> D { self(x) }
1263}
1264pub struct Same;
1266impl<T: Copy> Convert<T, T> for Same {
1267 #[inline]
1268 fn one(&self, x: T) -> T { x }
1269 fn same<'a>(&self, d: &'a mut Vec<T>) -> Option<&'a mut Vec<T>> { Some(d) }
1270 fn borrowed<'a>(&self, s: &'a [T]) -> Option<&'a [T]> { Some(s) }
1271}
1272
1273pub unsafe trait Item: Copy + Send + Sync {
1278 type Unit: Unit;
1280 #[inline]
1282 fn cells_from<S: Item, C: Convert<S, Self>>(_out: &mut [Self], _items: &[S], _conv: &C, _at: usize, _step: isize, _rest: &[Cow<'_, Steps>]) -> bool {
1283 false
1284 }
1285 #[inline]
1287 fn cells_into_f64<C: Convert<Self, f64>>(_out: &mut [f64], _items: &[Self], _conv: &C, _at: usize, _step: isize, _rest: &[Cow<'_, Steps>]) -> bool { false }
1288}
1289pub unsafe trait Unit: Copy + Send + Sync + 'static {}
1294macro_rules! units {
1295 ($($u:ty),+; $($t:ty: $tu:ty $(=> $body:ident)?),+) => {
1296 $(unsafe impl Unit for $u {})+
1298 $(
1299 unsafe impl Item for $t { type Unit = $tu; $(units!(@$body);)? }
1301 const _: () = assert!(size_of::<$t>() == size_of::<$tu>() && align_of::<$t>() == align_of::<$tu>());
1302 )+
1303 };
1304 (@into_f64) => {
1306 #[inline]
1307 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) }
1308 };
1309 (@from) => {
1311 #[inline]
1312 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) }
1313 };
1314}
1315units!(u8, u16, u32, u64, [u32; 2], [u64; 2];
1317 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,
1318 num_complex::Complex32: [u32; 2], num_complex::Complex64: [u64; 2], char: u32);
1319
1320fn units<T: Item>(items: &[T]) -> &[T::Unit] {
1322 unsafe { std::slice::from_raw_parts(items.as_ptr().cast(), items.len()) }
1324}
1325
1326unsafe fn written_as<A, B>(items: &mut [A]) -> &mut [B] {
1331 const { assert!(size_of::<A>() == size_of::<B>() && align_of::<A>() == align_of::<B>()) };
1332 unsafe { std::slice::from_raw_parts_mut(items.as_mut_ptr().cast(), items.len()) }
1334}
1335
1336pub fn interleave<T: Item>(out: &mut Vec<T>, parts: &[(&[T], usize)], rows: usize) {
1338 assert!(parts.iter().all(|&(items, n)| items.len() == rows * n), "each part holds one lane for every row");
1339 let width = parts.iter().map(|&(_, n)| n).sum::<usize>();
1340 let parts: Vec<(&[T::Unit], usize)> = parts.iter().map(|&(items, n)| (units(items), n)).collect();
1341 unsafe {
1342 crate::slice::appended(out, rows * width, |slots| {
1343 let slots = written_as::<MaybeUninit<T>, MaybeUninit<T::Unit>>(slots);
1345 match *parts {
1346 [(a, n), (b, m)] if n == m && (1..=RUN).contains(&n) => runs!(n, L => lane_pairs::<L, T::Unit>(slots, [a, b])),
1347 _ => lane_items(slots, &parts, width),
1348 }
1349 })
1350 }
1351}
1352
1353#[inline]
1355fn lane_pairs<const L: usize, U: Unit>(slots: &mut [MaybeUninit<U>], [a, b]: [&[U]; 2]) {
1356 let (a, b, mut to) = (a.as_ptr().cast::<[U; L]>(), b.as_ptr().cast::<[U; L]>(), slots.as_mut_ptr().cast::<[U; L]>());
1357 for r in 0..slots.len() / (2 * L) {
1358 unsafe {
1360 to.write(a.add(r).read());
1361 to.add(1).write(b.add(r).read());
1362 to = to.add(2)
1363 }
1364 }
1365}
1366
1367fn lane_items<U: Unit>(slots: &mut [MaybeUninit<U>], parts: &[(&[U], usize)], width: usize) {
1369 if width == 0 { return; }
1370 for (r, row) in slots.chunks_exact_mut(width).enumerate() {
1371 let mut at = 0;
1372 for &(items, n) in parts {
1373 for (slot, &u) in row[at..at + n].iter_mut().zip(&items[r * n..][..n]) { slot.write(u); }
1374 at += n;
1375 }
1376 }
1377}
1378
1379fn converted_cells<S: Copy, D, C: Convert<S, D>>(out: &mut [D], items: &[S], conv: &C, at: usize, step: isize, rest: &[Cow<'_, Steps>]) -> bool {
1381 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) {
1382 let width = cell.width();
1383 let m = items.len() / width;
1384 cell.check(at, step, m, out.len());
1385 let (from, to) = (items.as_ptr(), out.as_mut_ptr());
1386 cell.each_way::<L>(at, step, m, |item, at, rev| {
1387 let (mut run, out) = unsafe { (from.add(item).cast::<[S; L]>().read(), &mut *to.add(at).cast::<[D; L]>()) };
1389 if rev { run.reverse() }
1390 for i in 0..L { out[i] = conv.one(run[i]) }
1391 });
1392 }
1393 let Some(cell) = short_cells(rest, false) else { return false };
1394 runs!(cell.len, L => cells::<L, S, D, C>(out, items, conv, at, step, &cell));
1395 true
1396}
1397
1398#[inline]
1400pub fn walk<S: Item, D>(out: &mut Vec<D>, s: &[S], base: usize, steps: &[Steps], fill: S, conv: impl Convert<S, D>) {
1401 let n = Steps::count(steps);
1402 let (base, steps) = Steps::simplify(base, steps);
1403 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) })
1404}
1405
1406#[inline]
1408pub(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>) {
1409 walked(out, &conv, n, |d, at, m| match Steps::run(base, plan, from + at, m) {
1410 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)
1411 })
1412}
1413
1414const SPLIT: usize = 1 << 16;
1416
1417fn 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) {
1419 use crate::slice::CHUNK;
1420 match conv.same(out) {
1421 Some(out) if n >= SPLIT && !crate::parallel::serial() => {
1422 crate::parallel::extended(out, n, CHUNK, &|range, slots| {
1423 let mut block = Vec::with_capacity(CHUNK);
1424 for from in range.clone().step_by(CHUNK) {
1425 block.clear();
1426 walk(&mut block, from, CHUNK.min(range.end - from));
1427 slots.copy(&block);
1428 }
1429 true
1430 });
1431 }
1432 Some(out) => { out.reserve(n); walk(out, 0, n) }
1433 None => {
1434 out.reserve(n);
1435 let mut block = Vec::with_capacity(n.min(CHUNK));
1436 for from in (0..n).step_by(CHUNK) {
1437 block.clear();
1438 walk(&mut block, from, CHUNK.min(n - from));
1439 conv.slice(out, &block);
1440 }
1441 }
1442 }
1443}
1444
1445fn range_into<T: Item>(d: &mut Vec<T>, s: &[T], fill: T, base: usize, steps: &[Cow<Steps>], from: usize, n: usize) {
1447 if n == 0 { return; }
1448 let Some((axis, rest)) = steps.split_first() else { return d.push(s[base]) };
1449 let width = Steps::count(rest);
1450 let row = |d: &mut Vec<T>, j: usize, at: usize, m: usize| match axis.get(j) {
1451 Some(o) => range_into(d, s, fill, base + o, rest, at, m), None => d.extend(std::iter::repeat_n(fill, m))
1452 };
1453 let (mut j, at, mut left) = (from / width, from % width, n);
1454 if at > 0 {
1455 let m = left.min(width - at);
1456 row(d, j, at, m);
1457 (j, left) = (j + 1, left - m);
1458 }
1459 let whole = left / width;
1460 for piece in axis.pieces(j, whole) {
1461 let (base, first, rest) = Steps::boxed(base, piece, rest);
1462 walk_axis(d, s, fill, base, &first, rest);
1463 }
1464 if left > whole * width { row(d, j + whole, 0, left - whole * width) }
1465}
1466
1467const RUN: usize = 8;
1469const CELL: usize = 64;
1471
1472fn short_cells(rest: &[Cow<Steps>], fills: bool) -> Option<Cell> {
1474 let width = Steps::count(rest);
1475 let (len, rev) = match rest.last().map(|t| &**t) {
1476 Some(&Steps::Stride { len, step: 1, .. }) => (len, false), Some(&Steps::Stride { len, step: -1, .. }) => (len, true), _ => (1, false)
1477 };
1478 if rest.is_empty() || !(1..=CELL).contains(&width) { return None; }
1479 let (mut starts, runs, mut gaps) = ([0; CELL], width / len, 0u64);
1480 for (i, start) in starts[..runs].iter_mut().enumerate() {
1482 match Steps::reach(0, rest, i * len) { Some(o) => *start = o - if rev { len - 1 } else { 0 }, None => gaps |= 1 << i }
1483 }
1484 if gaps != 0 {
1485 let first = (!gaps).trailing_zeros() as usize;
1487 if !fills || first >= runs { return None; }
1488 for j in (0..runs).filter(|j| gaps >> j & 1 == 1) { starts[j] = starts[first] }
1489 }
1490 Some(Cell { starts, runs, len, rev, fills: gaps })
1491}
1492
1493fn walk_into<T: Item>(d: &mut Vec<T>, s: &[T], fill: T, base: usize, steps: &[Cow<Steps>]) {
1495 match steps.split_first() { Some((axis, rest)) => walk_axis(d, s, fill, base, axis, rest), None => d.push(s[base]) }
1496}
1497
1498fn walk_axis<T: Item>(d: &mut Vec<T>, s: &[T], fill: T, base: usize, axis: &Steps, rest: &[Cow<Steps>]) {
1500 if let [inner] = rest {
1501 if let Some((start, m, n, stride)) = Steps::transposing(axis, inner) { return transposed(d, &s[base + start..], m, n, stride); }
1502 if let (Steps::Table(t), &Steps::Stride { start: b, len: n, step }) = (axis, &**inner) {
1504 if step > 1 { t.chunks(|_, run| picked(&mut *d, s, base + b, fill, run, n, step as usize)); return; }
1505 }
1506 if let Steps::Stride { start: b, len: n, step: 1 } = **inner {
1508 if n > RUN {
1509 d.reserve(axis.len() * n);
1510 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)) });
1511 return;
1512 }
1513 }
1514 }
1515 if let Some(cell) = short_cells(rest, true) {
1517 let (width, start) = (cell.width(), d.len());
1518 if let Steps::Stride { start: a, len: m, step } = *axis {
1519 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)) });
1521 } else if !axis.fills() {
1522 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)) });
1524 } else {
1525 d.resize(start + axis.len() * width, fill);
1526 runs!(cell.len, L => cells_at::<L, T::Unit>(unsafe { written_as(&mut d[start..]) }, units(s), base, axis, &cell));
1527 }
1528 cell.filled(&mut d[start..], fill);
1529 return;
1530 }
1531 if !rest.is_empty() {
1532 let width = Steps::count(rest);
1533 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)) });
1534 return;
1535 }
1536 if axis.len() == 0 { return; }
1537 let s = s.get(base..).unwrap_or_default();
1539 match *axis {
1540 Steps::Stride { start, len, step: 1 } => d.extend_from_slice(&s[start..start + len]),
1541 Steps::Stride { start, len, step: -1 } => d.extend(s[start + 1 - len..=start].iter().rev().copied()),
1542 Steps::Stride { start, len, step: 0 } => d.extend(std::iter::repeat_n(s[start], len)),
1543 Steps::Stride { start, len, step } => {
1544 checked_run(start, len, step, s.len());
1545 unsafe {
1546 crate::slice::appended(d, len, |slots| {
1547 let item = std::convert::identity(
1548 #[inline(always)]
1549 |i: usize, slot: &mut MaybeUninit<T>| {
1550 slot.write(*s.get_unchecked(start.wrapping_add_signed(step * i as isize)));
1552 },
1553 );
1554 let (blocks, tail) = slots.as_chunks_mut::<4>();
1556 for (i, block) in blocks.iter_mut().enumerate() { for (j, slot) in block.iter_mut().enumerate() { item(i * 4 + j, slot); } }
1557 for (j, slot) in tail.iter_mut().enumerate() { item(blocks.len() * 4 + j, slot); }
1558 })
1559 };
1560 }
1561 Steps::Rotated { shift, len, stride } => {
1562 walk_axis(d, s, fill, 0, &Steps::Stride { start: shift * stride, len: len - shift, step: stride as isize }, &[]);
1563 walk_axis(d, s, fill, 0, &Steps::Stride { start: 0, len: shift, step: stride as isize }, &[]);
1564 }
1565 Steps::Padded { start, len, size, stride, edge } => {
1566 let (before, lo, middle) = padded_parts(start, len, size);
1567 let border = |d: &mut Vec<T>, from: i128, n: usize| match edge {
1569 Edge::Fill => d.extend(std::iter::repeat_n(fill, n)),
1570 Edge::Wrap if size > 0 && stride == 1 => cycled(d, &s[..size], from.rem_euclid(size as i128) as usize, n),
1571 _ => d.extend((0..n).map(|j| edged(edge, from + j as i128, size).map_or(fill, |q| s[q * stride]))),
1572 };
1573 border(d, start, before);
1574 walk_axis(d, s, fill, 0, &Steps::Stride { start: lo * stride, len: middle, step: stride as isize }, &[]);
1575 border(d, start + (before + middle) as i128, len - before - middle);
1576 }
1577 Steps::Table(ref t) => {
1578 if !t.take_into(d, s) {
1579 unsafe {
1580 crate::slice::appended(d, t.len(), |slots| {
1581 t.chunks(|j0, run| {
1582 for (slot, &o) in slots[j0..].iter_mut().zip(run) { slot.write(s.get(o).copied().unwrap_or(fill)); }
1583 })
1584 })
1585 }
1586 }
1587 }
1588 }
1589}
1590
1591fn transposed<T: Copy>(d: &mut Vec<T>, s: &[T], m: usize, n: usize, stride: usize) {
1593 for i0 in (0..m).step_by(8) {
1594 let rows = 8.min(m - i0);
1595 unsafe { crate::slice::appended(d, rows * n, |slots| crate::linalg::transpose_into(&s[i0..], stride, slots, n, [n, rows], MaybeUninit::new)) };
1596 }
1597}
1598
1599fn picked<T: Copy>(d: &mut Vec<T>, s: &[T], base: usize, fill: T, starts: &[usize], n: usize, stride: usize) {
1601 for block in starts.chunks(8) {
1602 let at = d.len();
1603 d.resize(at + block.len() * n, fill);
1604 let out = &mut d[at..];
1605 for j in 0..n {
1606 for (k, &start) in block.iter().enumerate() { if start != Steps::FILL { out[k * n + j] = s[base + start + j * stride]; } }
1607 }
1608 }
1609}
1610
1611fn placed<T: Copy>(out: &mut [T], items: &[T], base: usize, starts: &[usize], n: usize, stride: usize, k: usize) {
1613 for (b, block) in starts.chunks(8).enumerate() {
1614 let k = k + b * 8 * n;
1615 for j in 0..n {
1616 for (c, &start) in block.iter().enumerate() { if start != Steps::FILL { out[base + start + j * stride] = nth(items, k + c * n + j); } }
1617 }
1618 }
1619}
1620
1621fn checked_run(start: usize, len: usize, step: isize, n: usize) {
1623 let end = start.checked_add_signed(step.checked_mul((len - 1) as isize).expect("stride fits")).expect("run stays in range");
1624 assert!(start < n && end < n, "run stays in range");
1625}