@@ -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,135 @@ 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+ ///
234+ /// # Examples
235+ ///
236+ /// ```
237+ /// # #![feature(portable_simd)]
238+ /// # #[cfg(feature = "as_crate")] use core_simd::simd;
239+ /// # #[cfg(not(feature = "as_crate"))] use core::simd;
240+ /// # use simd::{Simd, u64x4};
241+ /// let v: u64x4 = Simd::from_array([3, 5, 7, 11]);
242+ /// assert_eq!(v.get(2), 7);
243+ /// ```
244+ #[ inline]
245+ pub fn get ( self , idx : usize ) -> T {
246+ assert ! ( idx < N ) ;
247+ // SAFETY: just checked in-bounds with the assert
248+ unsafe { self . get_inner ( idx) }
249+ }
250+
251+ /// Gets the value at `idx` to `val`, or `None` if `idx >= N`.
252+ ///
253+ /// This typically faster than reading via `as_array`.
254+ #[ inline]
255+ pub fn get_checked ( self , idx : usize ) -> Option < T > {
256+ if idx < N {
257+ // SAFETY: just checked in-bounds with the if
258+ Some ( unsafe { self . get_inner ( idx) } )
259+ } else {
260+ None
261+ }
262+ }
263+
264+ /// Gets the value at `idx` to `val`.
265+ ///
266+ /// This typically faster than reading via `as_array`.
267+ ///
268+ /// # Safety
269+ /// `idx` must be in-bounds (`idx < N`)
270+ #[ inline]
271+ pub unsafe fn get_unchecked ( self , idx : usize ) -> T {
272+ // SAFETY: our precondition is also that the value is in-bounds
273+ unsafe {
274+ core:: hint:: assert_unchecked ( idx < N ) ;
275+ self . get_inner ( idx)
276+ }
277+ }
278+
279+ /// # Safety
280+ /// `idx` must be in-bounds (`idx < N`)
281+ #[ inline]
282+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
283+ unsafe fn set_inner ( self , idx : usize , val : T ) -> Self {
284+ // SAFETY: our precondition is also that the value is in-bounds
285+ // and this type is a simd type of the correct element type.
286+ unsafe { core:: intrinsics:: simd:: simd_insert_dyn ( self , idx as u32 , val) }
287+ }
288+
289+ /// Sets the value at `idx` to `val`, returning the updated vector.
290+ ///
291+ /// This typically faster than updating via `as_mut_array`.
292+ ///
293+ /// # Panics
294+ ///
295+ /// If `idx` is out of bounds (aka if `idx >= N`).
296+ ///
297+ /// # Examples
298+ ///
299+ /// ```
300+ /// # #![feature(portable_simd)]
301+ /// # #[cfg(feature = "as_crate")] use core_simd::simd;
302+ /// # #[cfg(not(feature = "as_crate"))] use core::simd;
303+ /// # use simd::{Simd, u64x4};
304+ /// let v: u64x4 = Simd::from_array([3, 5, 7, 11]);
305+ /// assert_eq!(v.set(2, 99).as_array(), &[3, 5, 99, 11]);
306+ /// ```
307+ #[ inline]
308+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
309+ pub fn set ( self , idx : usize , val : T ) -> Self {
310+ assert ! ( idx < N ) ;
311+ // SAFETY: just checked in-bounds with the assert
312+ unsafe { self . set_inner ( idx, val) }
313+ }
314+
315+ /// Sets the value at `idx` to `val` and returns the updated vector
316+ /// or returns `None` if `idx >= N`.
317+ ///
318+ /// This typically faster than updating via `as_mut_array`.
319+ #[ inline]
320+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
321+ pub fn set_checked ( self , idx : usize , val : T ) -> Option < Self > {
322+ if idx < N {
323+ // SAFETY: just checked in-bounds with the if
324+ Some ( unsafe { self . set_inner ( idx, val) } )
325+ } else {
326+ None
327+ }
328+ }
329+
330+ /// Sets the value at `idx` to `val`, returning the updated vector.
331+ ///
332+ /// This typically faster than updating via `as_mut_array`.
333+ ///
334+ /// # Safety
335+ /// `idx` must be in-bounds (`idx < N`)
336+ #[ inline]
337+ #[ must_use = "This returns a new vector, rather than updating in-place" ]
338+ pub unsafe fn set_unchecked ( self , idx : usize , val : T ) -> Self {
339+ // SAFETY: our precondition is also that the value is in-bounds
340+ unsafe {
341+ core:: hint:: assert_unchecked ( idx < N ) ;
342+ self . set_inner ( idx, val)
343+ }
344+ }
345+
207346 /// Loads a vector from an array of `T`.
208347 ///
209348 /// This function is necessary since `repr(simd)` has padding for non-power-of-2 vectors (at the time of writing).
0 commit comments