1use crate::simd::SimdBool;
23/// Base trait for every SIMD types.
4pub trait SimdValue: Sized {
5/// The type of the elements of each lane of this SIMD value.
6type Element: SimdValue<Element = Self::Element, SimdBool = bool>;
7/// Type of the result of comparing two SIMD values like `self`.
8type SimdBool: SimdBool;
910/// The number of lanes of this SIMD value.
11fn lanes() -> usize;
12/// Initializes an SIMD value with each lanes set to `val`.
13fn splat(val: Self::Element) -> Self;
14/// Extracts the i-th lane of `self`.
15 ///
16 /// Panics if `i >= Self::lanes()`.
17fn extract(&self, i: usize) -> Self::Element;
18/// Extracts the i-th lane of `self` without bound-checking.
19unsafe fn extract_unchecked(&self, i: usize) -> Self::Element;
20/// Replaces the i-th lane of `self` by `val`.
21 ///
22 /// Panics if `i >= Self::lanes()`.
23fn replace(&mut self, i: usize, val: Self::Element);
24/// Replaces the i-th lane of `self` by `val` without bound-checking.
25unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element);
2627/// Merges `self` and `other` depending on the lanes of `cond`.
28 ///
29 /// For each lane of `cond` with bits set to 1, the result's will contain the value of the lane of `self`.
30 /// For each lane of `cond` with bits set to 0, the result's will contain the value of the lane of `other`.
31fn select(self, cond: Self::SimdBool, other: Self) -> Self;
3233/// Applies a function to each lane of `self`.
34 ///
35 /// Note that, while convenient, this method can be extremely slow as this
36 /// requires to extract each lane of `self` and then combine them again into
37 /// a new SIMD value.
38#[inline(always)]
39fn map_lanes(self, f: impl Fn(Self::Element) -> Self::Element) -> Self
40where
41Self: Clone,
42 {
43let mut result = self.clone();
4445for i in 0..Self::lanes() {
46unsafe { result.replace_unchecked(i, f(self.extract_unchecked(i))) }
47 }
4849 result
50 }
5152/// Applies a function to each lane of `self` paired with the corresponding lane of `b`.
53 ///
54 /// Note that, while convenient, this method can be extremely slow as this
55 /// requires to extract each lane of `self` and then combine them again into
56 /// a new SIMD value.
57#[inline(always)]
58fn zip_map_lanes(
59self,
60 b: Self,
61 f: impl Fn(Self::Element, Self::Element) -> Self::Element,
62 ) -> Self
63where
64Self: Clone,
65 {
66let mut result = self.clone();
6768for i in 0..Self::lanes() {
69unsafe {
70let a = self.extract_unchecked(i);
71let b = b.extract_unchecked(i);
72 result.replace_unchecked(i, f(a, b))
73 }
74 }
7576 result
77 }
78}
7980/// Marker trait implemented by SIMD and non-SIMD primitive numeric values.
81///
82/// This trait is useful for some disambiguations when writing blanked impls.
83/// This is implemented by all unsigned integer, integer, float, and complex types, as
84/// with only one lane, i.e., `f32`, `f64`, `u32`, `i64`, etc. as well as SIMD types like
85/// `f32x4, i32x8`, etc..
86pub trait PrimitiveSimdValue: Copy + SimdValue {}
8788impl<N: SimdValue> SimdValue for num_complex::Complex<N> {
89type Element = num_complex::Complex<N::Element>;
90type SimdBool = N::SimdBool;
9192#[inline(always)]
93fn lanes() -> usize {
94 N::lanes()
95 }
9697#[inline(always)]
98fn splat(val: Self::Element) -> Self {
99 num_complex::Complex {
100 re: N::splat(val.re),
101 im: N::splat(val.im),
102 }
103 }
104105#[inline(always)]
106fn extract(&self, i: usize) -> Self::Element {
107 num_complex::Complex {
108 re: self.re.extract(i),
109 im: self.im.extract(i),
110 }
111 }
112113#[inline(always)]
114unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
115 num_complex::Complex {
116 re: self.re.extract_unchecked(i),
117 im: self.im.extract_unchecked(i),
118 }
119 }
120121#[inline(always)]
122fn replace(&mut self, i: usize, val: Self::Element) {
123self.re.replace(i, val.re);
124self.im.replace(i, val.im);
125 }
126127#[inline(always)]
128unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
129self.re.replace_unchecked(i, val.re);
130self.im.replace_unchecked(i, val.im);
131 }
132133#[inline(always)]
134fn select(self, cond: Self::SimdBool, other: Self) -> Self {
135 num_complex::Complex {
136 re: self.re.select(cond, other.re),
137 im: self.im.select(cond, other.im),
138 }
139 }
140}
141142impl<N: PrimitiveSimdValue> PrimitiveSimdValue for num_complex::Complex<N> {}
143144macro_rules! impl_primitive_simd_value_for_scalar(
145 ($($t: ty),*) => {$(
146impl PrimitiveSimdValue for $t {}
147impl SimdValue for $t {
148type Element = $t;
149type SimdBool = bool;
150151#[inline(always)]
152fn lanes() -> usize {
1531
154}
155156#[inline(always)]
157fn splat(val: Self::Element) -> Self {
158 val
159 }
160161#[inline(always)]
162fn extract(&self, _: usize) -> Self::Element {
163*self
164}
165166#[inline(always)]
167unsafe fn extract_unchecked(&self, _: usize) -> Self::Element {
168*self
169}
170171#[inline(always)]
172fn replace(&mut self, _: usize, val: Self::Element) {
173*self = val
174 }
175176#[inline(always)]
177unsafe fn replace_unchecked(&mut self, _: usize, val: Self::Element) {
178*self = val
179 }
180181#[inline(always)]
182fn select(self, cond: Self::SimdBool, other: Self) -> Self {
183if cond {
184self
185} else {
186 other
187 }
188 }
189 }
190 )*}
191);
192193impl_primitive_simd_value_for_scalar!(
194 bool, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
195);
196#[cfg(feature = "decimal")]
197impl_primitive_simd_value_for_scalar!(decimal::d128);