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