vortex_array/arrays/primitive/compute/
is_constant.rs1use vortex_dtype::half::f16;
2use vortex_dtype::{NativePType, match_each_native_ptype};
3use vortex_error::VortexResult;
4
5use crate::arrays::{PrimitiveArray, PrimitiveVTable};
6use crate::compute::{IsConstantKernel, IsConstantKernelAdapter, IsConstantOpts};
7use crate::register_kernel;
8
9cfg_if::cfg_if! {
10 if #[cfg(target_feature = "avx2")] {
11 pub const IS_CONST_LANE_WIDTH: usize = 32;
12 } else {
13 pub const IS_CONST_LANE_WIDTH: usize = 16;
14 }
15}
16
17impl IsConstantKernel for PrimitiveVTable {
18 fn is_constant(
19 &self,
20 array: &PrimitiveArray,
21 opts: &IsConstantOpts,
22 ) -> VortexResult<Option<bool>> {
23 if opts.is_negligible_cost() {
24 return Ok(None);
25 }
26 let is_constant = match_each_native_ptype!(array.ptype(), integral: |$P| {
27 compute_is_constant::<_, {IS_CONST_LANE_WIDTH / size_of::<$P>()}>(array.as_slice::<$P>())
28 } floating_point: |$P| {
29 compute_is_constant::<_, {IS_CONST_LANE_WIDTH / size_of::<$P>()}>(unsafe { std::mem::transmute::<&[$P], &[<$P as EqFloat>::IntType]>(array.as_slice::<$P>()) })
30 });
31
32 Ok(Some(is_constant))
33 }
34}
35
36register_kernel!(IsConstantKernelAdapter(PrimitiveVTable).lift());
37
38pub fn compute_is_constant<T: NativePType, const WIDTH: usize>(values: &[T]) -> bool {
41 let first_value = values[0];
42 let first_vec = &[first_value; WIDTH];
43
44 let mut chunks = values[1..].array_chunks::<WIDTH>();
45 for chunk in &mut chunks {
46 if first_vec != chunk {
47 return false;
48 }
49 }
50
51 for value in chunks.remainder() {
52 if !value.is_eq(first_value) {
53 return false;
54 }
55 }
56
57 true
58}
59
60trait EqFloat {
61 type IntType;
62}
63
64impl EqFloat for f16 {
65 type IntType = u16;
66}
67impl EqFloat for f32 {
68 type IntType = u32;
69}
70impl EqFloat for f64 {
71 type IntType = u64;
72}