@@ -173,6 +173,11 @@ where
173173
174174 /// Returns an array reference containing the entire SIMD vector.
175175 ///
176+ /// While this exists and *can* be used to read an arbitrary element from a
177+ /// vector, like `v.as_array()[i]`, that's discouraged because it forces the
178+ /// vector to memory which tends to perform poorly. Instead, use
179+ /// [`Self::get`]. (This is also why `Index` is not implemented.)
180+ ///
176181 /// # Examples
177182 ///
178183 /// ```
@@ -193,6 +198,11 @@ where
193198 }
194199
195200 /// Returns a mutable array reference containing the entire SIMD vector.
201+ ///
202+ /// While this exists and *can* be used to write an arbitrary element into a
203+ /// vector, like `v.as_mut_array()[i] = x`, that's discouraged because it
204+ /// forces the vector to memory which tends to perform poorly. Instead, use
205+ /// [`Self::set`]. (This is also why `IndexMut` is not implemented.)
196206 #[ inline]
197207 pub const fn as_mut_array ( & mut self ) -> & mut [ T ; N ] {
198208 // SAFETY: `Simd<T, N>` is just an overaligned `[T; N]` with
@@ -204,6 +214,113 @@ where
204214 unsafe { & mut * ( self as * mut Self as * mut [ T ; N ] ) }
205215 }
206216
217+ /// # Safety
218+ /// `idx` must be in-bounds (`idx < N`)
219+ #[ inline]
220+ unsafe fn get_inner ( self , idx : usize ) -> T {
221+ // SAFETY: our precondition is also that the value is in-bounds
222+ // and this type is a simd type of the correct element type.
223+ unsafe { core:: intrinsics:: simd:: simd_extract_dyn ( self , idx as u32 ) }
224+ }
225+
226+ /// Gets the value at `idx` to `val`.
227+ ///
228+ /// This typically faster than reading via `as_array`.
229+ ///
230+ /// # Panics
231+ ///
232+ /// If `idx` is out of bounds (aka if `idx >= N`).
233+ #[ inline]
234+ pub fn get ( self , idx : usize ) -> T {
235+ assert ! ( idx < N ) ;
236+ // SAFETY: just checked in-bounds with the assert
237+ unsafe { self . get_inner ( idx) }
238+ }
239+
240+ /// Gets the value at `idx` to `val`, or `None` if `idx >= N`.
241+ ///
242+ /// This typically faster than reading via `as_array`.
243+ #[ inline]
244+ pub fn get_checked ( self , idx : usize ) -> Option < T > {
245+ if idx < N {
246+ // SAFETY: just checked in-bounds with the if
247+ Some ( unsafe { self . get_inner ( idx) } )
248+ } else {
249+ None
250+ }
251+ }
252+
253+ /// Gets the value at `idx` to `val`.
254+ ///
255+ /// This typically faster than reading via `as_array`.
256+ ///
257+ /// # Safety
258+ /// `idx` must be in-bounds (`idx < N`)
259+ #[ inline]
260+ pub unsafe fn get_unchecked ( self , idx : usize ) -> T {
261+ // SAFETY: our precondition is also that the value is in-bounds
262+ unsafe {
263+ core:: hint:: assert_unchecked ( idx < N ) ;
264+ self . get_inner ( idx)
265+ }
266+ }
267+
268+ /// # Safety
269+ /// `idx` must be in-bounds (`idx < N`)
270+ #[ inline]
271+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
272+ unsafe fn set_inner ( self , idx : usize , val : T ) -> Self {
273+ // SAFETY: our precondition is also that the value is in-bounds
274+ // and this type is a simd type of the correct element type.
275+ unsafe { core:: intrinsics:: simd:: simd_insert_dyn ( self , idx as u32 , val) }
276+ }
277+
278+ /// Sets the value at `idx` to `val`, returning the updated vector.
279+ ///
280+ /// This typically faster than updating via `as_mut_array`.
281+ ///
282+ /// # Panics
283+ ///
284+ /// If `idx` is out of bounds (aka if `idx >= N`).
285+ #[ inline]
286+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
287+ pub fn set ( self , idx : usize , val : T ) -> Self {
288+ assert ! ( idx < N ) ;
289+ // SAFETY: just checked in-bounds with the assert
290+ unsafe { self . set_inner ( idx, val) }
291+ }
292+
293+ /// Sets the value at `idx` to `val` and returns the updated vector
294+ /// or returns `None` if `idx >= N`.
295+ ///
296+ /// This typically faster than updating via `as_mut_array`.
297+ #[ inline]
298+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
299+ pub fn set_checked ( self , idx : usize , val : T ) -> Option < Self > {
300+ if idx < N {
301+ // SAFETY: just checked in-bounds with the if
302+ Some ( unsafe { self . set_inner ( idx, val) } )
303+ } else {
304+ None
305+ }
306+ }
307+
308+ /// Sets the value at `idx` to `val`, returning the updated vector.
309+ ///
310+ /// This typically faster than updating via `as_mut_array`.
311+ ///
312+ /// # Safety
313+ /// `idx` must be in-bounds (`idx < N`)
314+ #[ inline]
315+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
316+ pub unsafe fn set_unchecked ( self , idx : usize , val : T ) -> Self {
317+ // SAFETY: our precondition is also that the value is in-bounds
318+ unsafe {
319+ core:: hint:: assert_unchecked ( idx < N ) ;
320+ self . set_inner ( idx, val)
321+ }
322+ }
323+
207324 /// Loads a vector from an array of `T`.
208325 ///
209326 /// This function is necessary since `repr(simd)` has padding for non-power-of-2 vectors (at the time of writing).
0 commit comments