simba/simd/
simd_option.rs

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