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 type PipelineVTable = NotSupported;
164
165 fn id(_encoding: &Self::Encoding) -> EncodingId {
166 EncodingId::new_ref("vortex.sequence")
167 }
168
169 fn encoding(_array: &Self::Array) -> EncodingRef {
170 EncodingRef::new_ref(SequenceEncoding.as_ref())
171 }
172}
173
174impl ArrayVTable<SequenceVTable> for SequenceVTable {
175 fn len(array: &SequenceArray) -> usize {
176 array.length
177 }
178
179 fn dtype(array: &SequenceArray) -> &DType {
180 &array.dtype
181 }
182
183 fn stats(array: &SequenceArray) -> StatsSetRef<'_> {
184 array.stats_set.to_ref(array.as_ref())
185 }
186}
187
188impl CanonicalVTable<SequenceVTable> for SequenceVTable {
189 fn canonicalize(array: &SequenceArray) -> VortexResult<Canonical> {
190 let prim = match_each_native_ptype!(array.ptype(), |P| {
191 let base = array.base().as_primitive::<P>();
192 let multiplier = array.multiplier().as_primitive::<P>();
193 let values = BufferMut::from_iter(
194 (0..array.len())
195 .map(|i| base + <P>::from_usize(i).vortex_expect("must fit") * multiplier),
196 );
197 PrimitiveArray::new(values, array.dtype.nullability().into())
198 });
199
200 Ok(Canonical::Primitive(prim))
201 }
202}
203
204impl OperationsVTable<SequenceVTable> for SequenceVTable {
205 fn slice(array: &SequenceArray, start: usize, stop: usize) -> ArrayRef {
206 SequenceArray::unchecked_new(
207 array.index_value(start),
208 array.multiplier,
209 array.ptype(),
210 array.dtype().nullability(),
211 stop - start,
212 )
213 .to_array()
214 }
215
216 fn scalar_at(array: &SequenceArray, index: usize) -> Scalar {
217 Scalar::new(
218 array.dtype().clone(),
219 ScalarValue::from(array.index_value(index)),
220 )
221 }
222}
223
224impl ValidityVTable<SequenceVTable> for SequenceVTable {
225 fn is_valid(_array: &SequenceArray, _index: usize) -> VortexResult<bool> {
226 Ok(true)
227 }
228
229 fn all_valid(_array: &SequenceArray) -> VortexResult<bool> {
230 Ok(true)
231 }
232
233 fn all_invalid(_array: &SequenceArray) -> VortexResult<bool> {
234 Ok(false)
235 }
236
237 fn validity_mask(array: &SequenceArray) -> VortexResult<Mask> {
238 Ok(Mask::AllTrue(array.len()))
239 }
240}
241
242impl VisitorVTable<SequenceVTable> for SequenceVTable {
243 fn visit_buffers(_array: &SequenceArray, _visitor: &mut dyn ArrayBufferVisitor) {
244 }
246
247 fn visit_children(_array: &SequenceArray, _visitor: &mut dyn ArrayChildVisitor) {}
248}
249
250#[derive(Clone, Debug)]
251pub struct SequenceEncoding;
252
253#[cfg(test)]
254mod tests {
255 use vortex_array::arrays::PrimitiveArray;
256 use vortex_dtype::Nullability;
257 use vortex_scalar::{Scalar, ScalarValue};
258
259 use crate::array::SequenceArray;
260
261 #[test]
262 fn test_sequence_canonical() {
263 let arr = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4).unwrap();
264
265 let canon = PrimitiveArray::from_iter((0..4).map(|i| 2i64 + i * 3));
266
267 assert_eq!(
268 arr.to_canonical()
269 .unwrap()
270 .into_primitive()
271 .unwrap()
272 .as_slice::<i64>(),
273 canon.as_slice::<i64>()
274 )
275 }
276
277 #[test]
278 fn test_sequence_slice_canonical() {
279 let arr = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4)
280 .unwrap()
281 .slice(2, 3);
282
283 let canon = PrimitiveArray::from_iter((2..3).map(|i| 2i64 + i * 3));
284
285 assert_eq!(
286 arr.to_canonical()
287 .unwrap()
288 .into_primitive()
289 .unwrap()
290 .as_slice::<i64>(),
291 canon.as_slice::<i64>()
292 )
293 }
294
295 #[test]
296 fn test_sequence_scalar_at() {
297 let scalar = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4)
298 .unwrap()
299 .scalar_at(2);
300
301 assert_eq!(
302 scalar,
303 Scalar::new(scalar.dtype().clone(), ScalarValue::from(8i64))
304 )
305 }
306
307 #[test]
308 fn test_sequence_min_max() {
309 assert!(SequenceArray::typed_new(-127i8, -1i8, Nullability::NonNullable, 2).is_ok());
310 assert!(SequenceArray::typed_new(126i8, -1i8, Nullability::NonNullable, 2).is_ok());
311 }
312
313 #[test]
314 fn test_sequence_too_big() {
315 assert!(SequenceArray::typed_new(127i8, 1i8, Nullability::NonNullable, 2).is_err());
316 assert!(SequenceArray::typed_new(-128i8, -1i8, Nullability::NonNullable, 2).is_err());
317 }
318}