strided_basic/execution.rs
1//! Execution contract for operation-family implementations.
2//!
3//! This module is the shared kernel-extension interface, not a public mirror
4//! of implementation modules. Prevalidated entries require the caller to prove
5//! the exact destination geometry and every omitted shape check. A layout marker
6//! alone does not prove those obligations. Ordinary callers should use the
7//! checked APIs at the crate root. All families share the same execution policy.
8//!
9//! # Examples
10//!
11//! ```
12//! use strided_basic::{StridedArray, execution::*};
13//! let src = StridedArray::<f64>::col_major(&[2]);
14//! let mut dst = StridedArray::<f64>::col_major(&[2]);
15//! let marker = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
16//! // SAFETY: both arrays have shape [2], distinct storage, and the checked layout.
17//! unsafe { map_into_validated(&mut dst.view_mut(), &src.view(), |x| x, marker) }.unwrap();
18//! ```
19//!
20//! A marker alone does not make the prevalidated entry safe to call:
21//!
22//! ```compile_fail,E0133
23//! use strided_basic::{StridedArray, execution::*};
24//! let src = StridedArray::<f64>::col_major(&[2]);
25//! let mut dst = StridedArray::<f64>::col_major(&[2]);
26//! let marker = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
27//! map_into_validated(&mut dst.view_mut(), &src.view(), |x| x, marker).unwrap();
28//! ```
29pub use crate::erased_common::{
30 check_dtype, check_static_indexing_dtype, erased_view, validate_uninit_no_overlap,
31};
32#[cfg(feature = "parallel")]
33pub use crate::exec_context::with_execution_pool;
34pub use crate::kernel::{ensure_same_shape, KernelPlan, SMALL_TENSOR_THRESHOLD};
35pub use crate::layout_check::is_injective_layout;
36pub use crate::map_view::{
37 validate_destination_layout, validate_destination_layout_without_alloc,
38 ValidatedDestinationLayout,
39};
40#[cfg(feature = "parallel")]
41pub use crate::threading::{
42 parallel_map_reduce, parallel_threads_for_len, SendPtr, MINTHREADLENGTH,
43};
44
45use crate::{
46 ElementOp, InlineVec, MaybeSendSync, MaybeSync, OperandVec, Result, StridedView, StridedViewMut,
47};
48
49/// Prevalidated build plan fused for kernel-family implementations.
50///
51/// # Safety
52/// All rank-indexed arrays must have matching lengths and a valid destination
53/// index (when present). Shape products, stride magnitudes, cost arithmetic,
54/// and every intermediate offset used by planning/iteration must be representable.
55/// Iteration blocks must be positive and offsets must correspond to the supplied
56/// layouts; threaded partitioning additionally requires positive thread counts,
57/// costs and nonnegative spacing. Callback memory accesses must be valid for each generated
58/// block, with disjoint mutable regions when partitions execute concurrently.
59///
60/// # Examples
61///
62/// ```
63/// use strided_basic::execution::*;
64/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
65/// let (dims, _, plan) = unsafe { build_plan_fused(&[2, 3], &[&[1, 2]], Some(0), 8) };
66/// assert_eq!(dims.iter().product::<usize>(), 6);
67/// assert_eq!(plan.block.len(), dims.len());
68/// ```
69#[inline]
70pub unsafe fn build_plan_fused(
71 dims: &[usize],
72 strides_list: &[&[isize]],
73 dest_index: Option<usize>,
74 elem_size: usize,
75) -> (InlineVec<usize>, OperandVec<InlineVec<isize>>, KernelPlan) {
76 // SAFETY: the caller supplies the same invariants as the owning checked entry.
77 crate::kernel::build_plan_fused(dims, strides_list, dest_index, elem_size)
78}
79
80/// Prevalidated build plan fused small for kernel-family implementations.
81///
82/// # Safety
83/// All rank-indexed arrays must have matching lengths and a valid destination
84/// index (when present). Shape products, stride magnitudes, cost arithmetic,
85/// and every intermediate offset used by planning/iteration must be representable.
86/// Iteration blocks must be positive and offsets must correspond to the supplied
87/// layouts; threaded partitioning additionally requires positive thread counts,
88/// costs and nonnegative spacing. Callback memory accesses must be valid for each generated
89/// block, with disjoint mutable regions when partitions execute concurrently.
90///
91/// # Examples
92///
93/// ```
94/// use strided_basic::execution::*;
95/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
96/// let (dims, _, _) = unsafe { build_plan_fused_small(&[2, 3], &[&[1, 2]]) };
97/// assert_eq!(dims.iter().product::<usize>(), 6);
98/// ```
99#[inline]
100pub unsafe fn build_plan_fused_small(
101 dims: &[usize],
102 strides_list: &[&[isize]],
103) -> (InlineVec<usize>, OperandVec<InlineVec<isize>>, KernelPlan) {
104 // SAFETY: the caller supplies the same invariants as the owning checked entry.
105 crate::kernel::build_plan_fused_small(dims, strides_list)
106}
107
108/// Prevalidated for each inner block preordered for kernel-family implementations.
109///
110/// # Safety
111/// All rank-indexed arrays must have matching lengths and a valid destination
112/// index (when present). Shape products, stride magnitudes, cost arithmetic,
113/// and every intermediate offset used by planning/iteration must be representable.
114/// Iteration blocks must be positive and offsets must correspond to the supplied
115/// layouts; threaded partitioning additionally requires positive thread counts,
116/// costs and nonnegative spacing. Callback memory accesses must be valid for each generated
117/// block, with disjoint mutable regions when partitions execute concurrently.
118///
119/// # Examples
120///
121/// ```
122/// use strided_basic::execution::*;
123/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
124/// let mut count = 0;
125/// unsafe { for_each_inner_block_preordered(&[4], &[4], &[vec![1]], &[0], |_, n, _| { count += n; Ok(()) }) }.unwrap();
126/// assert_eq!(count, 4);
127/// ```
128///
129/// # Errors
130/// Forwards errors from the owning kernel or callback; callers must still
131/// satisfy the safety contract before invoking this prevalidated entry.
132#[inline]
133pub unsafe fn for_each_inner_block_preordered<S: AsRef<[isize]>, F>(
134 dims: &[usize],
135 blocks: &[usize],
136 strides: &[S],
137 initial_offsets: &[isize],
138 f: F,
139) -> Result<()>
140where
141 F: FnMut(&[isize], usize, &[isize]) -> Result<()>,
142{
143 // SAFETY: the caller supplies the same invariants as the owning checked entry.
144 crate::kernel::for_each_inner_block_preordered::<S, F>(
145 dims,
146 blocks,
147 strides,
148 initial_offsets,
149 f,
150 )
151}
152
153/// Prevalidated map into validated for kernel-family implementations.
154///
155/// # Safety
156/// All input shapes must match the destination. `validated` must have been
157/// obtained for this destination's current geometry, proving injectivity;
158/// possessing a marker from another layout is not sufficient. View/descriptor
159/// bounds and aliasing contracts must continue to hold throughout replay.
160///
161/// # Examples
162///
163/// ```
164/// use strided_basic::execution::*;
165/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
166/// use strided_basic::StridedArray;
167/// let src = StridedArray::<f64>::from_parts(vec![2.0; 2], &[2], &[1], 0).unwrap();
168/// let mut dst = StridedArray::<f64>::col_major(&[2]);
169/// let checked = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
170/// unsafe { map_into_validated(&mut dst.view_mut(), &src.view(), |a| a, checked) }.unwrap();
171/// assert_eq!(dst.get(&[1]), 2.0);
172/// ```
173///
174/// # Errors
175/// Forwards errors from the owning kernel or callback; callers must still
176/// satisfy the safety contract before invoking this prevalidated entry.
177#[inline]
178pub unsafe fn map_into_validated<
179 D: Copy + MaybeSendSync,
180 A: Copy + MaybeSendSync,
181 Op: ElementOp<A>,
182>(
183 dest: &mut StridedViewMut<D>,
184 src: &StridedView<A, Op>,
185 f: impl Fn(A) -> D + MaybeSync,
186 validated: ValidatedDestinationLayout,
187) -> Result<()> {
188 // SAFETY: the caller supplies the same invariants as the owning checked entry.
189 crate::map_view::map_into_validated::<D, A, Op>(dest, src, f, validated)
190}
191
192/// Prevalidated zip map2 into validated for kernel-family implementations.
193///
194/// # Safety
195/// All input shapes must match the destination. `validated` must have been
196/// obtained for this destination's current geometry, proving injectivity;
197/// possessing a marker from another layout is not sufficient. View/descriptor
198/// bounds and aliasing contracts must continue to hold throughout replay.
199///
200/// # Examples
201///
202/// ```
203/// use strided_basic::execution::*;
204/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
205/// use strided_basic::StridedArray;
206/// let src = StridedArray::<f64>::from_parts(vec![2.0; 2], &[2], &[1], 0).unwrap();
207/// let mut dst = StridedArray::<f64>::col_major(&[2]);
208/// let checked = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
209/// unsafe { zip_map2_into_validated(&mut dst.view_mut(), &src.view(), &src.view(), |a, b| a + b, checked) }.unwrap();
210/// assert_eq!(dst.get(&[1]), 4.0);
211/// ```
212///
213/// # Errors
214/// Forwards errors from the owning kernel or callback; callers must still
215/// satisfy the safety contract before invoking this prevalidated entry.
216#[inline]
217pub unsafe fn zip_map2_into_validated<
218 D: Copy + MaybeSendSync,
219 A: Copy + MaybeSendSync,
220 B: Copy + MaybeSendSync,
221 OpA: ElementOp<A>,
222 OpB: ElementOp<B>,
223>(
224 dest: &mut StridedViewMut<D>,
225 a: &StridedView<A, OpA>,
226 b: &StridedView<B, OpB>,
227 f: impl Fn(A, B) -> D + MaybeSync,
228 validated: ValidatedDestinationLayout,
229) -> Result<()> {
230 // SAFETY: the caller supplies the same invariants as the owning checked entry.
231 crate::map_view::zip_map2_into_validated::<D, A, B, OpA, OpB>(dest, a, b, f, validated)
232}
233
234/// Prevalidated zip map3 into validated for kernel-family implementations.
235///
236/// # Safety
237/// All input shapes must match the destination. `validated` must have been
238/// obtained for this destination's current geometry, proving injectivity;
239/// possessing a marker from another layout is not sufficient. View/descriptor
240/// bounds and aliasing contracts must continue to hold throughout replay.
241///
242/// # Examples
243///
244/// ```
245/// use strided_basic::execution::*;
246/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
247/// use strided_basic::StridedArray;
248/// let src = StridedArray::<f64>::from_parts(vec![2.0; 2], &[2], &[1], 0).unwrap();
249/// let mut dst = StridedArray::<f64>::col_major(&[2]);
250/// let checked = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
251/// unsafe { zip_map3_into_validated(&mut dst.view_mut(), &src.view(), &src.view(), &src.view(), |a, b, c| a + b + c, checked) }.unwrap();
252/// assert_eq!(dst.get(&[1]), 6.0);
253/// ```
254///
255/// # Errors
256/// Forwards errors from the owning kernel or callback; callers must still
257/// satisfy the safety contract before invoking this prevalidated entry.
258#[inline]
259pub unsafe fn zip_map3_into_validated<
260 D: Copy + MaybeSendSync,
261 A: Copy + MaybeSendSync,
262 B: Copy + MaybeSendSync,
263 C: Copy + MaybeSendSync,
264 OpA: ElementOp<A>,
265 OpB: ElementOp<B>,
266 OpC: ElementOp<C>,
267>(
268 dest: &mut StridedViewMut<D>,
269 a: &StridedView<A, OpA>,
270 b: &StridedView<B, OpB>,
271 c: &StridedView<C, OpC>,
272 f: impl Fn(A, B, C) -> D + MaybeSync,
273 validated: ValidatedDestinationLayout,
274) -> Result<()> {
275 // SAFETY: the caller supplies the same invariants as the owning checked entry.
276 crate::map_view::zip_map3_into_validated::<D, A, B, C, OpA, OpB, OpC>(
277 dest, a, b, c, f, validated,
278 )
279}
280
281/// Prevalidated zip map4 into validated for kernel-family implementations.
282///
283/// # Safety
284/// All input shapes must match the destination. `validated` must have been
285/// obtained for this destination's current geometry, proving injectivity;
286/// possessing a marker from another layout is not sufficient. View/descriptor
287/// bounds and aliasing contracts must continue to hold throughout replay.
288///
289/// # Examples
290///
291/// ```
292/// use strided_basic::execution::*;
293/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
294/// use strided_basic::StridedArray;
295/// let src = StridedArray::<f64>::from_parts(vec![2.0; 2], &[2], &[1], 0).unwrap();
296/// let mut dst = StridedArray::<f64>::col_major(&[2]);
297/// let checked = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
298/// unsafe { zip_map4_into_validated(&mut dst.view_mut(), &src.view(), &src.view(), &src.view(), &src.view(), |a, b, c, d| a + b + c + d, checked) }.unwrap();
299/// assert_eq!(dst.get(&[1]), 8.0);
300/// ```
301///
302/// # Errors
303/// Forwards errors from the owning kernel or callback; callers must still
304/// satisfy the safety contract before invoking this prevalidated entry.
305#[inline]
306pub unsafe fn zip_map4_into_validated<
307 D: Copy + MaybeSendSync,
308 A: Copy + MaybeSendSync,
309 B: Copy + MaybeSendSync,
310 C: Copy + MaybeSendSync,
311 E: Copy + MaybeSendSync,
312 OpA: ElementOp<A>,
313 OpB: ElementOp<B>,
314 OpC: ElementOp<C>,
315 OpE: ElementOp<E>,
316>(
317 dest: &mut StridedViewMut<D>,
318 a: &StridedView<A, OpA>,
319 b: &StridedView<B, OpB>,
320 c: &StridedView<C, OpC>,
321 e: &StridedView<E, OpE>,
322 f: impl Fn(A, B, C, E) -> D + MaybeSync,
323 validated: ValidatedDestinationLayout,
324) -> Result<()> {
325 // SAFETY: the caller supplies the same invariants as the owning checked entry.
326 crate::map_view::zip_map4_into_validated::<D, A, B, C, E, OpA, OpB, OpC, OpE>(
327 dest, a, b, c, e, f, validated,
328 )
329}
330
331/// Prevalidated map raw into validated for kernel-family implementations.
332///
333/// # Safety
334/// All input shapes must match the destination. `validated` must have been
335/// obtained for this destination's current geometry, proving injectivity;
336/// possessing a marker from another layout is not sufficient. View/descriptor
337/// bounds and aliasing contracts must continue to hold throughout replay.
338///
339/// # Examples
340///
341/// ```
342/// use strided_basic::execution::*;
343/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
344/// use strided_basic::{RawStridedRef, RawStridedMut, Identity};
345/// let values = [2.0_f64; 2];
346/// let src = RawStridedRef::new(&values, &[2], &[1], 0).unwrap();
347/// let mut output = [0.0; 2];
348/// let mut dst = RawStridedMut::new(&mut output, &[2], &[1], 0).unwrap();
349/// let checked = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
350/// unsafe { map_raw_into_validated::<f64, f64, Identity>(&mut dst, &src, |a| a, checked) }.unwrap();
351/// assert_eq!(output, [2.0; 2]);
352/// ```
353///
354/// # Errors
355/// Forwards errors from the owning kernel or callback; callers must still
356/// satisfy the safety contract before invoking this prevalidated entry.
357#[inline]
358pub unsafe fn map_raw_into_validated<
359 D: Copy + MaybeSendSync,
360 A: Copy + MaybeSendSync,
361 Op: ElementOp<A>,
362>(
363 dest: &mut crate::RawStridedMut<'_, D>,
364 src: &crate::RawStridedRef<'_, A>,
365 f: impl Fn(A) -> D + MaybeSync,
366 validated: ValidatedDestinationLayout,
367) -> Result<()> {
368 // SAFETY: the caller supplies the same invariants as the owning checked entry.
369 crate::map_view::map_raw_into_validated::<D, A, Op>(dest, src, f, validated)
370}
371
372/// Prevalidated zip map2 raw into validated for kernel-family implementations.
373///
374/// # Safety
375/// All input shapes must match the destination. `validated` must have been
376/// obtained for this destination's current geometry, proving injectivity;
377/// possessing a marker from another layout is not sufficient. View/descriptor
378/// bounds and aliasing contracts must continue to hold throughout replay.
379///
380/// # Examples
381///
382/// ```
383/// use strided_basic::execution::*;
384/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
385/// use strided_basic::{RawStridedRef, RawStridedMut, Identity};
386/// let values = [2.0_f64; 2];
387/// let src = RawStridedRef::new(&values, &[2], &[1], 0).unwrap();
388/// let mut output = [0.0; 2];
389/// let mut dst = RawStridedMut::new(&mut output, &[2], &[1], 0).unwrap();
390/// let checked = validate_destination_layout_without_alloc(&[2], &[1]).unwrap();
391/// unsafe { zip_map2_raw_into_validated::<f64, f64, f64, Identity, Identity>(&mut dst, &src, &src, |a, b| a + b, checked) }.unwrap();
392/// assert_eq!(output, [4.0; 2]);
393/// ```
394///
395/// # Errors
396/// Forwards errors from the owning kernel or callback; callers must still
397/// satisfy the safety contract before invoking this prevalidated entry.
398#[inline]
399pub unsafe fn zip_map2_raw_into_validated<
400 D: Copy + MaybeSendSync,
401 A: Copy + MaybeSendSync,
402 B: Copy + MaybeSendSync,
403 OpA: ElementOp<A>,
404 OpB: ElementOp<B>,
405>(
406 dest: &mut crate::RawStridedMut<'_, D>,
407 a: &crate::RawStridedRef<'_, A>,
408 b: &crate::RawStridedRef<'_, B>,
409 f: impl Fn(A, B) -> D + MaybeSync,
410 validated: ValidatedDestinationLayout,
411) -> Result<()> {
412 // SAFETY: the caller supplies the same invariants as the owning checked entry.
413 crate::map_view::zip_map2_raw_into_validated::<D, A, B, OpA, OpB>(dest, a, b, f, validated)
414}
415
416#[cfg(feature = "parallel")]
417/// Prevalidated compute costs for kernel-family implementations.
418///
419/// # Safety
420/// All rank-indexed arrays must have matching lengths and a valid destination
421/// index (when present). Shape products, stride magnitudes, cost arithmetic,
422/// and every intermediate offset used by planning/iteration must be representable.
423/// Iteration blocks must be positive and offsets must correspond to the supplied
424/// layouts; threaded partitioning additionally requires positive thread counts,
425/// costs and nonnegative spacing. Callback memory accesses must be valid for each generated
426/// block, with disjoint mutable regions when partitions execute concurrently.
427///
428/// # Examples
429///
430/// ```
431/// use strided_basic::execution::*;
432/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
433/// let costs = unsafe { compute_costs(&[vec![1, 4], vec![1, 8]]) };
434/// assert_eq!(costs.as_slice(), [2, 8]);
435/// ```
436#[inline]
437pub unsafe fn compute_costs<S: AsRef<[isize]>>(all_strides: &[S]) -> InlineVec<isize> {
438 // SAFETY: the caller supplies the same invariants as the owning checked entry.
439 crate::fuse::compute_costs::<S>(all_strides)
440}
441
442#[cfg(feature = "parallel")]
443/// Prevalidated mapreduce threaded for kernel-family implementations.
444///
445/// # Safety
446/// All rank-indexed arrays must have matching lengths and a valid destination
447/// index (when present). Shape products, stride magnitudes, cost arithmetic,
448/// and every intermediate offset used by planning/iteration must be representable.
449/// Iteration blocks must be positive and offsets must correspond to the supplied
450/// layouts; threaded partitioning additionally requires positive thread counts,
451/// costs and nonnegative spacing. Callback memory accesses must be valid for each generated
452/// block, with disjoint mutable regions when partitions execute concurrently.
453///
454/// # Examples
455///
456/// ```
457/// use strided_basic::execution::*;
458/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
459/// use std::sync::atomic::{AtomicUsize, Ordering};
460/// let count = AtomicUsize::new(0);
461/// unsafe { mapreduce_threaded(&[4], &[4], &[vec![1]], &[0], &[2], 1, 0, 1, &|dims, _, _, _| { count.fetch_add(dims.iter().product::<usize>(), Ordering::Relaxed); Ok(()) }) }.unwrap();
462/// assert_eq!(count.load(Ordering::Relaxed), 4);
463/// ```
464///
465/// # Errors
466/// Forwards errors from the owning kernel or callback; callers must still
467/// satisfy the safety contract before invoking this prevalidated entry.
468#[inline]
469pub unsafe fn mapreduce_threaded<S: AsRef<[isize]>, F>(
470 dims: &[usize],
471 blocks: &[usize],
472 strides_list: &[S],
473 offsets: &[isize],
474 costs: &[isize],
475 nthreads: usize,
476 spacing: isize,
477 taskindex: usize,
478 f: &F,
479) -> Result<()>
480where
481 F: Fn(&[usize], &[usize], &[&[isize]], &[isize]) -> Result<()> + Sync,
482{
483 // SAFETY: the caller supplies the same invariants as the owning checked entry.
484 crate::threading::mapreduce_threaded::<S, F>(
485 dims,
486 blocks,
487 strides_list,
488 offsets,
489 costs,
490 nthreads,
491 spacing,
492 taskindex,
493 f,
494 )
495}
496
497#[cfg(feature = "parallel")]
498pub use crate::execution_policy::rayon_threads;
499
500/// Full-overwrite indexed replay for an operation-family adapter.
501///
502/// # Safety
503/// The adapter must reject input/output overlap before creating the input
504/// references. All descriptor allocation and initialization contracts must
505/// remain valid for the call. Output slots may be uninitialized; the owning
506/// plan retains its checked layout/index validation and private initialization
507/// receipt. No initialized reference to the output backing may be formed.
508/// Gather into uninitialized output without exposing an initialization receipt.
509///
510/// # Examples
511///
512/// ```
513/// use strided_basic::{RawStridedRef, RawStridedMut};
514/// use strided_basic::execution::*;
515/// use core::mem::MaybeUninit;
516/// use strided_basic::{GatherPlan, GatherSpec};
517/// let spec = GatherSpec { offset_dims: vec![], collapsed_slice_dims: vec![0], start_index_map: vec![0], index_vector_dim: 1, slice_sizes: vec![1] };
518/// let plan = GatherPlan::compile(&[3], &[1], &[2, 1], &[1, 2], &[2], &[1], spec).unwrap();
519/// let src = RawStridedRef::new(&[1_i32, 2, 3], &[3], &[1], 0).unwrap();
520/// let indices = RawStridedRef::new(&[0_i32, 2], &[2, 1], &[1, 2], 0).unwrap();
521/// let mut values = [MaybeUninit::<i32>::uninit(); 2];
522/// let mut dst = RawStridedMut::new(&mut values, &[2], &[1], 0).unwrap();
523/// // SAFETY: input and output allocations are disjoint and layouts match the plan.
524/// unsafe { gather_into_uninit(&plan, &mut dst, &src, &indices) }.unwrap();
525/// assert_eq!(unsafe { values[1].assume_init() }, 3);
526/// ```
527///
528/// # Errors
529/// Forwards the plan layout/index validation errors before successful overwrite.
530#[inline]
531pub unsafe fn gather_into_uninit<T, I>(
532 plan: &crate::GatherPlan,
533 dest: &mut crate::RawStridedMut<'_, core::mem::MaybeUninit<T>>,
534 operand: &crate::RawStridedRef<'_, T>,
535 start_indices: &crate::RawStridedRef<'_, I>,
536) -> Result<()>
537where
538 T: Copy + MaybeSendSync,
539 I: crate::GatherIndex,
540{
541 plan.execute_uninit(dest, operand, start_indices)
542}
543
544/// Full-overwrite indexed replay for an operation-family adapter.
545///
546/// # Safety
547/// The adapter must reject input/output overlap before creating the input
548/// references. All descriptor allocation and initialization contracts must
549/// remain valid for the call. Output slots may be uninitialized; the owning
550/// plan retains its checked layout/index validation and private initialization
551/// receipt. No initialized reference to the output backing may be formed.
552///
553/// # Examples
554///
555/// ```
556/// use strided_basic::execution::*;
557/// // SAFETY: the example supplies matching bounded layouts and disjoint storage.
558/// use strided_basic::{DynamicSlicePlan, RawStridedRef, RawStridedMut};
559/// use core::mem::MaybeUninit;
560/// let plan = DynamicSlicePlan::compile(&[3], &[1], &[1], &[1], &[2], &[1], &[2]).unwrap();
561/// let src = RawStridedRef::new(&[1_i32, 2, 3], &[3], &[1], 0).unwrap();
562/// let starts = RawStridedRef::new(&[1_i32], &[1], &[1], 0).unwrap();
563/// let mut values = [MaybeUninit::<i32>::uninit(); 2];
564/// let mut dst = RawStridedMut::new(&mut values, &[2], &[1], 0).unwrap();
565/// unsafe { dynamic_slice_into_uninit(&plan, &mut dst, &src, &starts) }.unwrap();
566/// assert_eq!(unsafe { values[1].assume_init() }, 3);
567/// ```
568///
569/// # Errors
570/// Forwards errors from the owning kernel or callback; callers must still
571/// satisfy the safety contract before invoking this prevalidated entry.
572#[inline]
573pub unsafe fn dynamic_slice_into_uninit<T, I>(
574 plan: &crate::DynamicSlicePlan,
575 dest: &mut crate::RawStridedMut<'_, core::mem::MaybeUninit<T>>,
576 operand: &crate::RawStridedRef<'_, T>,
577 starts: &crate::RawStridedRef<'_, I>,
578) -> Result<()>
579where
580 T: Copy + MaybeSendSync,
581 I: crate::GatherIndex,
582{
583 plan.execute_uninit(dest, operand, starts)
584}
585
586/// Full-overwrite indexed replay for an operation-family adapter.
587///
588/// # Safety
589/// The adapter must reject input/output overlap before creating the input
590/// references. All descriptor allocation and initialization contracts must
591/// remain valid for the call. Output slots may be uninitialized; the owning
592/// plan retains its checked layout/index validation and private initialization
593/// receipt. No initialized reference to the output backing may be formed.
594/// Copy the operand and overwrite its selected window.
595///
596/// # Examples
597///
598/// ```
599/// use strided_basic::{RawStridedRef, RawStridedMut};
600/// use strided_basic::execution::*;
601/// use core::mem::MaybeUninit;
602/// use strided_basic::DynamicUpdateSlicePlan;
603/// let plan = DynamicUpdateSlicePlan::compile(&[3], &[1], &[1], &[1], &[1], &[1], &[3], &[1]).unwrap();
604/// let src = RawStridedRef::new(&[1_i32, 2, 3], &[3], &[1], 0).unwrap();
605/// let update = RawStridedRef::new(&[9_i32], &[1], &[1], 0).unwrap();
606/// let starts = RawStridedRef::new(&[1_i32], &[1], &[1], 0).unwrap();
607/// let mut values = [MaybeUninit::<i32>::uninit(); 3];
608/// let mut dst = RawStridedMut::new(&mut values, &[3], &[1], 0).unwrap();
609/// // SAFETY: all inputs are initialized and disjoint from the matching output.
610/// unsafe { dynamic_update_into_uninit(&plan, &mut dst, &src, &update, &starts) }.unwrap();
611/// assert_eq!(unsafe { values[1].assume_init() }, 9);
612/// ```
613///
614/// # Errors
615/// Forwards the plan layout/index validation errors.
616#[inline]
617pub unsafe fn dynamic_update_into_uninit<'a, T, I>(
618 plan: &crate::DynamicUpdateSlicePlan,
619 dest: &'a mut crate::RawStridedMut<'a, core::mem::MaybeUninit<T>>,
620 operand: &crate::RawStridedRef<'_, T>,
621 update: &crate::RawStridedRef<'_, T>,
622 starts: &crate::RawStridedRef<'_, I>,
623) -> Result<()>
624where
625 T: Copy + MaybeSendSync,
626 I: crate::GatherIndex,
627{
628 plan.execute_uninit(dest, operand, update, starts)
629}
630
631/// Full-overwrite indexed replay for an operation-family adapter.
632///
633/// # Safety
634/// The adapter must reject input/output overlap before creating the input
635/// references. All descriptor allocation and initialization contracts must
636/// remain valid for the call. Output slots may be uninitialized; the owning
637/// plan retains its checked layout/index validation and private initialization
638/// receipt. No initialized reference to the output backing may be formed.
639/// Copy the operand before additive scatter into its initialized logical slots.
640///
641/// # Examples
642///
643/// ```
644/// use strided_basic::{RawStridedRef, RawStridedMut};
645/// use strided_basic::execution::*;
646/// use core::mem::MaybeUninit;
647/// use strided_basic::{ScatterPlan, ScatterSpec};
648/// let spec = ScatterSpec { update_window_dims: vec![], inserted_window_dims: vec![0], scatter_dims_to_operand_dims: vec![0], index_vector_dim: 1 };
649/// let plan = ScatterPlan::compile(&[3], &[1], &[1, 1], &[1, 1], &[1], &[1], &[3], &[1], spec).unwrap();
650/// let src = RawStridedRef::new(&[1_i32, 2, 3], &[3], &[1], 0).unwrap();
651/// let update = RawStridedRef::new(&[9_i32], &[1], &[1], 0).unwrap();
652/// let indices = RawStridedRef::new(&[1_i64], &[1, 1], &[1, 1], 0).unwrap();
653/// let mut values = [MaybeUninit::<i32>::uninit(); 3];
654/// let mut dst = RawStridedMut::new(&mut values, &[3], &[1], 0).unwrap();
655/// // SAFETY: all inputs are initialized and disjoint from the matching output.
656/// unsafe { scatter_into_uninit(&plan, &mut dst, &src, &indices, &update, i32::wrapping_add) }.unwrap();
657/// assert_eq!(unsafe { values[1].assume_init() }, 11);
658/// ```
659///
660/// # Errors
661/// Forwards the plan layout/index validation errors.
662#[inline]
663pub unsafe fn scatter_into_uninit<'a, T, I>(
664 plan: &crate::ScatterPlan,
665 dest: &'a mut crate::RawStridedMut<'a, core::mem::MaybeUninit<T>>,
666 operand: &crate::RawStridedRef<'_, T>,
667 scatter_indices: &crate::RawStridedRef<'_, I>,
668 updates: &crate::RawStridedRef<'_, T>,
669 combine: fn(T, T) -> T,
670) -> Result<()>
671where
672 T: Copy + core::ops::Add<Output = T> + MaybeSendSync,
673 I: crate::GatherIndex,
674{
675 plan.execute_uninit(dest, operand, scatter_indices, updates, combine)
676}