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}