vortex_array/arrays/chunked/compute/
is_constant.rs

1use vortex_error::{VortexExpect, VortexResult};
2
3use crate::Array;
4use crate::arrays::{ChunkedArray, ChunkedEncoding};
5use crate::compute::{IsConstantFn, IsConstantOpts, is_constant_opts, scalar_at};
6
7impl IsConstantFn<&ChunkedArray> for ChunkedEncoding {
8    fn is_constant(
9        &self,
10        array: &ChunkedArray,
11        opts: &IsConstantOpts,
12    ) -> VortexResult<Option<bool>> {
13        let mut chunks = array.chunks().iter().skip_while(|c| c.is_empty());
14
15        let first_chunk = chunks.next().vortex_expect("Must have at least one value");
16
17        if !is_constant_opts(first_chunk, opts)? {
18            return Ok(Some(false));
19        }
20
21        let first_value = scalar_at(first_chunk, 0)?.into_nullable();
22
23        for chunk in chunks {
24            if chunk.is_empty() {
25                continue;
26            }
27
28            if !is_constant_opts(chunk, opts)? {
29                return Ok(Some(false));
30            }
31
32            if first_value != scalar_at(chunk, 0)?.into_nullable() {
33                return Ok(Some(false));
34            }
35        }
36
37        Ok(Some(true))
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use vortex_buffer::{Buffer, buffer};
44    use vortex_dtype::{DType, Nullability, PType};
45
46    use crate::arrays::ChunkedArray;
47    use crate::{Array, IntoArray};
48
49    #[test]
50    fn empty_chunk_is_constant() {
51        let chunked = ChunkedArray::try_new(
52            vec![
53                Buffer::<u8>::empty().into_array(),
54                Buffer::<u8>::empty().into_array(),
55                buffer![255u8, 255].into_array(),
56                Buffer::<u8>::empty().into_array(),
57                buffer![255u8, 255].into_array(),
58            ],
59            DType::Primitive(PType::U8, Nullability::NonNullable),
60        )
61        .unwrap()
62        .into_array();
63
64        assert!(chunked.statistics().compute_is_constant().unwrap());
65    }
66}