From f39589ab72a3b4a11ad199bc9d89f2482c02a960 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sun, 4 Mar 2018 12:27:35 -0800 Subject: [PATCH] Small refactor of float4 crate to make it easier to read. --- sub_crates/float4/src/lib.rs | 670 +++++++++++++++++------------------ 1 file changed, 328 insertions(+), 342 deletions(-) diff --git a/sub_crates/float4/src/lib.rs b/sub_crates/float4/src/lib.rs index 2a45a3d..35b1df0 100644 --- a/sub_crates/float4/src/lib.rs +++ b/sub_crates/float4/src/lib.rs @@ -4,10 +4,10 @@ extern crate simd; 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")] -use simd::{f32x4, bool32fx4}; +use simd::{bool32fx4, f32x4}; /// Essentially a tuple of four floats, which will use SIMD operations /// where possible on a platform. @@ -24,26 +24,32 @@ pub struct Float4 { } impl Float4 { - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn new(a: f32, b: f32, c: f32, d: f32) -> Float4 { - Float4 { data: f32x4::new(a, b, c, d) } - } - #[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] } + #[cfg(feature = "simd_perf")] + { + Float4 { + data: f32x4::new(a, b, c, d), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { data: [a, b, c, d] } + } } - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn splat(n: f32) -> Float4 { - Float4 { data: f32x4::splat(n) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn splat(n: f32) -> Float4 { - Float4 { data: [n, n, n, n] } + #[cfg(feature = "simd_perf")] + { + Float4 { + data: f32x4::splat(n), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { data: [n, n, n, n] } + } } #[inline] @@ -68,7 +74,11 @@ impl Float4 { } else { self.get_3() }; - if n1 < n2 { n1 } else { n2 } + if n1 < n2 { + n1 + } else { + n2 + } } #[inline] @@ -83,308 +93,281 @@ impl Float4 { } else { self.get_3() }; - if n1 > n2 { n1 } else { n2 } + if n1 > n2 { + n1 + } else { + n2 + } } - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn v_min(&self, other: Float4) -> Float4 { - Float4 { data: self.data.min(other.data) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline] - pub fn v_min(&self, other: Float4) -> Float4 { - Float4::new( - if self.get_0() < other.get_0() { - self.get_0() - } else { - other.get_0() - }, - if self.get_1() < other.get_1() { - self.get_1() - } else { - other.get_1() - }, - if self.get_2() < other.get_2() { - self.get_2() - } else { - other.get_2() - }, - if self.get_3() < other.get_3() { - self.get_3() - } else { - other.get_3() - }, - ) - + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data.min(other.data), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4::new( + if self.get_0() < other.get_0() { + self.get_0() + } else { + other.get_0() + }, + if self.get_1() < other.get_1() { + self.get_1() + } else { + other.get_1() + }, + if self.get_2() < other.get_2() { + self.get_2() + } else { + other.get_2() + }, + if self.get_3() < other.get_3() { + self.get_3() + } else { + other.get_3() + }, + ) + } } - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn v_max(&self, other: Float4) -> Float4 { - Float4 { data: self.data.max(other.data) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline] - pub fn v_max(&self, other: Float4) -> Float4 { - Float4::new( - if self.get_0() > other.get_0() { - self.get_0() - } else { - other.get_0() - }, - if self.get_1() > other.get_1() { - self.get_1() - } else { - other.get_1() - }, - if self.get_2() > other.get_2() { - self.get_2() - } else { - other.get_2() - }, - if self.get_3() > other.get_3() { - self.get_3() - } else { - other.get_3() - }, - ) + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data.max(other.data), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4::new( + if self.get_0() > other.get_0() { + self.get_0() + } else { + other.get_0() + }, + if self.get_1() > other.get_1() { + self.get_1() + } else { + other.get_1() + }, + if self.get_2() > other.get_2() { + self.get_2() + } else { + other.get_2() + }, + if self.get_3() > other.get_3() { + self.get_3() + } else { + other.get_3() + }, + ) + } } - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn lt(&self, other: Float4) -> Bool4 { - Bool4 { data: self.data.lt(other.data) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline] - pub fn lt(&self, other: Float4) -> Bool4 { - Bool4 { - data: [ - self.data[0] < other.data[0], - self.data[1] < other.data[1], - self.data[2] < other.data[2], - self.data[3] < other.data[3], - ], + #[cfg(feature = "simd_perf")] + { + Bool4 { + data: self.data.lt(other.data), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Bool4 { + data: [ + self.data[0] < other.data[0], + self.data[1] < other.data[1], + self.data[2] < other.data[2], + self.data[3] < other.data[3], + ], + } } } - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn lte(&self, other: Float4) -> Bool4 { - Bool4 { data: self.data.le(other.data) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline] - pub fn lte(&self, other: Float4) -> Bool4 { - Bool4 { - data: [ - self.data[0] <= other.data[0], - self.data[1] <= other.data[1], - self.data[2] <= other.data[2], - self.data[3] <= other.data[3], - ], + #[cfg(feature = "simd_perf")] + { + Bool4 { + data: self.data.le(other.data), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Bool4 { + data: [ + self.data[0] <= other.data[0], + self.data[1] <= other.data[1], + self.data[2] <= other.data[2], + self.data[3] <= other.data[3], + ], + } } } - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn gt(&self, other: Float4) -> Bool4 { - Bool4 { data: self.data.gt(other.data) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline] - pub fn gt(&self, other: Float4) -> Bool4 { - Bool4 { - data: [ - self.data[0] > other.data[0], - self.data[1] > other.data[1], - self.data[2] > other.data[2], - self.data[3] > other.data[3], - ], + #[cfg(feature = "simd_perf")] + { + Bool4 { + data: self.data.gt(other.data), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Bool4 { + data: [ + self.data[0] > other.data[0], + self.data[1] > other.data[1], + self.data[2] > other.data[2], + self.data[3] > other.data[3], + ], + } } } - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn gte(&self, other: Float4) -> Bool4 { - Bool4 { data: self.data.ge(other.data) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline] - pub fn gte(&self, other: Float4) -> Bool4 { - Bool4 { - data: [ - self.data[0] >= other.data[0], - self.data[1] >= other.data[1], - self.data[2] >= other.data[2], - self.data[3] >= other.data[3], - ], + #[cfg(feature = "simd_perf")] + { + Bool4 { + data: self.data.ge(other.data), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Bool4 { + data: [ + self.data[0] >= other.data[0], + self.data[1] >= other.data[1], + self.data[2] >= other.data[2], + self.data[3] >= other.data[3], + ], + } } } /// Set the nth element to the given value. - #[inline] + #[inline(always)] pub fn set_n(&mut self, n: usize, v: f32) { - match n { - 0 => self.set_0(v), - 1 => self.set_1(v), - 2 => self.set_2(v), - 3 => self.set_3(v), - _ => panic!("Attempted to set element of Float4 outside of bounds."), + assert!( + n <= 3, + "Attempted to set element of Float4 outside of bounds." + ); + #[cfg(feature = "simd_perf")] + { + 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. - #[cfg(feature = "simd_perf")] #[inline(always)] - pub fn set_0(&mut self, n: f32) { - self.data = self.data.replace(0, n); - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn set_0(&mut self, n: f32) { - unsafe { - *self.data.get_unchecked_mut(0) = n; - } + pub fn set_0(&mut self, v: f32) { + self.set_n(0, v); } /// Set the 1th element to the given value. - #[cfg(feature = "simd_perf")] #[inline(always)] - pub fn set_1(&mut self, n: f32) { - self.data = self.data.replace(1, n); - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn set_1(&mut self, n: f32) { - unsafe { - *self.data.get_unchecked_mut(1) = n; - } + pub fn set_1(&mut self, v: f32) { + self.set_n(1, v); } /// Set the 2th element to the given value. - #[cfg(feature = "simd_perf")] #[inline(always)] - pub fn set_2(&mut self, n: f32) { - self.data = self.data.replace(2, n); - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn set_2(&mut self, n: f32) { - unsafe { - *self.data.get_unchecked_mut(2) = n; - } + pub fn set_2(&mut self, v: f32) { + self.set_n(2, v); } /// Set the 3th element to the given value. - #[cfg(feature = "simd_perf")] #[inline(always)] - pub fn set_3(&mut self, n: f32) { - self.data = self.data.replace(3, n); - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn set_3(&mut self, n: f32) { - unsafe { - *self.data.get_unchecked_mut(3) = n; - } + pub fn set_3(&mut self, v: f32) { + self.set_n(3, v); } /// Returns the value of the nth element. - #[inline] + #[inline(always)] pub fn get_n(&self, n: usize) -> f32 { - match n { - 0 => self.get_0(), - 1 => self.get_1(), - 2 => self.get_2(), - 3 => self.get_3(), - _ => panic!("Attempted to access element of Float4 outside of bounds."), + assert!( + n <= 3, + "Attempted to access element of Float4 outside of bounds." + ); + #[cfg(feature = "simd_perf")] + { + self.data.extract(n) } + #[cfg(not(feature = "simd_perf"))] + unsafe { *self.data.get_unchecked(n) } } /// Returns the value of the 0th element. - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn get_0(&self) -> f32 { - self.data.extract(0) - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn get_0(&self) -> f32 { - unsafe { *self.data.get_unchecked(0) } + self.get_n(0) } /// Returns the value of the 1th element. - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn get_1(&self) -> f32 { - self.data.extract(1) - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn get_1(&self) -> f32 { - unsafe { *self.data.get_unchecked(1) } + self.get_n(1) } /// Returns the value of the 2th element. - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn get_2(&self) -> f32 { - self.data.extract(2) - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn get_2(&self) -> f32 { - unsafe { *self.data.get_unchecked(2) } + self.get_n(2) } /// Returns the value of the 3th element. - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn get_3(&self) -> f32 { - self.data.extract(3) - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn get_3(&self) -> f32 { - unsafe { *self.data.get_unchecked(3) } + self.get_n(3) } } - impl PartialEq for Float4 { #[inline] fn eq(&self, other: &Float4) -> bool { - 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_0() == other.get_0() && self.get_1() == other.get_1() + && self.get_2() == other.get_2() && self.get_3() == other.get_3() } } - impl Add for Float4 { type Output = Float4; - #[cfg(feature = "simd_perf")] #[inline(always)] fn add(self, other: Float4) -> Float4 { - Float4 { data: self.data + other.data } - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - fn add(self, other: Float4) -> Float4 { - Float4 { - data: [ - self.get_0() + other.get_0(), - self.get_1() + other.get_1(), - self.get_2() + other.get_2(), - self.get_3() + other.get_3(), - ], + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data + other.data, + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { + data: [ + self.get_0() + other.get_0(), + self.get_1() + other.get_1(), + self.get_2() + other.get_2(), + self.get_3() + other.get_3(), + ], + } } } } - impl AddAssign for Float4 { #[inline(always)] fn add_assign(&mut self, rhs: Float4) { @@ -392,30 +375,31 @@ impl AddAssign for Float4 { } } - impl Sub for Float4 { type Output = Float4; - #[cfg(feature = "simd_perf")] #[inline(always)] fn sub(self, other: Float4) -> Float4 { - Float4 { data: self.data - other.data } - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - fn sub(self, other: Float4) -> Float4 { - Float4 { - data: [ - self.get_0() - other.get_0(), - self.get_1() - other.get_1(), - self.get_2() - other.get_2(), - self.get_3() - other.get_3(), - ], + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data - other.data, + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { + data: [ + self.get_0() - other.get_0(), + self.get_1() - other.get_1(), + self.get_2() - other.get_2(), + self.get_3() - other.get_3(), + ], + } } } } - impl SubAssign for Float4 { #[inline(always)] fn sub_assign(&mut self, rhs: Float4) { @@ -423,25 +407,27 @@ impl SubAssign for Float4 { } } - impl Mul for Float4 { type Output = Float4; - #[cfg(feature = "simd_perf")] #[inline(always)] fn mul(self, other: Float4) -> Float4 { - Float4 { data: self.data * other.data } - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - fn mul(self, other: Float4) -> Float4 { - Float4 { - data: [ - self.get_0() * other.get_0(), - self.get_1() * other.get_1(), - self.get_2() * other.get_2(), - self.get_3() * other.get_3(), - ], + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data * other.data, + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { + data: [ + self.get_0() * other.get_0(), + self.get_1() * other.get_1(), + self.get_2() * other.get_2(), + self.get_3() * other.get_3(), + ], + } } } } @@ -449,26 +435,28 @@ impl Mul for Float4 { impl Mul for Float4 { type Output = Float4; - #[cfg(feature = "simd_perf")] #[inline(always)] fn mul(self, other: f32) -> Float4 { - Float4 { data: self.data * f32x4::splat(other) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - fn mul(self, other: f32) -> Float4 { - Float4 { - data: [ - self.get_0() * other, - self.get_1() * other, - self.get_2() * other, - self.get_3() * other, - ], + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data * f32x4::splat(other), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { + data: [ + self.get_0() * other, + self.get_1() * other, + self.get_2() * other, + self.get_3() * other, + ], + } } } } - impl MulAssign for Float4 { #[inline(always)] fn mul_assign(&mut self, rhs: Float4) { @@ -483,25 +471,27 @@ impl MulAssign for Float4 { } } - impl Div for Float4 { type Output = Float4; - #[cfg(feature = "simd_perf")] #[inline(always)] fn div(self, other: Float4) -> Float4 { - Float4 { data: self.data / other.data } - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - fn div(self, other: Float4) -> Float4 { - Float4 { - data: [ - self.get_0() / other.get_0(), - self.get_1() / other.get_1(), - self.get_2() / other.get_2(), - self.get_3() / other.get_3(), - ], + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data / other.data, + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { + data: [ + self.get_0() / other.get_0(), + self.get_1() / other.get_1(), + self.get_2() / other.get_2(), + self.get_3() / other.get_3(), + ], + } } } } @@ -509,26 +499,28 @@ impl Div for Float4 { impl Div for Float4 { type Output = Float4; - #[cfg(feature = "simd_perf")] #[inline(always)] fn div(self, other: f32) -> Float4 { - Float4 { data: self.data / f32x4::splat(other) } - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - fn div(self, other: f32) -> Float4 { - Float4 { - data: [ - self.get_0() / other, - self.get_1() / other, - self.get_2() / other, - self.get_3() / other, - ], + #[cfg(feature = "simd_perf")] + { + Float4 { + data: self.data / f32x4::splat(other), + } + } + #[cfg(not(feature = "simd_perf"))] + { + Float4 { + data: [ + self.get_0() / other, + self.get_1() / other, + self.get_2() / other, + self.get_3() / other, + ], + } } } } - impl DivAssign for Float4 { #[inline(always)] fn div_assign(&mut self, rhs: Float4) { @@ -553,7 +545,6 @@ pub fn v_max(a: Float4, b: Float4) -> Float4 { a.v_max(b) } - /// Essentially a tuple of four bools, which will use SIMD operations /// where possible on a platform. #[cfg(feature = "simd_perf")] @@ -569,84 +560,79 @@ pub struct Bool4 { } impl Bool4 { - /// Returns the value of the 0th element. - #[cfg(feature = "simd_perf")] + /// Returns the value of the nth element. #[inline(always)] - pub fn get_0(&self) -> bool { - self.data.extract(0) + pub fn get_n(&self, n: usize) -> bool { + 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"))] + { + unsafe { *self.data.get_unchecked(n) } + } } - #[cfg(not(feature = "simd_perf"))] + + /// Returns the value of the 0th element. #[inline(always)] pub fn get_0(&self) -> bool { - unsafe { *self.data.get_unchecked(0) } + self.get_n(0) } /// Returns the value of the 1th element. - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn get_1(&self) -> bool { - self.data.extract(1) - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn get_1(&self) -> bool { - unsafe { *self.data.get_unchecked(1) } + self.get_n(1) } /// Returns the value of the 2th element. - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn get_2(&self) -> bool { - self.data.extract(2) - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn get_2(&self) -> bool { - unsafe { *self.data.get_unchecked(2) } + self.get_n(2) } /// Returns the value of the 3th element. - #[cfg(feature = "simd_perf")] #[inline(always)] pub fn get_3(&self) -> bool { - self.data.extract(3) - } - #[cfg(not(feature = "simd_perf"))] - #[inline(always)] - pub fn get_3(&self) -> bool { - unsafe { *self.data.get_unchecked(3) } + self.get_n(3) } #[inline] 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_3() as u8) << 3) + (self.get_0() as u8) | ((self.get_1() as u8) << 1) | ((self.get_2() as u8) << 2) + | ((self.get_3() as u8) << 3) } } impl BitAnd for Bool4 { type Output = Bool4; - #[cfg(feature = "simd_perf")] #[inline(always)] fn bitand(self, rhs: Bool4) -> Bool4 { - Bool4 { data: self.data & rhs.data } - } - #[cfg(not(feature = "simd_perf"))] - #[inline] - fn bitand(self, rhs: Bool4) -> Bool4 { - Bool4 { - data: [ - self.data[0] && rhs.data[0], - self.data[1] && rhs.data[1], - self.data[2] && rhs.data[2], - self.data[3] && rhs.data[3], - ], + #[cfg(feature = "simd_perf")] + { + Bool4 { + data: self.data & rhs.data, + } + } + #[cfg(not(feature = "simd_perf"))] + { + Bool4 { + data: [ + self.data[0] && rhs.data[0], + self.data[1] && rhs.data[1], + self.data[2] && rhs.data[2], + self.data[3] && rhs.data[3], + ], + } } } } - #[cfg(test)] mod tests { use super::*;