diff options
| author | Caleb Zulawski <caleb.zulawski@gmail.com> | 2024-09-27 22:38:36 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-27 22:38:36 -0400 |
| commit | 158e2409fe479cd509d1549ce629a40a1588f1bf (patch) | |
| tree | e35fe3767b16088796c8bc36240a14d190de7fe4 | |
| parent | 5fb43ca86f09ef963fffb995c359c380d7beab2f (diff) | |
| parent | 9392fb1c2b73b453a53392ebfd52462100e0c430 (diff) | |
| download | rust-158e2409fe479cd509d1549ce629a40a1588f1bf.tar.gz rust-158e2409fe479cd509d1549ce629a40a1588f1bf.zip | |
Merge pull request #441 from sammysheep/shift_elements
shift_elements_{left,right}| -rw-r--r-- | crates/core_simd/src/swizzle.rs | 74 | ||||
| -rw-r--r-- | crates/core_simd/tests/swizzle.rs | 18 |
2 files changed, 92 insertions, 0 deletions
diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index e0edb2cf10a..dbd84543064 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -251,6 +251,50 @@ where Rotate::<OFFSET>::swizzle(self) } + /// Shifts the vector elements to the left by `OFFSET`, filling in with + /// `padding` from the right. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original inputs"] + pub fn shift_elements_left<const OFFSET: usize>(self, padding: T) -> Self { + struct Shift<const OFFSET: usize>; + + impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> { + const INDEX: [usize; N] = const { + let mut index = [N; N]; + let mut i = 0; + while i + OFFSET < N { + index[i] = i + OFFSET; + i += 1; + } + index + }; + } + + Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding)) + } + + /// Shifts the vector elements to the right by `OFFSET`, filling in with + /// `padding` from the left. + #[inline] + #[must_use = "method returns a new vector and does not mutate the original inputs"] + pub fn shift_elements_right<const OFFSET: usize>(self, padding: T) -> Self { + struct Shift<const OFFSET: usize>; + + impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> { + const INDEX: [usize; N] = const { + let mut index = [N; N]; + let mut i = OFFSET; + while i < N { + index[i] = i - OFFSET; + i += 1; + } + index + }; + } + + Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding)) + } + /// Interleave two vectors. /// /// The resulting vectors contain elements taken alternatively from `self` and `other`, first @@ -451,6 +495,36 @@ where unsafe { Self::from_int_unchecked(self.to_int().rotate_elements_right::<OFFSET>()) } } + /// Shifts the mask elements to the left by `OFFSET`, filling in with + /// `padding` from the right. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original inputs"] + pub fn shift_elements_left<const OFFSET: usize>(self, padding: bool) -> Self { + // Safety: swizzles are safe for masks + unsafe { + Self::from_int_unchecked(self.to_int().shift_elements_left::<OFFSET>(if padding { + T::TRUE + } else { + T::FALSE + })) + } + } + + /// Shifts the mask elements to the right by `OFFSET`, filling in with + /// `padding` from the left. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original inputs"] + pub fn shift_elements_right<const OFFSET: usize>(self, padding: bool) -> Self { + // Safety: swizzles are safe for masks + unsafe { + Self::from_int_unchecked(self.to_int().shift_elements_right::<OFFSET>(if padding { + T::TRUE + } else { + T::FALSE + })) + } + } + /// Interleave two masks. /// /// The resulting masks contain elements taken alternatively from `self` and `other`, first diff --git a/crates/core_simd/tests/swizzle.rs b/crates/core_simd/tests/swizzle.rs index 522d71439b7..7001e5f6bf8 100644 --- a/crates/core_simd/tests/swizzle.rs +++ b/crates/core_simd/tests/swizzle.rs @@ -50,6 +50,24 @@ fn rotate() { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn shift() { + let a = Simd::from_array([1, 2, 3, 4]); + assert_eq!(a.shift_elements_left::<0>(0).to_array(), [1, 2, 3, 4]); + assert_eq!(a.shift_elements_left::<1>(0).to_array(), [2, 3, 4, 0]); + assert_eq!(a.shift_elements_left::<2>(9).to_array(), [3, 4, 9, 9]); + assert_eq!(a.shift_elements_left::<3>(8).to_array(), [4, 8, 8, 8]); + assert_eq!(a.shift_elements_left::<4>(7).to_array(), [7, 7, 7, 7]); + assert_eq!(a.shift_elements_left::<5>(6).to_array(), [6, 6, 6, 6]); + assert_eq!(a.shift_elements_right::<0>(0).to_array(), [1, 2, 3, 4]); + assert_eq!(a.shift_elements_right::<1>(0).to_array(), [0, 1, 2, 3]); + assert_eq!(a.shift_elements_right::<2>(-1).to_array(), [-1, -1, 1, 2]); + assert_eq!(a.shift_elements_right::<3>(-2).to_array(), [-2, -2, -2, 1]); + assert_eq!(a.shift_elements_right::<4>(-3).to_array(), [-3, -3, -3, -3]); + assert_eq!(a.shift_elements_right::<5>(-4).to_array(), [-4, -4, -4, -4]); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn interleave() { let a = Simd::from_array([0, 1, 2, 3, 4, 5, 6, 7]); let b = Simd::from_array([8, 9, 10, 11, 12, 13, 14, 15]); |
