Skip to main content

strided_kernel/
static_indexing_plan.rs

1//! Prepared static-indexing plans over raw strided value layouts.
2//!
3//! This module owns reusable static indexing traversal for downstream tensor
4//! runtimes. It keeps allocation, dtype policy, and tensor-level validation out
5//! of `strided-kernel`; callers provide already-owned output buffers and fixed
6//! raw descriptors.
7
8use core::mem::MaybeUninit;
9
10use crate::{CopyPlan, MaybeSendSync, RawStridedMut, RawStridedRef, Result, StridedError};
11
12#[cfg(feature = "parallel")]
13type AxisVec<T> = smallvec::SmallVec<[T; crate::RAW_FUSED_RANK_LIMIT]>;
14#[cfg(not(feature = "parallel"))]
15type AxisVec<T> = Vec<T>;
16
17/// A compiled static-slice traversal.
18///
19/// `compile` validates the fixed `starts`/`limits`/`slice_strides` contract and
20/// lowers replay to a strided copy from the corresponding source view.
21#[derive(Clone, Debug)]
22pub struct SlicePlan {
23    operand_dims: AxisVec<usize>,
24    operand_strides: AxisVec<isize>,
25    dest_dims: AxisVec<usize>,
26    dest_strides: AxisVec<isize>,
27    source_strides: AxisVec<isize>,
28    source_offset_delta: isize,
29    copy_plan: CopyPlan,
30}
31
32/// A compiled reverse traversal over selected axes.
33///
34/// Replay is a strided copy from a negative-stride source view.
35#[derive(Clone, Debug)]
36pub struct ReversePlan {
37    operand_dims: AxisVec<usize>,
38    operand_strides: AxisVec<isize>,
39    dest_strides: AxisVec<isize>,
40    source_strides: AxisVec<isize>,
41    source_offset_delta: isize,
42    copy_plan: CopyPlan,
43}
44
45/// A compiled pad traversal.
46///
47/// Replay first fills every destination element with the caller-provided fill
48/// scalar, then copies reachable input positions into the padded output.
49#[derive(Clone, Debug)]
50pub struct PadPlan {
51    operand_dims: AxisVec<usize>,
52    operand_strides: AxisVec<isize>,
53    dest_dims: AxisVec<usize>,
54    dest_strides: AxisVec<isize>,
55    edge_padding_low: AxisVec<i64>,
56    interior_step: AxisVec<i64>,
57    operand_total: usize,
58    dest_total: usize,
59    contiguous_dest_fill: bool,
60    contiguous_axis0_run: Option<ContiguousPadAxis0Run>,
61}
62
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64struct ContiguousPadAxis0Run {
65    operand_start: usize,
66    dest_start: usize,
67    len: usize,
68}
69
70/// A compiled multi-input concatenate traversal.
71///
72/// Each input segment is lowered to a prepared strided copy into the
73/// corresponding destination window.
74#[derive(Clone, Debug)]
75pub struct ConcatenatePlan {
76    input_dims: Vec<AxisVec<usize>>,
77    input_strides: Vec<AxisVec<isize>>,
78    dest_dims: AxisVec<usize>,
79    dest_strides: AxisVec<isize>,
80    dest_offset_deltas: Vec<isize>,
81    copy_plans: Vec<CopyPlan>,
82}
83
84impl SlicePlan {
85    /// Compile a static slice plan for one operand layout and destination layout.
86    #[allow(clippy::too_many_arguments)]
87    pub fn compile(
88        operand_dims: &[usize],
89        operand_strides: &[isize],
90        dest_dims: &[usize],
91        dest_strides: &[isize],
92        starts: &[usize],
93        limits: &[usize],
94        slice_strides: &[usize],
95    ) -> Result<Self> {
96        let rank = operand_dims.len();
97        if operand_strides.len() != rank || dest_dims.len() != rank || dest_strides.len() != rank {
98            return Err(StridedError::StrideLengthMismatch);
99        }
100        if starts.len() != rank {
101            return Err(StridedError::RankMismatch(starts.len(), rank));
102        }
103        if limits.len() != rank {
104            return Err(StridedError::RankMismatch(limits.len(), rank));
105        }
106        if slice_strides.len() != rank {
107            return Err(StridedError::RankMismatch(slice_strides.len(), rank));
108        }
109        checked_total_len(operand_dims)?;
110        checked_total_len(dest_dims)?;
111
112        let mut expected_dest_dims: AxisVec<usize> = AxisVec::with_capacity(rank);
113        let mut source_strides: AxisVec<isize> = AxisVec::with_capacity(rank);
114        let mut source_offset_delta = 0isize;
115        for axis in 0..rank {
116            let start = starts[axis];
117            let limit = limits[axis];
118            let stride = slice_strides[axis];
119            if start > limit || limit > operand_dims[axis] || stride == 0 {
120                return Err(StridedError::InvalidAxis { axis, rank });
121            }
122            let span = limit - start;
123            expected_dest_dims.push(span.div_ceil(stride));
124            source_strides.push(checked_stride_mul(operand_strides[axis], stride)?);
125            source_offset_delta =
126                checked_offset_add(source_offset_delta, operand_strides[axis], start)?;
127        }
128        if dest_dims != &expected_dest_dims[..] {
129            return Err(StridedError::ShapeMismatch(
130                dest_dims.to_vec(),
131                expected_dest_dims.to_vec(),
132            ));
133        }
134        let copy_plan = CopyPlan::compile(dest_dims, dest_strides, &source_strides)?;
135
136        Ok(Self {
137            operand_dims: operand_dims.into(),
138            operand_strides: operand_strides.into(),
139            dest_dims: dest_dims.into(),
140            dest_strides: dest_strides.into(),
141            source_strides,
142            source_offset_delta,
143            copy_plan,
144        })
145    }
146
147    /// Execute the prepared static slice traversal.
148    pub fn execute<T>(
149        &self,
150        dest: &mut RawStridedMut<'_, T>,
151        operand: &RawStridedRef<'_, T>,
152    ) -> Result<()>
153    where
154        T: Copy + MaybeSendSync,
155    {
156        self.check_call(dest, operand)?;
157        let source_offset = operand
158            .offset()
159            .checked_add(self.source_offset_delta)
160            .ok_or(StridedError::OffsetOverflow)?;
161        let source = unsafe {
162            RawStridedRef::new_unchecked(
163                operand.data(),
164                &self.dest_dims,
165                &self.source_strides,
166                source_offset,
167            )
168        };
169        self.copy_plan.execute(dest, &source)
170    }
171
172    /// Execute into storage whose reachable destination elements are uninitialized.
173    pub fn execute_uninit<T>(
174        &self,
175        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
176        operand: &RawStridedRef<'_, T>,
177    ) -> Result<()>
178    where
179        T: Copy + MaybeSendSync,
180    {
181        self.check_call(dest, operand)?;
182        let source_offset = operand
183            .offset()
184            .checked_add(self.source_offset_delta)
185            .ok_or(StridedError::OffsetOverflow)?;
186        let source = unsafe {
187            RawStridedRef::new_unchecked(
188                operand.data(),
189                &self.dest_dims,
190                &self.source_strides,
191                source_offset,
192            )
193        };
194        self.copy_plan.execute_uninit(dest, &source)
195    }
196
197    fn check_call<D, T>(
198        &self,
199        dest: &RawStridedMut<'_, D>,
200        operand: &RawStridedRef<'_, T>,
201    ) -> Result<()> {
202        if operand.dims() != &self.operand_dims[..]
203            || operand.strides() != &self.operand_strides[..]
204            || dest.dims() != &self.dest_dims[..]
205            || dest.strides() != &self.dest_strides[..]
206        {
207            return Err(StridedError::PlanLayoutMismatch);
208        }
209        Ok(())
210    }
211}
212
213impl PadPlan {
214    /// Compile a pad plan for one operand layout and destination layout.
215    #[allow(clippy::too_many_arguments)]
216    pub fn compile(
217        operand_dims: &[usize],
218        operand_strides: &[isize],
219        dest_dims: &[usize],
220        dest_strides: &[isize],
221        edge_padding_low: &[i64],
222        edge_padding_high: &[i64],
223        interior_padding: &[i64],
224    ) -> Result<Self> {
225        let rank = operand_dims.len();
226        if operand_strides.len() != rank || dest_dims.len() != rank || dest_strides.len() != rank {
227            return Err(StridedError::StrideLengthMismatch);
228        }
229        if edge_padding_low.len() != rank {
230            return Err(StridedError::RankMismatch(edge_padding_low.len(), rank));
231        }
232        if edge_padding_high.len() != rank {
233            return Err(StridedError::RankMismatch(edge_padding_high.len(), rank));
234        }
235        if interior_padding.len() != rank {
236            return Err(StridedError::RankMismatch(interior_padding.len(), rank));
237        }
238
239        let operand_total = checked_total_len(operand_dims)?;
240        let dest_total = checked_total_len(dest_dims)?;
241        if !crate::fused::is_injective_layout(dest_dims, dest_strides) {
242            return Err(StridedError::NonInjectiveOutputLayout);
243        }
244
245        let mut expected_dest_dims: AxisVec<usize> = AxisVec::with_capacity(rank);
246        let mut interior_step: AxisVec<i64> = AxisVec::with_capacity(rank);
247        for axis in 0..rank {
248            if interior_padding[axis] < 0 {
249                return Err(StridedError::InvalidAxis { axis, rank });
250            }
251            let step = interior_padding[axis]
252                .checked_add(1)
253                .ok_or(StridedError::OffsetOverflow)?;
254            interior_step.push(step);
255            expected_dest_dims.push(checked_pad_output_dim(
256                operand_dims[axis],
257                edge_padding_low[axis],
258                edge_padding_high[axis],
259                step,
260                axis,
261                rank,
262            )?);
263        }
264        if dest_dims != &expected_dest_dims[..] {
265            return Err(StridedError::ShapeMismatch(
266                dest_dims.to_vec(),
267                expected_dest_dims.to_vec(),
268            ));
269        }
270        let contiguous_dest_fill = is_dense_col_major(dest_dims, dest_strides);
271        let contiguous_axis0_run = compile_contiguous_pad_axis0_run(
272            operand_dims,
273            operand_strides,
274            dest_dims,
275            dest_strides,
276            edge_padding_low,
277            &interior_step,
278        );
279
280        Ok(Self {
281            operand_dims: operand_dims.into(),
282            operand_strides: operand_strides.into(),
283            dest_dims: dest_dims.into(),
284            dest_strides: dest_strides.into(),
285            edge_padding_low: edge_padding_low.into(),
286            interior_step,
287            operand_total,
288            dest_total,
289            contiguous_dest_fill,
290            contiguous_axis0_run,
291        })
292    }
293
294    /// Execute the prepared pad traversal.
295    pub fn execute<T>(
296        &self,
297        dest: &mut RawStridedMut<'_, T>,
298        operand: &RawStridedRef<'_, T>,
299        fill: T,
300    ) -> Result<()>
301    where
302        T: Copy + MaybeSendSync,
303    {
304        self.check_call(dest, operand)?;
305        self.fill_dest(dest, fill)?;
306
307        if self.operand_total == 0 {
308            return Ok(());
309        }
310        if let Some(run) = self.contiguous_axis0_run {
311            return self.copy_operand_axis0_runs(dest, operand, run);
312        }
313        self.copy_operand(dest, operand)
314    }
315
316    /// Execute pad into storage whose reachable destination elements are uninitialized.
317    pub fn execute_uninit<T>(
318        &self,
319        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
320        operand: &RawStridedRef<'_, T>,
321        fill: T,
322    ) -> Result<()>
323    where
324        T: Copy + MaybeSendSync,
325    {
326        self.check_call(dest, operand)?;
327        self.fill_dest(dest, MaybeUninit::new(fill))?;
328
329        if self.operand_total == 0 {
330            return Ok(());
331        }
332        if let Some(run) = self.contiguous_axis0_run {
333            return self.copy_operand_axis0_runs_uninit(dest, operand, run);
334        }
335        self.copy_operand_uninit(dest, operand)
336    }
337
338    fn fill_dest<T>(&self, dest: &mut RawStridedMut<'_, T>, fill: T) -> Result<()>
339    where
340        T: Copy + MaybeSendSync,
341    {
342        if self.dest_total == 0 {
343            return Ok(());
344        }
345        if self.contiguous_dest_fill {
346            let dest_offset =
347                usize::try_from(dest.offset()).map_err(|_| StridedError::OffsetOverflow)?;
348            let dest_end = dest_offset
349                .checked_add(self.dest_total)
350                .ok_or(StridedError::OffsetOverflow)?;
351            let dest_data = dest.data_mut();
352            let dest_slice = dest_data
353                .get_mut(dest_offset..dest_end)
354                .ok_or(StridedError::OffsetOverflow)?;
355            dest_slice.fill(fill);
356            return Ok(());
357        }
358        #[cfg(feature = "parallel")]
359        {
360            let nthreads = crate::threading::parallel_threads_for_len(self.dest_total);
361            if nthreads > 1 {
362                return self.fill_dest_parallel(dest, fill, nthreads);
363            }
364        }
365        self.fill_dest_serial(dest, fill)
366    }
367
368    fn copy_operand_axis0_runs<T>(
369        &self,
370        dest: &mut RawStridedMut<'_, T>,
371        operand: &RawStridedRef<'_, T>,
372        run: ContiguousPadAxis0Run,
373    ) -> Result<()>
374    where
375        T: Copy,
376    {
377        if run.len == 0 {
378            return Ok(());
379        }
380        let outer_dims = &self.operand_dims[1..];
381        let outer_total = checked_total_len(outer_dims)?;
382        let mut outer_idx_storage = CoordScratch::new(outer_dims.len());
383        let outer_idx = outer_idx_storage.as_mut_slice();
384        let operand_ptr = operand.data().as_ptr();
385        let dest_ptr = dest.data_mut().as_mut_ptr();
386
387        for _ in 0..outer_total {
388            let mut operand_offset =
389                checked_offset_add(operand.offset(), self.operand_strides[0], run.operand_start)?;
390            let mut dest_offset =
391                checked_offset_add(dest.offset(), self.dest_strides[0], run.dest_start)?;
392            let mut in_bounds = true;
393            for (outer_axis, &coord) in outer_idx.iter().enumerate() {
394                let axis = outer_axis + 1;
395                let out_pos = i128::from(self.edge_padding_low[axis])
396                    + coord as i128 * i128::from(self.interior_step[axis]);
397                if out_pos < 0 || out_pos >= self.dest_dims[axis] as i128 {
398                    in_bounds = false;
399                    break;
400                }
401                operand_offset =
402                    checked_offset_add(operand_offset, self.operand_strides[axis], coord)?;
403                dest_offset =
404                    checked_offset_add(dest_offset, self.dest_strides[axis], out_pos as usize)?;
405            }
406            if in_bounds {
407                unsafe {
408                    // SAFETY: compile requires unit axis-0 strides, the clipped
409                    // run is in bounds, and the destination layout is injective.
410                    // RawStridedMut's exclusive borrow cannot overlap the
411                    // RawStridedRef's shared borrow in safe Rust.
412                    core::ptr::copy_nonoverlapping(
413                        operand_ptr.offset(operand_offset),
414                        dest_ptr.offset(dest_offset),
415                        run.len,
416                    );
417                }
418            }
419            advance_col_major_index(outer_idx, outer_dims);
420        }
421        Ok(())
422    }
423
424    fn copy_operand_axis0_runs_uninit<T>(
425        &self,
426        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
427        operand: &RawStridedRef<'_, T>,
428        run: ContiguousPadAxis0Run,
429    ) -> Result<()>
430    where
431        T: Copy,
432    {
433        if run.len == 0 {
434            return Ok(());
435        }
436        let outer_dims = &self.operand_dims[1..];
437        let outer_total = checked_total_len(outer_dims)?;
438        let mut outer_idx_storage = CoordScratch::new(outer_dims.len());
439        let outer_idx = outer_idx_storage.as_mut_slice();
440        let operand_ptr = operand.data().as_ptr();
441        let dest_ptr = dest.data_mut().as_mut_ptr();
442
443        for _ in 0..outer_total {
444            let mut operand_offset =
445                checked_offset_add(operand.offset(), self.operand_strides[0], run.operand_start)?;
446            let mut dest_offset =
447                checked_offset_add(dest.offset(), self.dest_strides[0], run.dest_start)?;
448            let mut in_bounds = true;
449            for (outer_axis, &coord) in outer_idx.iter().enumerate() {
450                let axis = outer_axis + 1;
451                let out_pos = i128::from(self.edge_padding_low[axis])
452                    + coord as i128 * i128::from(self.interior_step[axis]);
453                if out_pos < 0 || out_pos >= self.dest_dims[axis] as i128 {
454                    in_bounds = false;
455                    break;
456                }
457                operand_offset =
458                    checked_offset_add(operand_offset, self.operand_strides[axis], coord)?;
459                dest_offset =
460                    checked_offset_add(dest_offset, self.dest_strides[axis], out_pos as usize)?;
461            }
462            if in_bounds {
463                unsafe {
464                    core::ptr::copy_nonoverlapping(
465                        operand_ptr.offset(operand_offset),
466                        dest_ptr.offset(dest_offset).cast::<T>(),
467                        run.len,
468                    );
469                }
470            }
471            advance_col_major_index(outer_idx, outer_dims);
472        }
473        Ok(())
474    }
475
476    #[cfg(test)]
477    fn contiguous_axis0_run(&self) -> Option<(usize, usize, usize)> {
478        self.contiguous_axis0_run
479            .map(|run| (run.operand_start, run.dest_start, run.len))
480    }
481
482    #[cfg(test)]
483    fn has_contiguous_dest_fill(&self) -> bool {
484        self.contiguous_dest_fill
485    }
486
487    fn fill_dest_serial<T>(&self, dest: &mut RawStridedMut<'_, T>, fill: T) -> Result<()>
488    where
489        T: Copy,
490    {
491        let dest_offset_base = dest.offset();
492        let dest_strides = dest.strides();
493        let dest_data = dest.data_mut();
494        let mut dest_idx_storage = CoordScratch::new(self.dest_dims.len());
495        let dest_idx = dest_idx_storage.as_mut_slice();
496        for _ in 0..self.dest_total {
497            let dest_offset = checked_strided_offset(dest_offset_base, dest_strides, dest_idx)?;
498            unsafe {
499                *dest_data.as_mut_ptr().offset(dest_offset) = fill;
500            }
501            advance_col_major_index(dest_idx, &self.dest_dims);
502        }
503        Ok(())
504    }
505
506    #[cfg(feature = "parallel")]
507    fn fill_dest_parallel<T>(
508        &self,
509        dest: &mut RawStridedMut<'_, T>,
510        fill: T,
511        nthreads: usize,
512    ) -> Result<()>
513    where
514        T: Copy + MaybeSendSync,
515    {
516        let dest_offset_base = dest.offset();
517        let dest_ptr = crate::threading::SendPtr(dest.data_mut().as_mut_ptr());
518        crate::threading::parallel_map_reduce(
519            0..self.dest_total,
520            nthreads,
521            &|range| {
522                let mut dest_idx_storage = CoordScratch::new(self.dest_dims.len());
523                let dest_idx = dest_idx_storage.as_mut_slice();
524                fill_col_major_index(range.start, &self.dest_dims, dest_idx);
525                let dest_ptr = dest_ptr.as_ptr();
526                for _ in range {
527                    let dest_offset =
528                        checked_strided_offset(dest_offset_base, &self.dest_strides, dest_idx)?;
529                    unsafe {
530                        // SAFETY: `compile` rejected non-injective destination
531                        // layouts, and each logical destination index is visited
532                        // by exactly one range partition.
533                        *dest_ptr.offset(dest_offset) = fill;
534                    }
535                    advance_col_major_index(dest_idx, &self.dest_dims);
536                }
537                Ok(())
538            },
539            &|left, right| left.and(right),
540        )
541    }
542
543    fn copy_operand<T>(
544        &self,
545        dest: &mut RawStridedMut<'_, T>,
546        operand: &RawStridedRef<'_, T>,
547    ) -> Result<()>
548    where
549        T: Copy + MaybeSendSync,
550    {
551        #[cfg(feature = "parallel")]
552        {
553            let nthreads = crate::threading::parallel_threads_for_len(self.operand_total);
554            if nthreads > 1 {
555                return self.copy_operand_parallel(dest, operand, nthreads);
556            }
557        }
558        self.copy_operand_serial(dest, operand)
559    }
560
561    fn copy_operand_uninit<T>(
562        &self,
563        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
564        operand: &RawStridedRef<'_, T>,
565    ) -> Result<()>
566    where
567        T: Copy + MaybeSendSync,
568    {
569        #[cfg(feature = "parallel")]
570        {
571            let nthreads = crate::threading::parallel_threads_for_len(self.operand_total);
572            if nthreads > 1 {
573                return self.copy_operand_uninit_parallel(dest, operand, nthreads);
574            }
575        }
576        self.copy_operand_uninit_serial(dest, operand)
577    }
578
579    fn copy_operand_uninit_serial<T>(
580        &self,
581        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
582        operand: &RawStridedRef<'_, T>,
583    ) -> Result<()>
584    where
585        T: Copy,
586    {
587        let operand_offset_base = operand.offset();
588        let operand_strides = operand.strides();
589        let operand_data = operand.data();
590        let dest_offset_base = dest.offset();
591        let dest_strides = dest.strides();
592        let dest_data = dest.data_mut();
593        let mut input_idx_storage = CoordScratch::new(self.operand_dims.len());
594        let mut out_idx_storage = CoordScratch::new(self.dest_dims.len());
595        let input_idx = input_idx_storage.as_mut_slice();
596        let out_idx = out_idx_storage.as_mut_slice();
597
598        for _ in 0..self.operand_total {
599            let mut in_bounds = true;
600            for axis in 0..self.operand_dims.len() {
601                let out_pos = i128::from(self.edge_padding_low[axis])
602                    + input_idx[axis] as i128 * i128::from(self.interior_step[axis]);
603                if out_pos < 0 || out_pos >= self.dest_dims[axis] as i128 {
604                    in_bounds = false;
605                    break;
606                }
607                out_idx[axis] = out_pos as usize;
608            }
609            if in_bounds {
610                let operand_offset =
611                    checked_strided_offset(operand_offset_base, operand_strides, input_idx)?;
612                let dest_offset = checked_strided_offset(dest_offset_base, dest_strides, out_idx)?;
613                unsafe {
614                    (*dest_data.as_mut_ptr().offset(dest_offset))
615                        .write(*operand_data.as_ptr().offset(operand_offset));
616                }
617            }
618            advance_col_major_index(input_idx, &self.operand_dims);
619        }
620        Ok(())
621    }
622
623    #[cfg(feature = "parallel")]
624    fn copy_operand_uninit_parallel<T>(
625        &self,
626        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
627        operand: &RawStridedRef<'_, T>,
628        nthreads: usize,
629    ) -> Result<()>
630    where
631        T: Copy + MaybeSendSync,
632    {
633        let operand_offset_base = operand.offset();
634        let operand_ptr = crate::threading::SendPtr(operand.data().as_ptr() as *mut T);
635        let dest_offset_base = dest.offset();
636        let dest_ptr = crate::threading::SendPtr(dest.data_mut().as_mut_ptr());
637        crate::threading::parallel_map_reduce(
638            0..self.operand_total,
639            nthreads,
640            &|range| {
641                let mut input_idx_storage = CoordScratch::new(self.operand_dims.len());
642                let mut out_idx_storage = CoordScratch::new(self.dest_dims.len());
643                let input_idx = input_idx_storage.as_mut_slice();
644                let out_idx = out_idx_storage.as_mut_slice();
645                fill_col_major_index(range.start, &self.operand_dims, input_idx);
646                let operand_ptr = operand_ptr.as_const();
647                let dest_ptr = dest_ptr.as_ptr();
648
649                for _ in range {
650                    let mut in_bounds = true;
651                    for axis in 0..self.operand_dims.len() {
652                        let out_pos = i128::from(self.edge_padding_low[axis])
653                            + input_idx[axis] as i128 * i128::from(self.interior_step[axis]);
654                        if out_pos < 0 || out_pos >= self.dest_dims[axis] as i128 {
655                            in_bounds = false;
656                            break;
657                        }
658                        out_idx[axis] = out_pos as usize;
659                    }
660                    if in_bounds {
661                        let operand_offset = checked_strided_offset(
662                            operand_offset_base,
663                            &self.operand_strides,
664                            input_idx,
665                        )?;
666                        let dest_offset =
667                            checked_strided_offset(dest_offset_base, &self.dest_strides, out_idx)?;
668                        unsafe {
669                            (*dest_ptr.offset(dest_offset))
670                                .write(*operand_ptr.offset(operand_offset));
671                        }
672                    }
673                    advance_col_major_index(input_idx, &self.operand_dims);
674                }
675                Ok(())
676            },
677            &|left, right| left.and(right),
678        )
679    }
680
681    fn copy_operand_serial<T>(
682        &self,
683        dest: &mut RawStridedMut<'_, T>,
684        operand: &RawStridedRef<'_, T>,
685    ) -> Result<()>
686    where
687        T: Copy,
688    {
689        let operand_offset_base = operand.offset();
690        let operand_strides = operand.strides();
691        let operand_data = operand.data();
692        let dest_offset_base = dest.offset();
693        let dest_strides = dest.strides();
694        let dest_data = dest.data_mut();
695        let mut input_idx_storage = CoordScratch::new(self.operand_dims.len());
696        let mut out_idx_storage = CoordScratch::new(self.dest_dims.len());
697        let input_idx = input_idx_storage.as_mut_slice();
698        let out_idx = out_idx_storage.as_mut_slice();
699
700        for _ in 0..self.operand_total {
701            let mut in_bounds = true;
702            for axis in 0..self.operand_dims.len() {
703                let out_pos = i128::from(self.edge_padding_low[axis])
704                    + input_idx[axis] as i128 * i128::from(self.interior_step[axis]);
705                if out_pos < 0 || out_pos >= self.dest_dims[axis] as i128 {
706                    in_bounds = false;
707                    break;
708                }
709                out_idx[axis] = out_pos as usize;
710            }
711            if in_bounds {
712                let operand_offset =
713                    checked_strided_offset(operand_offset_base, operand_strides, input_idx)?;
714                let dest_offset = checked_strided_offset(dest_offset_base, dest_strides, out_idx)?;
715                unsafe {
716                    *dest_data.as_mut_ptr().offset(dest_offset) =
717                        *operand_data.as_ptr().offset(operand_offset);
718                }
719            }
720            advance_col_major_index(input_idx, &self.operand_dims);
721        }
722        Ok(())
723    }
724
725    #[cfg(feature = "parallel")]
726    fn copy_operand_parallel<T>(
727        &self,
728        dest: &mut RawStridedMut<'_, T>,
729        operand: &RawStridedRef<'_, T>,
730        nthreads: usize,
731    ) -> Result<()>
732    where
733        T: Copy + MaybeSendSync,
734    {
735        let operand_offset_base = operand.offset();
736        let operand_ptr = crate::threading::SendPtr(operand.data().as_ptr() as *mut T);
737        let dest_offset_base = dest.offset();
738        let dest_ptr = crate::threading::SendPtr(dest.data_mut().as_mut_ptr());
739        crate::threading::parallel_map_reduce(
740            0..self.operand_total,
741            nthreads,
742            &|range| {
743                let mut input_idx_storage = CoordScratch::new(self.operand_dims.len());
744                let mut out_idx_storage = CoordScratch::new(self.dest_dims.len());
745                let input_idx = input_idx_storage.as_mut_slice();
746                let out_idx = out_idx_storage.as_mut_slice();
747                fill_col_major_index(range.start, &self.operand_dims, input_idx);
748                let operand_ptr = operand_ptr.as_const();
749                let dest_ptr = dest_ptr.as_ptr();
750
751                for _ in range {
752                    let mut in_bounds = true;
753                    for axis in 0..self.operand_dims.len() {
754                        let out_pos = i128::from(self.edge_padding_low[axis])
755                            + input_idx[axis] as i128 * i128::from(self.interior_step[axis]);
756                        if out_pos < 0 || out_pos >= self.dest_dims[axis] as i128 {
757                            in_bounds = false;
758                            break;
759                        }
760                        out_idx[axis] = out_pos as usize;
761                    }
762                    if in_bounds {
763                        let operand_offset = checked_strided_offset(
764                            operand_offset_base,
765                            &self.operand_strides,
766                            input_idx,
767                        )?;
768                        let dest_offset =
769                            checked_strided_offset(dest_offset_base, &self.dest_strides, out_idx)?;
770                        unsafe {
771                            // SAFETY: positive interior steps make the
772                            // input-to-output mapping injective for in-bounds
773                            // positions; the destination layout is also
774                            // injective.
775                            *dest_ptr.offset(dest_offset) = *operand_ptr.offset(operand_offset);
776                        }
777                    }
778                    advance_col_major_index(input_idx, &self.operand_dims);
779                }
780                Ok(())
781            },
782            &|left, right| left.and(right),
783        )
784    }
785
786    fn check_call<D, T>(
787        &self,
788        dest: &RawStridedMut<'_, D>,
789        operand: &RawStridedRef<'_, T>,
790    ) -> Result<()> {
791        if operand.dims() != &self.operand_dims[..]
792            || operand.strides() != &self.operand_strides[..]
793            || dest.dims() != &self.dest_dims[..]
794            || dest.strides() != &self.dest_strides[..]
795        {
796            return Err(StridedError::PlanLayoutMismatch);
797        }
798        Ok(())
799    }
800}
801
802impl ConcatenatePlan {
803    /// Compile a multi-input concatenate plan for fixed input and destination layouts.
804    pub fn compile(
805        input_dims: &[&[usize]],
806        input_strides: &[&[isize]],
807        dest_dims: &[usize],
808        dest_strides: &[isize],
809        axis: usize,
810    ) -> Result<Self> {
811        if input_dims.is_empty() {
812            return Err(StridedError::UnsupportedArity {
813                arity: 0,
814                max: usize::MAX,
815            });
816        }
817        if input_dims.len() != input_strides.len() {
818            return Err(StridedError::RankMismatch(
819                input_strides.len(),
820                input_dims.len(),
821            ));
822        }
823
824        let rank = input_dims[0].len();
825        if dest_dims.len() != rank || dest_strides.len() != rank {
826            return Err(StridedError::StrideLengthMismatch);
827        }
828        if axis >= rank {
829            return Err(StridedError::InvalidAxis { axis, rank });
830        }
831        checked_total_len(dest_dims)?;
832        if !crate::fused::is_injective_layout(dest_dims, dest_strides) {
833            return Err(StridedError::NonInjectiveOutputLayout);
834        }
835
836        let mut expected_dest_dims: AxisVec<usize> = input_dims[0].into();
837        expected_dest_dims[axis] = 0;
838        let mut stored_input_dims = Vec::with_capacity(input_dims.len());
839        let mut stored_input_strides = Vec::with_capacity(input_dims.len());
840        let mut dest_offset_deltas = Vec::with_capacity(input_dims.len());
841        let mut copy_plans = Vec::with_capacity(input_dims.len());
842        let mut axis_base = 0usize;
843
844        for (dims, strides) in input_dims.iter().zip(input_strides.iter()) {
845            if dims.len() != rank {
846                return Err(StridedError::RankMismatch(dims.len(), rank));
847            }
848            if strides.len() != rank {
849                return Err(StridedError::StrideLengthMismatch);
850            }
851            checked_total_len(dims)?;
852            for dim in 0..rank {
853                if dim == axis {
854                    expected_dest_dims[axis] = expected_dest_dims[axis]
855                        .checked_add(dims[axis])
856                        .ok_or(StridedError::OffsetOverflow)?;
857                } else if dims[dim] != input_dims[0][dim] {
858                    return Err(StridedError::ShapeMismatch(
859                        dims.to_vec(),
860                        input_dims[0].to_vec(),
861                    ));
862                }
863            }
864            dest_offset_deltas.push(checked_offset_add(0, dest_strides[axis], axis_base)?);
865            axis_base = axis_base
866                .checked_add(dims[axis])
867                .ok_or(StridedError::OffsetOverflow)?;
868            copy_plans.push(CopyPlan::compile(dims, dest_strides, strides)?);
869            stored_input_dims.push((*dims).into());
870            stored_input_strides.push((*strides).into());
871        }
872
873        if dest_dims != &expected_dest_dims[..] {
874            return Err(StridedError::ShapeMismatch(
875                dest_dims.to_vec(),
876                expected_dest_dims.to_vec(),
877            ));
878        }
879
880        Ok(Self {
881            input_dims: stored_input_dims,
882            input_strides: stored_input_strides,
883            dest_dims: dest_dims.into(),
884            dest_strides: dest_strides.into(),
885            dest_offset_deltas,
886            copy_plans,
887        })
888    }
889
890    /// Execute the prepared concatenate traversal.
891    pub fn execute<T>(
892        &self,
893        dest: &mut RawStridedMut<'_, T>,
894        inputs: &[RawStridedRef<'_, T>],
895    ) -> Result<()>
896    where
897        T: Copy + MaybeSendSync,
898    {
899        self.check_dest_layout(dest)?;
900        if inputs.len() != self.input_dims.len() {
901            return Err(StridedError::RankMismatch(
902                inputs.len(),
903                self.input_dims.len(),
904            ));
905        }
906        for (position, input) in inputs.iter().enumerate() {
907            self.check_input_layout(position, input)?;
908            self.segment_offset(position, dest.offset())?;
909        }
910        for (position, input) in inputs.iter().enumerate() {
911            self.execute_segment(position, dest, input)?;
912        }
913        Ok(())
914    }
915
916    /// Execute concatenate into storage whose reachable destination elements are uninitialized.
917    pub fn execute_uninit<T>(
918        &self,
919        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
920        inputs: &[RawStridedRef<'_, T>],
921    ) -> Result<()>
922    where
923        T: Copy + MaybeSendSync,
924    {
925        self.check_dest_layout(dest)?;
926        if inputs.len() != self.input_dims.len() {
927            return Err(StridedError::RankMismatch(
928                inputs.len(),
929                self.input_dims.len(),
930            ));
931        }
932        for (position, input) in inputs.iter().enumerate() {
933            self.check_input_layout(position, input)?;
934            self.segment_offset(position, dest.offset())?;
935        }
936        for (position, input) in inputs.iter().enumerate() {
937            self.execute_segment_uninit(position, dest, input)?;
938        }
939        Ok(())
940    }
941
942    pub(crate) fn check_dest_layout<T>(&self, dest: &RawStridedMut<'_, T>) -> Result<()> {
943        if dest.dims() != &self.dest_dims[..] || dest.strides() != &self.dest_strides[..] {
944            return Err(StridedError::PlanLayoutMismatch);
945        }
946        Ok(())
947    }
948
949    pub(crate) fn check_input_layout<T>(
950        &self,
951        position: usize,
952        input: &RawStridedRef<'_, T>,
953    ) -> Result<()> {
954        if position >= self.input_dims.len()
955            || input.dims() != &self.input_dims[position][..]
956            || input.strides() != &self.input_strides[position][..]
957        {
958            return Err(StridedError::PlanLayoutMismatch);
959        }
960        Ok(())
961    }
962
963    pub(crate) fn input_count(&self) -> usize {
964        self.input_dims.len()
965    }
966
967    pub(crate) fn segment_offset(&self, position: usize, dest_offset: isize) -> Result<isize> {
968        dest_offset
969            .checked_add(self.dest_offset_deltas[position])
970            .ok_or(StridedError::OffsetOverflow)
971    }
972
973    pub(crate) fn execute_segment<T>(
974        &self,
975        position: usize,
976        dest: &mut RawStridedMut<'_, T>,
977        input: &RawStridedRef<'_, T>,
978    ) -> Result<()>
979    where
980        T: Copy + MaybeSendSync,
981    {
982        let segment_offset = self.segment_offset(position, dest.offset())?;
983        let dest_data = dest.data_mut();
984        let mut segment = unsafe {
985            RawStridedMut::new_unchecked(
986                dest_data,
987                &self.input_dims[position],
988                &self.dest_strides,
989                segment_offset,
990            )
991        };
992        self.copy_plans[position].execute(&mut segment, input)
993    }
994
995    pub(crate) fn execute_segment_uninit<T>(
996        &self,
997        position: usize,
998        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
999        input: &RawStridedRef<'_, T>,
1000    ) -> Result<()>
1001    where
1002        T: Copy + MaybeSendSync,
1003    {
1004        let segment_offset = self.segment_offset(position, dest.offset())?;
1005        let dest_data = dest.data_mut();
1006        let mut segment = unsafe {
1007            RawStridedMut::new_unchecked(
1008                dest_data,
1009                &self.input_dims[position],
1010                &self.dest_strides,
1011                segment_offset,
1012            )
1013        };
1014        self.copy_plans[position].execute_uninit(&mut segment, input)
1015    }
1016}
1017
1018impl ReversePlan {
1019    /// Compile a reverse plan for one operand layout, destination layout, and axis set.
1020    pub fn compile(
1021        operand_dims: &[usize],
1022        operand_strides: &[isize],
1023        dest_strides: &[isize],
1024        axes: &[usize],
1025    ) -> Result<Self> {
1026        let rank = operand_dims.len();
1027        if operand_strides.len() != rank || dest_strides.len() != rank {
1028            return Err(StridedError::StrideLengthMismatch);
1029        }
1030        checked_total_len(operand_dims)?;
1031
1032        let mut reverse_axis: AxisVec<bool> = (0..rank).map(|_| false).collect();
1033        for &axis in axes {
1034            if axis >= rank {
1035                return Err(StridedError::InvalidAxis { axis, rank });
1036            }
1037            reverse_axis[axis] = true;
1038        }
1039
1040        let mut source_strides: AxisVec<isize> = AxisVec::with_capacity(rank);
1041        let mut source_offset_delta = 0isize;
1042        for axis in 0..rank {
1043            if reverse_axis[axis] {
1044                source_strides.push(
1045                    operand_strides[axis]
1046                        .checked_neg()
1047                        .ok_or(StridedError::OffsetOverflow)?,
1048                );
1049                if operand_dims[axis] > 0 {
1050                    source_offset_delta = checked_offset_add(
1051                        source_offset_delta,
1052                        operand_strides[axis],
1053                        operand_dims[axis] - 1,
1054                    )?;
1055                }
1056            } else {
1057                source_strides.push(operand_strides[axis]);
1058            }
1059        }
1060        let copy_plan = CopyPlan::compile(operand_dims, dest_strides, &source_strides)?;
1061
1062        Ok(Self {
1063            operand_dims: operand_dims.into(),
1064            operand_strides: operand_strides.into(),
1065            dest_strides: dest_strides.into(),
1066            source_strides,
1067            source_offset_delta,
1068            copy_plan,
1069        })
1070    }
1071
1072    /// Execute the prepared reverse traversal.
1073    pub fn execute<T>(
1074        &self,
1075        dest: &mut RawStridedMut<'_, T>,
1076        operand: &RawStridedRef<'_, T>,
1077    ) -> Result<()>
1078    where
1079        T: Copy + MaybeSendSync,
1080    {
1081        self.check_call(dest, operand)?;
1082        let source_offset = operand
1083            .offset()
1084            .checked_add(self.source_offset_delta)
1085            .ok_or(StridedError::OffsetOverflow)?;
1086        let source = unsafe {
1087            RawStridedRef::new_unchecked(
1088                operand.data(),
1089                &self.operand_dims,
1090                &self.source_strides,
1091                source_offset,
1092            )
1093        };
1094        self.copy_plan.execute(dest, &source)
1095    }
1096
1097    /// Execute reverse into storage whose reachable destination elements are uninitialized.
1098    pub fn execute_uninit<T>(
1099        &self,
1100        dest: &mut RawStridedMut<'_, MaybeUninit<T>>,
1101        operand: &RawStridedRef<'_, T>,
1102    ) -> Result<()>
1103    where
1104        T: Copy + MaybeSendSync,
1105    {
1106        self.check_call(dest, operand)?;
1107        let source_offset = operand
1108            .offset()
1109            .checked_add(self.source_offset_delta)
1110            .ok_or(StridedError::OffsetOverflow)?;
1111        let source = unsafe {
1112            RawStridedRef::new_unchecked(
1113                operand.data(),
1114                &self.operand_dims,
1115                &self.source_strides,
1116                source_offset,
1117            )
1118        };
1119        self.copy_plan.execute_uninit(dest, &source)
1120    }
1121
1122    fn check_call<D, T>(
1123        &self,
1124        dest: &RawStridedMut<'_, D>,
1125        operand: &RawStridedRef<'_, T>,
1126    ) -> Result<()> {
1127        if operand.dims() != &self.operand_dims[..]
1128            || operand.strides() != &self.operand_strides[..]
1129            || dest.dims() != &self.operand_dims[..]
1130            || dest.strides() != &self.dest_strides[..]
1131        {
1132            return Err(StridedError::PlanLayoutMismatch);
1133        }
1134        Ok(())
1135    }
1136}
1137
1138fn checked_total_len(dims: &[usize]) -> Result<usize> {
1139    if dims.is_empty() {
1140        return Ok(1);
1141    }
1142    dims.iter()
1143        .try_fold(1usize, |acc, &dim| acc.checked_mul(dim))
1144        .ok_or(StridedError::OffsetOverflow)
1145}
1146
1147fn checked_stride_mul(stride: isize, factor: usize) -> Result<isize> {
1148    let factor = isize::try_from(factor).map_err(|_| StridedError::OffsetOverflow)?;
1149    stride
1150        .checked_mul(factor)
1151        .ok_or(StridedError::OffsetOverflow)
1152}
1153
1154fn checked_pad_output_dim(
1155    input_extent: usize,
1156    edge_low: i64,
1157    edge_high: i64,
1158    interior_step: i64,
1159    axis: usize,
1160    rank: usize,
1161) -> Result<usize> {
1162    let base = if input_extent == 0 {
1163        0i128
1164    } else {
1165        (input_extent as i128 - 1)
1166            .checked_mul(i128::from(interior_step))
1167            .and_then(|value| value.checked_add(1))
1168            .ok_or(StridedError::OffsetOverflow)?
1169    };
1170    let dim = i128::from(edge_low)
1171        .checked_add(i128::from(edge_high))
1172        .and_then(|value| value.checked_add(base))
1173        .ok_or(StridedError::OffsetOverflow)?;
1174    usize::try_from(dim).map_err(|_| StridedError::InvalidAxis { axis, rank })
1175}
1176
1177fn is_dense_col_major(dims: &[usize], strides: &[isize]) -> bool {
1178    let mut expected = 1isize;
1179    for (&dim, &stride) in dims.iter().zip(strides.iter()) {
1180        if stride != expected {
1181            return false;
1182        }
1183        let Ok(dim) = isize::try_from(dim) else {
1184            return false;
1185        };
1186        let Some(next) = expected.checked_mul(dim) else {
1187            return false;
1188        };
1189        expected = next;
1190    }
1191    true
1192}
1193
1194fn compile_contiguous_pad_axis0_run(
1195    operand_dims: &[usize],
1196    operand_strides: &[isize],
1197    dest_dims: &[usize],
1198    dest_strides: &[isize],
1199    edge_padding_low: &[i64],
1200    interior_step: &[i64],
1201) -> Option<ContiguousPadAxis0Run> {
1202    if operand_dims.is_empty()
1203        || operand_strides[0] != 1
1204        || dest_strides[0] != 1
1205        || interior_step[0] != 1
1206    {
1207        return None;
1208    }
1209
1210    let operand_extent = operand_dims[0] as i128;
1211    let dest_extent = dest_dims[0] as i128;
1212    let edge_low = i128::from(edge_padding_low[0]);
1213    let operand_start = (-edge_low).clamp(0, operand_extent);
1214    let dest_start = edge_low.clamp(0, dest_extent);
1215    let len = (operand_extent - operand_start).min(dest_extent - dest_start);
1216    Some(ContiguousPadAxis0Run {
1217        operand_start: usize::try_from(operand_start).ok()?,
1218        dest_start: usize::try_from(dest_start).ok()?,
1219        len: usize::try_from(len).ok()?,
1220    })
1221}
1222
1223fn checked_strided_offset(base: isize, strides: &[isize], index: &[usize]) -> Result<isize> {
1224    let mut offset = base;
1225    for (&stride, &coord) in strides.iter().zip(index.iter()) {
1226        offset = checked_offset_add(offset, stride, coord)?;
1227    }
1228    Ok(offset)
1229}
1230
1231fn checked_offset_add(base: isize, stride: isize, coord: usize) -> Result<isize> {
1232    let coord = isize::try_from(coord).map_err(|_| StridedError::OffsetOverflow)?;
1233    let scaled = stride
1234        .checked_mul(coord)
1235        .ok_or(StridedError::OffsetOverflow)?;
1236    base.checked_add(scaled).ok_or(StridedError::OffsetOverflow)
1237}
1238
1239fn advance_col_major_index(index: &mut [usize], shape: &[usize]) {
1240    for axis in 0..index.len() {
1241        index[axis] += 1;
1242        if index[axis] < shape[axis] {
1243            return;
1244        }
1245        index[axis] = 0;
1246    }
1247}
1248
1249#[cfg(feature = "parallel")]
1250fn fill_col_major_index(mut linear: usize, shape: &[usize], out: &mut [usize]) {
1251    for (axis, coord) in out.iter_mut().enumerate() {
1252        let dim = shape[axis];
1253        *coord = linear % dim;
1254        linear /= dim;
1255    }
1256}
1257
1258struct CoordScratch {
1259    inline: [usize; crate::RAW_FUSED_RANK_LIMIT],
1260    heap: Option<Vec<usize>>,
1261    len: usize,
1262}
1263
1264impl CoordScratch {
1265    fn new(len: usize) -> Self {
1266        if len <= crate::RAW_FUSED_RANK_LIMIT {
1267            Self {
1268                inline: [0; crate::RAW_FUSED_RANK_LIMIT],
1269                heap: None,
1270                len,
1271            }
1272        } else {
1273            Self {
1274                inline: [0; crate::RAW_FUSED_RANK_LIMIT],
1275                heap: Some(vec![0; len]),
1276                len,
1277            }
1278        }
1279    }
1280
1281    fn as_mut_slice(&mut self) -> &mut [usize] {
1282        match &mut self.heap {
1283            Some(heap) => heap,
1284            None => &mut self.inline[..self.len],
1285        }
1286    }
1287}
1288
1289#[cfg(test)]
1290mod tests {
1291    use core::fmt::Debug;
1292
1293    use num_complex::{Complex32, Complex64};
1294
1295    use super::{PadPlan, RawStridedMut, RawStridedRef};
1296
1297    fn assert_contiguous_pad_matches_scalar<T>(operand_data: &[T], fill: T)
1298    where
1299        T: Copy + Debug + PartialEq + super::MaybeSendSync,
1300    {
1301        let operand_dims = [3usize, 2];
1302        let operand_strides = [1isize, -3];
1303        let operand_offset = 3isize;
1304        let dest_dims = [4usize, 4];
1305        let dest_strides = [1isize, 4];
1306        let dest_offset = 2isize;
1307        let edge_low = [-1i64, 1];
1308        let edge_high = [2i64, 0];
1309        let interior = [0i64, 1];
1310        let plan = PadPlan::compile(
1311            &operand_dims,
1312            &operand_strides,
1313            &dest_dims,
1314            &dest_strides,
1315            &edge_low,
1316            &edge_high,
1317            &interior,
1318        )
1319        .unwrap();
1320        assert!(plan.contiguous_axis0_run.is_some());
1321
1322        let mut scalar_plan = plan.clone();
1323        scalar_plan.contiguous_dest_fill = false;
1324        scalar_plan.contiguous_axis0_run = None;
1325        let mut fast_dest = vec![fill; 20];
1326        let mut scalar_dest = fast_dest.clone();
1327        let operand = RawStridedRef::new(
1328            operand_data,
1329            &operand_dims,
1330            &operand_strides,
1331            operand_offset,
1332        )
1333        .unwrap();
1334        {
1335            let mut dest =
1336                RawStridedMut::new(&mut fast_dest, &dest_dims, &dest_strides, dest_offset).unwrap();
1337            plan.execute(&mut dest, &operand, fill).unwrap();
1338        }
1339        {
1340            let mut dest =
1341                RawStridedMut::new(&mut scalar_dest, &dest_dims, &dest_strides, dest_offset)
1342                    .unwrap();
1343            scalar_plan.execute(&mut dest, &operand, fill).unwrap();
1344        }
1345        assert_eq!(fast_dest, scalar_dest);
1346    }
1347
1348    #[test]
1349    fn pad_plan_selects_contiguous_axis0_run_for_dense_edge_padding() {
1350        let plan =
1351            PadPlan::compile(&[2_097_152], &[1], &[2_097_408], &[1], &[128], &[128], &[0]).unwrap();
1352
1353        assert_eq!(plan.contiguous_axis0_run(), Some((0, 128, 2_097_152)));
1354        assert!(plan.has_contiguous_dest_fill());
1355    }
1356
1357    #[test]
1358    fn contiguous_pad_matches_scalar_for_every_erased_scalar_type() {
1359        assert_contiguous_pad_matches_scalar(&[1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0], -1.0);
1360        assert_contiguous_pad_matches_scalar(&[1.0f64, 2.0, 3.0, 4.0, 5.0, 6.0], -1.0);
1361        assert_contiguous_pad_matches_scalar(&[1i32, 2, 3, 4, 5, 6], -1);
1362        assert_contiguous_pad_matches_scalar(&[1i64, 2, 3, 4, 5, 6], -1);
1363        assert_contiguous_pad_matches_scalar(&[true, false, true, false, true, false], false);
1364        assert_contiguous_pad_matches_scalar(
1365            &[
1366                Complex32::new(1.0, -1.0),
1367                Complex32::new(2.0, -2.0),
1368                Complex32::new(3.0, -3.0),
1369                Complex32::new(4.0, -4.0),
1370                Complex32::new(5.0, -5.0),
1371                Complex32::new(6.0, -6.0),
1372            ],
1373            Complex32::new(-1.0, 0.0),
1374        );
1375        assert_contiguous_pad_matches_scalar(
1376            &[
1377                Complex64::new(1.0, -1.0),
1378                Complex64::new(2.0, -2.0),
1379                Complex64::new(3.0, -3.0),
1380                Complex64::new(4.0, -4.0),
1381                Complex64::new(5.0, -5.0),
1382                Complex64::new(6.0, -6.0),
1383            ],
1384            Complex64::new(-1.0, 0.0),
1385        );
1386    }
1387}