Skip to content

Commit

Permalink
Merge pull request #441 from sammysheep/shift_elements
Browse files Browse the repository at this point in the history
shift_elements_{left,right}
  • Loading branch information
calebzulawski authored Sep 28, 2024
2 parents 5fb43ca + 9392fb1 commit 158e240
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
74 changes: 74 additions & 0 deletions crates/core_simd/src/swizzle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions crates/core_simd/tests/swizzle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ fn rotate() {
assert_eq!(a.rotate_elements_right::<5>().to_array(), [4, 1, 2, 3]);
}

#[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() {
Expand Down

0 comments on commit 158e240

Please sign in to comment.