1use vortex_array::stats::{ArrayStats, StatsSetRef};
2use vortex_array::variants::PrimitiveArrayTrait;
3use vortex_array::vtable::VTableRef;
4use vortex_array::{
5 Array, ArrayCanonicalImpl, ArrayImpl, ArrayRef, ArrayStatisticsImpl, ArrayValidityImpl,
6 ArrayVariantsImpl, Canonical, EmptyMetadata, Encoding, ToCanonical, try_from_array_ref,
7};
8use vortex_dtype::{DType, PType};
9use vortex_error::{VortexResult, vortex_bail};
10use vortex_mask::Mask;
11
12use crate::zigzag_decode;
13
14#[derive(Clone, Debug)]
15pub struct ZigZagArray {
16 dtype: DType,
17 encoded: ArrayRef,
18 stats_set: ArrayStats,
19}
20
21try_from_array_ref!(ZigZagArray);
22
23#[derive(Debug)]
24pub struct ZigZagEncoding;
25impl Encoding for ZigZagEncoding {
26 type Array = ZigZagArray;
27 type Metadata = EmptyMetadata;
28}
29
30impl ZigZagArray {
31 pub fn try_new(encoded: ArrayRef) -> VortexResult<Self> {
32 let encoded_dtype = encoded.dtype().clone();
33 if !encoded_dtype.is_unsigned_int() {
34 vortex_bail!(MismatchedTypes: "unsigned int", encoded_dtype);
35 }
36
37 let dtype = DType::from(PType::try_from(&encoded_dtype)?.to_signed())
38 .with_nullability(encoded_dtype.nullability());
39
40 Ok(Self {
41 dtype,
42 encoded,
43 stats_set: Default::default(),
44 })
45 }
46
47 pub fn encoded(&self) -> &ArrayRef {
48 &self.encoded
49 }
50}
51
52impl ArrayImpl for ZigZagArray {
53 type Encoding = ZigZagEncoding;
54
55 fn _len(&self) -> usize {
56 self.encoded.len()
57 }
58
59 fn _dtype(&self) -> &DType {
60 &self.dtype
61 }
62
63 fn _vtable(&self) -> VTableRef {
64 VTableRef::new_ref(&ZigZagEncoding)
65 }
66
67 fn _with_children(&self, children: &[ArrayRef]) -> VortexResult<Self> {
68 let encoded = children[0].clone();
69
70 Self::try_new(encoded)
71 }
72}
73
74impl ArrayCanonicalImpl for ZigZagArray {
75 fn _to_canonical(&self) -> VortexResult<Canonical> {
76 zigzag_decode(self.encoded().to_primitive()?).map(Canonical::Primitive)
77 }
78}
79
80impl ArrayStatisticsImpl for ZigZagArray {
81 fn _stats_ref(&self) -> StatsSetRef<'_> {
82 self.stats_set.to_ref(self)
83 }
84}
85
86impl ArrayValidityImpl for ZigZagArray {
87 fn _is_valid(&self, index: usize) -> VortexResult<bool> {
88 self.encoded.is_valid(index)
89 }
90
91 fn _all_valid(&self) -> VortexResult<bool> {
92 self.encoded.all_valid()
93 }
94
95 fn _all_invalid(&self) -> VortexResult<bool> {
96 self.encoded.all_invalid()
97 }
98
99 fn _validity_mask(&self) -> VortexResult<Mask> {
100 self.encoded.validity_mask()
101 }
102}
103
104impl ArrayVariantsImpl for ZigZagArray {
105 fn _as_primitive_typed(&self) -> Option<&dyn PrimitiveArrayTrait> {
106 Some(self)
107 }
108}
109
110impl PrimitiveArrayTrait for ZigZagArray {}
111
112#[cfg(test)]
113mod test {
114 use vortex_array::IntoArray;
115 use vortex_array::compute::{scalar_at, slice};
116 use vortex_array::vtable::EncodingVTable;
117 use vortex_buffer::buffer;
118 use vortex_scalar::Scalar;
119
120 use super::*;
121
122 #[test]
123 fn test_compute_statistics() {
124 let array = buffer![1i32, -5i32, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_array();
125 let canonical = array.to_canonical().unwrap();
126 let zigzag = ZigZagEncoding.encode(&canonical, None).unwrap().unwrap();
127
128 assert_eq!(
129 zigzag.statistics().compute_max::<i32>(),
130 array.statistics().compute_max::<i32>()
131 );
132 assert_eq!(
133 zigzag.statistics().compute_null_count(),
134 array.statistics().compute_null_count()
135 );
136 assert_eq!(
137 zigzag.statistics().compute_is_constant(),
138 array.statistics().compute_is_constant()
139 );
140
141 let sliced = ZigZagArray::try_from(slice(&zigzag, 0, 2).unwrap()).unwrap();
142 assert_eq!(
143 scalar_at(&sliced, sliced.len() - 1).unwrap(),
144 Scalar::from(-5i32)
145 );
146
147 assert_eq!(
148 sliced.statistics().compute_min::<i32>(),
149 array.statistics().compute_min::<i32>()
150 );
151 assert_eq!(
152 sliced.statistics().compute_null_count(),
153 array.statistics().compute_null_count()
154 );
155 assert_eq!(
156 sliced.statistics().compute_is_constant(),
157 array.statistics().compute_is_constant()
158 );
159 }
160}