1use num_traits::cast::FromPrimitive;
5use vortex_array::arrays::PrimitiveArray;
6use vortex_array::stats::{ArrayStats, StatsSetRef};
7use vortex_array::vtable::{
8 ArrayVTable, CanonicalVTable, NotSupported, OperationsVTable, VTable, ValidityVTable,
9 VisitorVTable,
10};
11use vortex_array::{
12 ArrayBufferVisitor, ArrayChildVisitor, ArrayRef, Canonical, EncodingId, EncodingRef, vtable,
13};
14use vortex_buffer::BufferMut;
15use vortex_dtype::{
16 DType, NativePType, Nullability, PType, match_each_integer_ptype, match_each_native_ptype,
17};
18use vortex_error::{VortexExpect, VortexResult, vortex_bail, vortex_err};
19use vortex_mask::Mask;
20use vortex_scalar::{PValue, Scalar, ScalarValue};
21
22vtable!(Sequence);
23
24#[derive(Clone, Debug)]
25pub struct SequenceArray {
27 base: PValue,
28 multiplier: PValue,
29 dtype: DType,
30 length: usize,
31 stats_set: ArrayStats,
32}
33
34impl SequenceArray {
35 pub fn typed_new<T: NativePType + Into<PValue>>(
36 base: T,
37 multiplier: T,
38 nullability: Nullability,
39 length: usize,
40 ) -> VortexResult<Self> {
41 Self::new(
42 base.into(),
43 multiplier.into(),
44 T::PTYPE,
45 nullability,
46 length,
47 )
48 }
49
50 pub fn new(
52 base: PValue,
53 multiplier: PValue,
54 ptype: PType,
55 nullability: Nullability,
56 length: usize,
57 ) -> VortexResult<Self> {
58 if !ptype.is_int() {
59 vortex_bail!("only integer ptype are supported in SequenceArray currently")
60 }
61
62 Self::try_last(base, multiplier, ptype, length).map_err(|e| {
63 e.with_context(format!(
64 "final value not expressible, base = {base:?}, multiplier = {multiplier:?}, len = {length} ",
65 ))
66 })?;
67
68 Ok(Self::unchecked_new(
69 base,
70 multiplier,
71 ptype,
72 nullability,
73 length,
74 ))
75 }
76
77 pub(crate) fn unchecked_new(
78 base: PValue,
79 multiplier: PValue,
80 ptype: PType,
81 nullability: Nullability,
82 length: usize,
83 ) -> Self {
84 let dtype = DType::Primitive(ptype, nullability);
85 Self {
86 base,
87 multiplier,
88 dtype,
89 length,
90 stats_set: Default::default(),
92 }
93 }
94
95 pub fn ptype(&self) -> PType {
96 self.dtype.as_ptype()
97 }
98
99 pub fn base(&self) -> PValue {
100 self.base
101 }
102
103 pub fn multiplier(&self) -> PValue {
104 self.multiplier
105 }
106
107 pub(crate) fn try_last(
108 base: PValue,
109 multiplier: PValue,
110 ptype: PType,
111 length: usize,
112 ) -> VortexResult<PValue> {
113 match_each_integer_ptype!(ptype, |P| {
114 let len_t = <P>::from_usize(length - 1)
115 .ok_or_else(|| vortex_err!("cannot convert length {} into {}", length, ptype))?;
116
117 let base = base.as_primitive::<P>();
118 let multiplier = multiplier.as_primitive::<P>();
119
120 let last = len_t
121 .checked_mul(multiplier)
122 .and_then(|offset| offset.checked_add(base))
123 .ok_or_else(|| vortex_err!("last value computation overflows"))?;
124 Ok(PValue::from(last))
125 })
126 }
127
128 fn index_value(&self, idx: usize) -> PValue {
129 assert!(idx < self.length, "index_value({idx}): index out of bounds");
130
131 match_each_native_ptype!(self.ptype(), |P| {
132 let base = self.base.as_primitive::<P>();
133 let multiplier = self.multiplier.as_primitive::<P>();
134 let value = base + (multiplier * <P>::from_usize(idx).vortex_expect("must fit"));
135
136 PValue::from(value)
137 })
138 }
139
140 pub fn last(&self) -> PValue {
142 Self::try_last(self.base, self.multiplier, self.ptype(), self.length)
143 .vortex_expect("validated array")
144 }
145
146 pub fn dtype(&self) -> &DType {
147 &self.dtype
148 }
149}
150
151impl VTable for SequenceVTable {
152 type Array = SequenceArray;
153 type Encoding = SequenceEncoding;
154
155 type ArrayVTable = Self;
156 type CanonicalVTable = Self;
157 type OperationsVTable = Self;
158 type ValidityVTable = Self;
159 type VisitorVTable = Self;
160 type ComputeVTable = NotSupported;
161 type EncodeVTable = Self;
162 type SerdeVTable = Self;
163
164 fn id(_encoding: &Self::Encoding) -> EncodingId {
165 EncodingId::new_ref("vortex.sequence")
166 }
167
168 fn encoding(_array: &Self::Array) -> EncodingRef {
169 EncodingRef::new_ref(SequenceEncoding.as_ref())
170 }
171}
172
173impl ArrayVTable<SequenceVTable> for SequenceVTable {
174 fn len(array: &SequenceArray) -> usize {
175 array.length
176 }
177
178 fn dtype(array: &SequenceArray) -> &DType {
179 &array.dtype
180 }
181
182 fn stats(array: &SequenceArray) -> StatsSetRef<'_> {
183 array.stats_set.to_ref(array.as_ref())
184 }
185}
186
187impl CanonicalVTable<SequenceVTable> for SequenceVTable {
188 fn canonicalize(array: &SequenceArray) -> VortexResult<Canonical> {
189 let prim = match_each_native_ptype!(array.ptype(), |P| {
190 let base = array.base().as_primitive::<P>();
191 let multiplier = array.multiplier().as_primitive::<P>();
192 let values = BufferMut::from_iter(
193 (0..array.len())
194 .map(|i| base + <P>::from_usize(i).vortex_expect("must fit") * multiplier),
195 );
196 PrimitiveArray::new(values, array.dtype.nullability().into())
197 });
198
199 Ok(Canonical::Primitive(prim))
200 }
201}
202
203impl OperationsVTable<SequenceVTable> for SequenceVTable {
204 fn slice(array: &SequenceArray, start: usize, stop: usize) -> ArrayRef {
205 SequenceArray::unchecked_new(
206 array.index_value(start),
207 array.multiplier,
208 array.ptype(),
209 array.dtype().nullability(),
210 stop - start,
211 )
212 .to_array()
213 }
214
215 fn scalar_at(array: &SequenceArray, index: usize) -> Scalar {
216 Scalar::new(
217 array.dtype().clone(),
218 ScalarValue::from(array.index_value(index)),
219 )
220 }
221}
222
223impl ValidityVTable<SequenceVTable> for SequenceVTable {
224 fn is_valid(_array: &SequenceArray, _index: usize) -> VortexResult<bool> {
225 Ok(true)
226 }
227
228 fn all_valid(_array: &SequenceArray) -> VortexResult<bool> {
229 Ok(true)
230 }
231
232 fn all_invalid(_array: &SequenceArray) -> VortexResult<bool> {
233 Ok(false)
234 }
235
236 fn validity_mask(array: &SequenceArray) -> VortexResult<Mask> {
237 Ok(Mask::AllTrue(array.len()))
238 }
239}
240
241impl VisitorVTable<SequenceVTable> for SequenceVTable {
242 fn visit_buffers(_array: &SequenceArray, _visitor: &mut dyn ArrayBufferVisitor) {
243 }
245
246 fn visit_children(_array: &SequenceArray, _visitor: &mut dyn ArrayChildVisitor) {}
247}
248
249#[derive(Clone, Debug)]
250pub struct SequenceEncoding;
251
252#[cfg(test)]
253mod tests {
254 use vortex_array::arrays::PrimitiveArray;
255 use vortex_dtype::Nullability;
256 use vortex_scalar::{Scalar, ScalarValue};
257
258 use crate::array::SequenceArray;
259
260 #[test]
261 fn test_sequence_canonical() {
262 let arr = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4).unwrap();
263
264 let canon = PrimitiveArray::from_iter((0..4).map(|i| 2i64 + i * 3));
265
266 assert_eq!(
267 arr.to_canonical()
268 .unwrap()
269 .into_primitive()
270 .unwrap()
271 .as_slice::<i64>(),
272 canon.as_slice::<i64>()
273 )
274 }
275
276 #[test]
277 fn test_sequence_slice_canonical() {
278 let arr = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4)
279 .unwrap()
280 .slice(2, 3);
281
282 let canon = PrimitiveArray::from_iter((2..3).map(|i| 2i64 + i * 3));
283
284 assert_eq!(
285 arr.to_canonical()
286 .unwrap()
287 .into_primitive()
288 .unwrap()
289 .as_slice::<i64>(),
290 canon.as_slice::<i64>()
291 )
292 }
293
294 #[test]
295 fn test_sequence_scalar_at() {
296 let scalar = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4)
297 .unwrap()
298 .scalar_at(2);
299
300 assert_eq!(
301 scalar,
302 Scalar::new(scalar.dtype().clone(), ScalarValue::from(8i64))
303 )
304 }
305
306 #[test]
307 fn test_sequence_min_max() {
308 assert!(SequenceArray::typed_new(-127i8, -1i8, Nullability::NonNullable, 2).is_ok());
309 assert!(SequenceArray::typed_new(126i8, -1i8, Nullability::NonNullable, 2).is_ok());
310 }
311
312 #[test]
313 fn test_sequence_too_big() {
314 assert!(SequenceArray::typed_new(127i8, 1i8, Nullability::NonNullable, 2).is_err());
315 assert!(SequenceArray::typed_new(-128i8, -1i8, Nullability::NonNullable, 2).is_err());
316 }
317}