simba/simd/simd_option.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
use crate::simd::{SimdBool, SimdValue};
//pub trait SimdOption {
// type SimdValue: SimdValue;
//
// fn simd_unwrap(self) -> Self::SimdValue;
// fn simd_unwrap_or(self, other: impl FnOnce() -> Self::SimdValue) -> Self::SimdValue;
//}
//impl<T: SimdValue> SimdOption for Option<T> {
// type SimdValue = T;
//
// #[inline(always)]
// fn simd_unwrap(self) -> T {
// self.unwrap()
// }
//
// #[inline(always)]
// fn simd_unwrap_or(self, other: impl FnOnce() -> Self::SimdValue) -> Self::SimdValue {
// self.unwrap_or_else(other)
// }
//}
/// Generalization of Option for SIMD computation.
pub struct SimdOption<V: SimdValue> {
val: V,
mask: V::SimdBool,
}
impl<V: SimdValue> SimdOption<V> {
/// Creates a new SIMD option by combining a value and a mask indicating what lane of the value is valid.
pub fn new(val: V, mask: V::SimdBool) -> Self {
SimdOption { val, mask }
}
/// Return the underlying SIMD boolean mask.
pub fn mask(&self) -> V::SimdBool {
self.mask
}
/// Return the underlying unfiltered value.
pub fn value(&self) -> &V {
&self.val
}
/// Converts this SIMD option to a strandard Option.
///
/// If all the bits of `self.mask` are 1, then this returns `Some(self.value())`.
/// If any bit of `self.mask` is 0, then this returns `None`.
pub fn option(self) -> Option<V> {
if self.mask.all() {
Some(self.val)
} else {
None
}
}
/// Retrieve the underlying value if all the bits of `self.mask` are 1.
///
/// Panics if any of the bits of `self.mask` is 0.
#[inline]
pub fn simd_unwrap(self) -> V {
assert!(
self.mask.all(),
"Attempt to unwrap an SIMD value with at least one false lane."
);
self.val
}
/// Merges the value of `self` with the value of `other`.
///
/// Each lane of the result with a corresponding bit mask set to 1 will be filled with the corresponding lanes of `self.value()`.
/// The lanes of the result with a corresponding bit mask set to 0 will be filled with the corresponding lanes of `other()`.
///
/// The function in `other` should not do any side-effect. Indeed, implementors of this trait are free to decide in what
/// cases `other` is called or not.
#[inline(always)]
pub fn simd_unwrap_or(self, other: impl FnOnce() -> V) -> V {
self.val.select(self.mask, other())
}
}