1include!(concat!(env!("OUT_DIR"), "/simd_lanes.rs"));
36
37#[cfg(feature = "datetime")]
38use crate::DatetimeAVT;
39#[cfg(feature = "datetime")]
40use crate::DatetimeArray;
41use crate::enums::error::KernelError;
42use crate::enums::operators::ArithmeticOperator::{self};
43#[cfg(feature = "simd")]
44use crate::kernels::arithmetic::simd::{
45 float_dense_body_f32_simd, float_dense_body_f64_simd, float_masked_body_f32_simd,
46 float_masked_body_f64_simd, fma_dense_body_f32_simd, fma_dense_body_f64_simd,
47 fma_masked_body_f32_simd, fma_masked_body_f64_simd, int_dense_body_simd, int_masked_body_simd,
48};
49use crate::kernels::arithmetic::std::{
50 float_dense_body_std, float_masked_body_std, int_dense_body_std, int_masked_body_std,
51};
52#[cfg(feature = "datetime")]
53use crate::kernels::bitmask::merge_bitmasks_to_new;
54use crate::structs::variants::float::FloatArray;
55use crate::structs::variants::integer::IntegerArray;
56use crate::utils::confirm_equal_len;
57#[cfg(feature = "simd")]
58use crate::utils::is_simd_aligned;
59use crate::{Bitmask, Vec64};
60macro_rules! impl_apply_int {
66 ($fn_name:ident, $ty:ty, $lanes:expr) => {
67 #[doc = concat!(
68 "Performs element-wise integer `ArithmeticOperator` over two `&[", stringify!($ty),
69 "]`, SIMD-accelerated using ", stringify!($lanes), " lanes if available, \
70 otherwise falls back to scalar. \
71 Returns `IntegerArray<", stringify!($ty), ">` with appropriate null-mask handling."
72 )]
73 #[inline(always)]
74 pub fn $fn_name(
75 lhs: &[$ty],
76 rhs: &[$ty],
77 op: ArithmeticOperator,
78 mask: Option<&Bitmask>
79 ) -> Result<IntegerArray<$ty>, KernelError> {
80 let len = lhs.len();
81 confirm_equal_len("apply numeric: length mismatch", len, rhs.len())?;
82
83 #[cfg(feature = "simd")]
84 {
85 if is_simd_aligned(lhs) && is_simd_aligned(rhs) {
87 let mut out = Vec64::with_capacity(len);
89 unsafe { out.set_len(len) };
90 match mask {
91 Some(mask) => {
92 let mut out_mask = crate::Bitmask::new_set_all(len, true);
93 int_masked_body_simd::<$ty, $lanes>(op, lhs, rhs, mask, &mut out, &mut out_mask);
94 return Ok(IntegerArray {
95 data: out.into(),
96 null_mask: Some(out_mask),
97 });
98 }
99 None => {
100 int_dense_body_simd::<$ty, $lanes>(op, lhs, rhs, &mut out);
101 return Ok(IntegerArray {
102 data: out.into(),
103 null_mask: None,
104 });
105 }
106 }
107 }
108 }
110
111 let mut out = Vec64::with_capacity(len);
113 unsafe { out.set_len(len) };
114 match mask {
115 Some(mask) => {
116 let mut out_mask = crate::Bitmask::new_set_all(len, true);
117 int_masked_body_std::<$ty>(op, lhs, rhs, mask, &mut out, &mut out_mask);
118 Ok(IntegerArray {
119 data: out.into(),
120 null_mask: Some(out_mask),
121 })
122 }
123 None => {
124 int_dense_body_std::<$ty>(op, lhs, rhs, &mut out);
125 Ok(IntegerArray {
126 data: out.into(),
127 null_mask: None,
128 })
129 }
130 }
131 }
132 };
133}
134
135macro_rules! impl_apply_float {
139 ($fn_name:ident, $ty:ty, $lanes:expr, $dense_body_simd:ident, $masked_body_simd:ident) => {
140 #[doc = concat!(
141 "Performs element-wise float `ArithmeticOperator` on `&[", stringify!($ty),
142 "]` using SIMD (", stringify!($lanes), " lanes) for dense/masked cases, \
143 Falls back to standard scalar ops when the `simd` feature is not enabled. \
144 Returns `FloatArray<", stringify!($ty), ">` and handles optional null-mask."
145 )]
146 #[inline(always)]
147 pub fn $fn_name(
148 lhs: &[$ty],
149 rhs: &[$ty],
150 op: ArithmeticOperator,
151 mask: Option<&Bitmask>
152 ) -> Result<FloatArray<$ty>, KernelError> {
153 let len = lhs.len();
154 confirm_equal_len("apply numeric: length mismatch", len, rhs.len())?;
155
156 #[cfg(feature = "simd")]
157 {
158 if is_simd_aligned(lhs) && is_simd_aligned(rhs) {
160 let mut out = Vec64::with_capacity(len);
162 unsafe { out.set_len(len) };
163 match mask {
164 Some(mask) => {
165 let mut out_mask = crate::Bitmask::new_set_all(len, true);
166 $masked_body_simd::<$lanes>(op, lhs, rhs, mask, &mut out, &mut out_mask);
167 return Ok(FloatArray {
168 data: out.into(),
169 null_mask: Some(out_mask),
170 });
171 }
172 None => {
173 $dense_body_simd::<$lanes>(op, lhs, rhs, &mut out);
174 return Ok(FloatArray {
175 data: out.into(),
176 null_mask: None,
177 });
178 }
179 }
180 }
181 }
183
184 let mut out = Vec64::with_capacity(len);
186 unsafe { out.set_len(len) };
187 match mask {
188 Some(mask) => {
189 let mut out_mask = crate::Bitmask::new_set_all(len, true);
190 float_masked_body_std::<$ty>(op, lhs, rhs, mask, &mut out, &mut out_mask);
191 Ok(FloatArray {
192 data: out.into(),
193 null_mask: Some(out_mask),
194 })
195 }
196 None => {
197 float_dense_body_std::<$ty>(op, lhs, rhs, &mut out);
198 Ok(FloatArray {
199 data: out.into(),
200 null_mask: None,
201 })
202 }
203 }
204 }
205 };
206}
207
208macro_rules! impl_apply_fma_float {
212 ($fn_name:ident, $ty:ty, $lanes:expr, $dense_simd:ident, $masked_simd:ident) => {
213 #[doc = concat!(
214 "Performs element-wise fused multiply-add (`a * b + acc`) on `&[", stringify!($ty),
215 "]` using SIMD (", stringify!($lanes), " lanes; dense or masked, via `",
216 stringify!($dense), "`/`", stringify!($masked), "` as needed. \
217 Falls back to standard scalar ops when the `simd` feature is not enabled. \
218 Results in a `FloatArray<", stringify!($ty), ">`."
219 )]
220 #[inline(always)]
221 pub fn $fn_name(
222 lhs: &[$ty],
223 rhs: &[$ty],
224 acc: &[$ty],
225 mask: Option<&Bitmask>
226 ) -> Result<FloatArray<$ty>, KernelError> {
227 let len = lhs.len();
228 confirm_equal_len("apply numeric: length mismatch", len, rhs.len())?;
229 confirm_equal_len("acc length mismatch", len, acc.len())?;
230
231 let mut out = Vec64::with_capacity(len);
232 unsafe { out.set_len(len) };
233 let mut out_mask = crate::Bitmask::new_set_all(len, true);
234
235 #[cfg(feature = "simd")]
236 {
237 if is_simd_aligned(lhs) && is_simd_aligned(rhs) && is_simd_aligned(acc) {
239 match mask {
241 Some(mask) => {
242 $masked_simd::<$lanes>(lhs, rhs, acc, mask, &mut out, &mut out_mask);
243 return Ok(FloatArray {
244 data: out.into(),
245 null_mask: Some(out_mask),
246 });
247 }
248 None => {
249 $dense_simd::<$lanes>(lhs, rhs, acc, &mut out);
250 return Ok(FloatArray {
251 data: out.into(),
252 null_mask: None,
253 });
254 }
255 }
256 }
257 }
259
260 match mask {
262 Some(mask) => {
263 for i in 0..len {
265 if unsafe { mask.get_unchecked(i) } {
266 out[i] = lhs[i] * rhs[i] + acc[i];
267 } else {
268 out[i] = 0 as $ty; out_mask.set(i, false);
270 }
271 }
272 Ok(FloatArray {
273 data: out.into(),
274 null_mask: Some(out_mask),
275 })
276 }
277 None => {
278 for i in 0..len {
280 out[i] = lhs[i] * rhs[i] + acc[i];
281 }
282 Ok(FloatArray {
283 data: out.into(),
284 null_mask: None,
285 })
286 }
287 }
288 }
289 };
290}
291
292#[cfg(feature = "datetime")]
309macro_rules! impl_apply_datetime {
310 ($fn_name:ident, $ty:ty, $lanes:expr) => {
311 #[inline(always)]
312 pub fn $fn_name(
313 lhs: DatetimeAVT<$ty>,
314 rhs: DatetimeAVT<$ty>,
315 op: ArithmeticOperator,
316 ) -> Result<DatetimeArray<$ty>, KernelError> {
317 let (larr, loff, llen) = lhs;
318 let (rarr, roff, rlen) = rhs;
319 confirm_equal_len("apply_datetime: length mismatch", llen, rlen)?;
320
321 let out_mask =
322 merge_bitmasks_to_new(larr.null_mask.as_ref(), rarr.null_mask.as_ref(), llen);
323 let ldata = &larr.data[loff..loff + llen];
324 let rdata = &rarr.data[roff..roff + rlen];
325
326 let mut out = Vec64::<$ty>::with_capacity(llen);
327 unsafe {
328 out.set_len(llen);
329 }
330
331 match out_mask.as_ref() {
332 Some(mask) => {
333 let mut result_mask = crate::Bitmask::new_set_all(llen, true);
334 #[cfg(feature = "simd")]
335 {
336 int_masked_body_simd::<$ty, $lanes>(
337 op,
338 ldata,
339 rdata,
340 mask,
341 &mut out,
342 &mut result_mask,
343 );
344 }
345 #[cfg(not(feature = "simd"))]
346 {
347 int_masked_body_std::<$ty>(
348 op,
349 ldata,
350 rdata,
351 mask,
352 &mut out,
353 &mut result_mask,
354 );
355 }
356 Ok(DatetimeArray::from_vec64(out, Some(result_mask), None))
357 }
358 None => {
359 #[cfg(feature = "simd")]
360 {
361 int_dense_body_simd::<$ty, $lanes>(op, ldata, rdata, &mut out);
362 }
363 #[cfg(not(feature = "simd"))]
364 {
365 int_dense_body_std::<$ty>(op, ldata, rdata, &mut out);
366 }
367 Ok(DatetimeArray::from_vec64(out, None, None))
368 }
369 }
370 }
371 };
372}
373
374impl_apply_int!(apply_int_i32, i32, W32);
377impl_apply_int!(apply_int_u32, u32, W32);
378impl_apply_int!(apply_int_i64, i64, W64);
379impl_apply_int!(apply_int_u64, u64, W64);
380#[cfg(feature = "extended_numeric_types")]
381impl_apply_int!(apply_int_i16, i16, W16);
382#[cfg(feature = "extended_numeric_types")]
383impl_apply_int!(apply_int_u16, u16, W16);
384#[cfg(feature = "extended_numeric_types")]
385impl_apply_int!(apply_int_i8, i8, W8);
386#[cfg(feature = "extended_numeric_types")]
387impl_apply_int!(apply_int_u8, u8, W8);
388
389impl_apply_float!(
390 apply_float_f32,
391 f32,
392 W32,
393 float_dense_body_f32_simd,
394 float_masked_body_f32_simd
395);
396impl_apply_float!(
397 apply_float_f64,
398 f64,
399 W64,
400 float_dense_body_f64_simd,
401 float_masked_body_f64_simd
402);
403
404impl_apply_fma_float!(
405 apply_fma_f32,
406 f32,
407 W32,
408 fma_dense_body_f32_simd,
409 fma_masked_body_f32_simd
410);
411
412impl_apply_fma_float!(
413 apply_fma_f64,
414 f64,
415 W64,
416 fma_dense_body_f64_simd,
417 fma_masked_body_f64_simd
418);
419
420#[cfg(feature = "datetime")]
421impl_apply_datetime!(apply_datetime_i32, i32, W32);
422#[cfg(feature = "datetime")]
423impl_apply_datetime!(apply_datetime_u32, u32, W32);
424#[cfg(feature = "datetime")]
425impl_apply_datetime!(apply_datetime_i64, i64, W64);
426#[cfg(feature = "datetime")]
427impl_apply_datetime!(apply_datetime_u64, u64, W64);