Small refactor of float4 crate to make it easier to read.

This commit is contained in:
Nathan Vegdahl 2018-03-04 12:27:35 -08:00
parent a797ff012d
commit f39589ab72

View File

@ -4,10 +4,10 @@
extern crate simd; extern crate simd;
use std::cmp::PartialEq; use std::cmp::PartialEq;
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, BitAnd}; use std::ops::{Add, AddAssign, BitAnd, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
use simd::{f32x4, bool32fx4}; use simd::{bool32fx4, f32x4};
/// Essentially a tuple of four floats, which will use SIMD operations /// Essentially a tuple of four floats, which will use SIMD operations
/// where possible on a platform. /// where possible on a platform.
@ -24,27 +24,33 @@ pub struct Float4 {
} }
impl Float4 { impl Float4 {
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn new(a: f32, b: f32, c: f32, d: f32) -> Float4 { pub fn new(a: f32, b: f32, c: f32, d: f32) -> Float4 {
Float4 { data: f32x4::new(a, b, c, d) } #[cfg(feature = "simd_perf")]
{
Float4 {
data: f32x4::new(a, b, c, d),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
pub fn new(a: f32, b: f32, c: f32, d: f32) -> Float4 {
Float4 { data: [a, b, c, d] } Float4 { data: [a, b, c, d] }
} }
}
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn splat(n: f32) -> Float4 { pub fn splat(n: f32) -> Float4 {
Float4 { data: f32x4::splat(n) } #[cfg(feature = "simd_perf")]
{
Float4 {
data: f32x4::splat(n),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
pub fn splat(n: f32) -> Float4 {
Float4 { data: [n, n, n, n] } Float4 { data: [n, n, n, n] }
} }
}
#[inline] #[inline]
pub fn h_sum(&self) -> f32 { pub fn h_sum(&self) -> f32 {
@ -68,7 +74,11 @@ impl Float4 {
} else { } else {
self.get_3() self.get_3()
}; };
if n1 < n2 { n1 } else { n2 } if n1 < n2 {
n1
} else {
n2
}
} }
#[inline] #[inline]
@ -83,17 +93,23 @@ impl Float4 {
} else { } else {
self.get_3() self.get_3()
}; };
if n1 > n2 { n1 } else { n2 } if n1 > n2 {
n1
} else {
n2
}
} }
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn v_min(&self, other: Float4) -> Float4 { pub fn v_min(&self, other: Float4) -> Float4 {
Float4 { data: self.data.min(other.data) } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data.min(other.data),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline] {
pub fn v_min(&self, other: Float4) -> Float4 {
Float4::new( Float4::new(
if self.get_0() < other.get_0() { if self.get_0() < other.get_0() {
self.get_0() self.get_0()
@ -116,17 +132,19 @@ impl Float4 {
other.get_3() other.get_3()
}, },
) )
}
} }
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn v_max(&self, other: Float4) -> Float4 { pub fn v_max(&self, other: Float4) -> Float4 {
Float4 { data: self.data.max(other.data) } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data.max(other.data),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline] {
pub fn v_max(&self, other: Float4) -> Float4 {
Float4::new( Float4::new(
if self.get_0() > other.get_0() { if self.get_0() > other.get_0() {
self.get_0() self.get_0()
@ -150,15 +168,18 @@ impl Float4 {
}, },
) )
} }
}
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn lt(&self, other: Float4) -> Bool4 { pub fn lt(&self, other: Float4) -> Bool4 {
Bool4 { data: self.data.lt(other.data) } #[cfg(feature = "simd_perf")]
{
Bool4 {
data: self.data.lt(other.data),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline] {
pub fn lt(&self, other: Float4) -> Bool4 {
Bool4 { Bool4 {
data: [ data: [
self.data[0] < other.data[0], self.data[0] < other.data[0],
@ -168,15 +189,18 @@ impl Float4 {
], ],
} }
} }
}
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn lte(&self, other: Float4) -> Bool4 { pub fn lte(&self, other: Float4) -> Bool4 {
Bool4 { data: self.data.le(other.data) } #[cfg(feature = "simd_perf")]
{
Bool4 {
data: self.data.le(other.data),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline] {
pub fn lte(&self, other: Float4) -> Bool4 {
Bool4 { Bool4 {
data: [ data: [
self.data[0] <= other.data[0], self.data[0] <= other.data[0],
@ -186,15 +210,18 @@ impl Float4 {
], ],
} }
} }
}
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn gt(&self, other: Float4) -> Bool4 { pub fn gt(&self, other: Float4) -> Bool4 {
Bool4 { data: self.data.gt(other.data) } #[cfg(feature = "simd_perf")]
{
Bool4 {
data: self.data.gt(other.data),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline] {
pub fn gt(&self, other: Float4) -> Bool4 {
Bool4 { Bool4 {
data: [ data: [
self.data[0] > other.data[0], self.data[0] > other.data[0],
@ -204,15 +231,18 @@ impl Float4 {
], ],
} }
} }
}
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn gte(&self, other: Float4) -> Bool4 { pub fn gte(&self, other: Float4) -> Bool4 {
Bool4 { data: self.data.ge(other.data) } #[cfg(feature = "simd_perf")]
{
Bool4 {
data: self.data.ge(other.data),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline] {
pub fn gte(&self, other: Float4) -> Bool4 {
Bool4 { Bool4 {
data: [ data: [
self.data[0] >= other.data[0], self.data[0] >= other.data[0],
@ -222,157 +252,110 @@ impl Float4 {
], ],
} }
} }
}
/// Set the nth element to the given value. /// Set the nth element to the given value.
#[inline] #[inline(always)]
pub fn set_n(&mut self, n: usize, v: f32) { pub fn set_n(&mut self, n: usize, v: f32) {
match n { assert!(
0 => self.set_0(v), n <= 3,
1 => self.set_1(v), "Attempted to set element of Float4 outside of bounds."
2 => self.set_2(v), );
3 => self.set_3(v), #[cfg(feature = "simd_perf")]
_ => panic!("Attempted to set element of Float4 outside of bounds."), {
self.data = self.data.replace(n, v);
}
#[cfg(not(feature = "simd_perf"))]
unsafe {
*self.data.get_unchecked_mut(n) = v;
} }
} }
/// Set the 0th element to the given value. /// Set the 0th element to the given value.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn set_0(&mut self, n: f32) { pub fn set_0(&mut self, v: f32) {
self.data = self.data.replace(0, n); self.set_n(0, v);
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_0(&mut self, n: f32) {
unsafe {
*self.data.get_unchecked_mut(0) = n;
}
} }
/// Set the 1th element to the given value. /// Set the 1th element to the given value.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn set_1(&mut self, n: f32) { pub fn set_1(&mut self, v: f32) {
self.data = self.data.replace(1, n); self.set_n(1, v);
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_1(&mut self, n: f32) {
unsafe {
*self.data.get_unchecked_mut(1) = n;
}
} }
/// Set the 2th element to the given value. /// Set the 2th element to the given value.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn set_2(&mut self, n: f32) { pub fn set_2(&mut self, v: f32) {
self.data = self.data.replace(2, n); self.set_n(2, v);
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_2(&mut self, n: f32) {
unsafe {
*self.data.get_unchecked_mut(2) = n;
}
} }
/// Set the 3th element to the given value. /// Set the 3th element to the given value.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn set_3(&mut self, n: f32) { pub fn set_3(&mut self, v: f32) {
self.data = self.data.replace(3, n); self.set_n(3, v);
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_3(&mut self, n: f32) {
unsafe {
*self.data.get_unchecked_mut(3) = n;
}
} }
/// Returns the value of the nth element. /// Returns the value of the nth element.
#[inline] #[inline(always)]
pub fn get_n(&self, n: usize) -> f32 { pub fn get_n(&self, n: usize) -> f32 {
match n { assert!(
0 => self.get_0(), n <= 3,
1 => self.get_1(), "Attempted to access element of Float4 outside of bounds."
2 => self.get_2(), );
3 => self.get_3(), #[cfg(feature = "simd_perf")]
_ => panic!("Attempted to access element of Float4 outside of bounds."), {
self.data.extract(n)
} }
#[cfg(not(feature = "simd_perf"))]
unsafe { *self.data.get_unchecked(n) }
} }
/// Returns the value of the 0th element. /// Returns the value of the 0th element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_0(&self) -> f32 { pub fn get_0(&self) -> f32 {
self.data.extract(0) self.get_n(0)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_0(&self) -> f32 {
unsafe { *self.data.get_unchecked(0) }
} }
/// Returns the value of the 1th element. /// Returns the value of the 1th element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_1(&self) -> f32 { pub fn get_1(&self) -> f32 {
self.data.extract(1) self.get_n(1)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_1(&self) -> f32 {
unsafe { *self.data.get_unchecked(1) }
} }
/// Returns the value of the 2th element. /// Returns the value of the 2th element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_2(&self) -> f32 { pub fn get_2(&self) -> f32 {
self.data.extract(2) self.get_n(2)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_2(&self) -> f32 {
unsafe { *self.data.get_unchecked(2) }
} }
/// Returns the value of the 3th element. /// Returns the value of the 3th element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_3(&self) -> f32 { pub fn get_3(&self) -> f32 {
self.data.extract(3) self.get_n(3)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_3(&self) -> f32 {
unsafe { *self.data.get_unchecked(3) }
} }
} }
impl PartialEq for Float4 { impl PartialEq for Float4 {
#[inline] #[inline]
fn eq(&self, other: &Float4) -> bool { fn eq(&self, other: &Float4) -> bool {
self.get_0() == other.get_0() && self.get_1() == other.get_1() && self.get_0() == other.get_0() && self.get_1() == other.get_1()
self.get_2() == other.get_2() && self.get_3() == other.get_3() && self.get_2() == other.get_2() && self.get_3() == other.get_3()
} }
} }
impl Add for Float4 { impl Add for Float4 {
type Output = Float4; type Output = Float4;
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
fn add(self, other: Float4) -> Float4 { fn add(self, other: Float4) -> Float4 {
Float4 { data: self.data + other.data } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data + other.data,
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
fn add(self, other: Float4) -> Float4 {
Float4 { Float4 {
data: [ data: [
self.get_0() + other.get_0(), self.get_0() + other.get_0(),
@ -383,7 +366,7 @@ impl Add for Float4 {
} }
} }
} }
}
impl AddAssign for Float4 { impl AddAssign for Float4 {
#[inline(always)] #[inline(always)]
@ -392,18 +375,19 @@ impl AddAssign for Float4 {
} }
} }
impl Sub for Float4 { impl Sub for Float4 {
type Output = Float4; type Output = Float4;
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
fn sub(self, other: Float4) -> Float4 { fn sub(self, other: Float4) -> Float4 {
Float4 { data: self.data - other.data } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data - other.data,
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
fn sub(self, other: Float4) -> Float4 {
Float4 { Float4 {
data: [ data: [
self.get_0() - other.get_0(), self.get_0() - other.get_0(),
@ -414,7 +398,7 @@ impl Sub for Float4 {
} }
} }
} }
}
impl SubAssign for Float4 { impl SubAssign for Float4 {
#[inline(always)] #[inline(always)]
@ -423,18 +407,19 @@ impl SubAssign for Float4 {
} }
} }
impl Mul for Float4 { impl Mul for Float4 {
type Output = Float4; type Output = Float4;
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
fn mul(self, other: Float4) -> Float4 { fn mul(self, other: Float4) -> Float4 {
Float4 { data: self.data * other.data } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data * other.data,
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
fn mul(self, other: Float4) -> Float4 {
Float4 { Float4 {
data: [ data: [
self.get_0() * other.get_0(), self.get_0() * other.get_0(),
@ -445,18 +430,21 @@ impl Mul for Float4 {
} }
} }
} }
}
impl Mul<f32> for Float4 { impl Mul<f32> for Float4 {
type Output = Float4; type Output = Float4;
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
fn mul(self, other: f32) -> Float4 { fn mul(self, other: f32) -> Float4 {
Float4 { data: self.data * f32x4::splat(other) } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data * f32x4::splat(other),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
fn mul(self, other: f32) -> Float4 {
Float4 { Float4 {
data: [ data: [
self.get_0() * other, self.get_0() * other,
@ -467,7 +455,7 @@ impl Mul<f32> for Float4 {
} }
} }
} }
}
impl MulAssign for Float4 { impl MulAssign for Float4 {
#[inline(always)] #[inline(always)]
@ -483,18 +471,19 @@ impl MulAssign<f32> for Float4 {
} }
} }
impl Div for Float4 { impl Div for Float4 {
type Output = Float4; type Output = Float4;
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
fn div(self, other: Float4) -> Float4 { fn div(self, other: Float4) -> Float4 {
Float4 { data: self.data / other.data } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data / other.data,
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
fn div(self, other: Float4) -> Float4 {
Float4 { Float4 {
data: [ data: [
self.get_0() / other.get_0(), self.get_0() / other.get_0(),
@ -505,18 +494,21 @@ impl Div for Float4 {
} }
} }
} }
}
impl Div<f32> for Float4 { impl Div<f32> for Float4 {
type Output = Float4; type Output = Float4;
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
fn div(self, other: f32) -> Float4 { fn div(self, other: f32) -> Float4 {
Float4 { data: self.data / f32x4::splat(other) } #[cfg(feature = "simd_perf")]
{
Float4 {
data: self.data / f32x4::splat(other),
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)] {
fn div(self, other: f32) -> Float4 {
Float4 { Float4 {
data: [ data: [
self.get_0() / other, self.get_0() / other,
@ -527,7 +519,7 @@ impl Div<f32> for Float4 {
} }
} }
} }
}
impl DivAssign for Float4 { impl DivAssign for Float4 {
#[inline(always)] #[inline(always)]
@ -553,7 +545,6 @@ pub fn v_max(a: Float4, b: Float4) -> Float4 {
a.v_max(b) a.v_max(b)
} }
/// Essentially a tuple of four bools, which will use SIMD operations /// Essentially a tuple of four bools, which will use SIMD operations
/// where possible on a platform. /// where possible on a platform.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
@ -569,72 +560,67 @@ pub struct Bool4 {
} }
impl Bool4 { impl Bool4 {
/// Returns the value of the 0th element. /// Returns the value of the nth element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_0(&self) -> bool { pub fn get_n(&self, n: usize) -> bool {
self.data.extract(0) assert!(
n <= 3,
"Attempted to access element of Bool4 outside of bounds."
);
#[cfg(feature = "simd_perf")]
{
self.data.extract(n)
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
{
unsafe { *self.data.get_unchecked(n) }
}
}
/// Returns the value of the 0th element.
#[inline(always)] #[inline(always)]
pub fn get_0(&self) -> bool { pub fn get_0(&self) -> bool {
unsafe { *self.data.get_unchecked(0) } self.get_n(0)
} }
/// Returns the value of the 1th element. /// Returns the value of the 1th element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_1(&self) -> bool { pub fn get_1(&self) -> bool {
self.data.extract(1) self.get_n(1)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_1(&self) -> bool {
unsafe { *self.data.get_unchecked(1) }
} }
/// Returns the value of the 2th element. /// Returns the value of the 2th element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_2(&self) -> bool { pub fn get_2(&self) -> bool {
self.data.extract(2) self.get_n(2)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_2(&self) -> bool {
unsafe { *self.data.get_unchecked(2) }
} }
/// Returns the value of the 3th element. /// Returns the value of the 3th element.
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
pub fn get_3(&self) -> bool { pub fn get_3(&self) -> bool {
self.data.extract(3) self.get_n(3)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_3(&self) -> bool {
unsafe { *self.data.get_unchecked(3) }
} }
#[inline] #[inline]
pub fn to_bitmask(&self) -> u8 { pub fn to_bitmask(&self) -> u8 {
(self.get_0() as u8) | ((self.get_1() as u8) << 1) | ((self.get_2() as u8) << 2) | (self.get_0() as u8) | ((self.get_1() as u8) << 1) | ((self.get_2() as u8) << 2)
((self.get_3() as u8) << 3) | ((self.get_3() as u8) << 3)
} }
} }
impl BitAnd for Bool4 { impl BitAnd for Bool4 {
type Output = Bool4; type Output = Bool4;
#[cfg(feature = "simd_perf")]
#[inline(always)] #[inline(always)]
fn bitand(self, rhs: Bool4) -> Bool4 { fn bitand(self, rhs: Bool4) -> Bool4 {
Bool4 { data: self.data & rhs.data } #[cfg(feature = "simd_perf")]
{
Bool4 {
data: self.data & rhs.data,
}
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline] {
fn bitand(self, rhs: Bool4) -> Bool4 {
Bool4 { Bool4 {
data: [ data: [
self.data[0] && rhs.data[0], self.data[0] && rhs.data[0],
@ -645,7 +631,7 @@ impl BitAnd for Bool4 {
} }
} }
} }
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {