• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16277982668

14 Jul 2025 09:12PM UTC coverage: 81.564% (+0.4%) from 81.147%
16277982668

Pull #3852

github

web-flow
Merge e78f6e62e into b0be264bf
Pull Request #3852: feat: call optimize in compressor

3 of 3 new or added lines in 1 file covered. (100.0%)

381 existing lines in 36 files now uncovered.

46289 of 56752 relevant lines covered (81.56%)

157514.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.02
/encodings/sequence/src/array.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use num_traits::cast::FromPrimitive;
5
use vortex_array::arrays::PrimitiveArray;
6
use vortex_array::stats::{ArrayStats, StatsSetRef};
7
use vortex_array::vtable::{
8
    ArrayVTable, CanonicalVTable, NotSupported, OperationsVTable, VTable, ValidityVTable,
9
    VisitorVTable,
10
};
11
use vortex_array::{
12
    ArrayBufferVisitor, ArrayChildVisitor, ArrayRef, Canonical, EncodingId, EncodingRef, vtable,
13
};
14
use vortex_buffer::BufferMut;
15
use vortex_dtype::{
16
    DType, NativePType, Nullability, PType, match_each_integer_ptype, match_each_native_ptype,
17
};
18
use vortex_error::{VortexExpect, VortexResult, vortex_bail, vortex_err};
19
use vortex_mask::Mask;
20
use vortex_scalar::{PValue, Scalar, ScalarValue};
21

22
vtable!(Sequence);
23

24
#[derive(Clone, Debug)]
25
/// An array representing the equation `A[i] = base + i * multiplier`.
26
pub struct SequenceArray {
27
    base: PValue,
28
    multiplier: PValue,
29
    dtype: DType,
30
    length: usize,
31
    stats_set: ArrayStats,
32
}
33

34
impl SequenceArray {
35
    pub fn typed_new<T: NativePType + Into<PValue>>(
16,822✔
36
        base: T,
16,822✔
37
        multiplier: T,
16,822✔
38
        nullability: Nullability,
16,822✔
39
        length: usize,
16,822✔
40
    ) -> VortexResult<Self> {
16,822✔
41
        Self::new(
16,822✔
42
            base.into(),
16,822✔
43
            multiplier.into(),
16,822✔
44
            T::PTYPE,
16,822✔
45
            nullability,
16,822✔
46
            length,
16,822✔
47
        )
16,822✔
48
    }
16,822✔
49

50
    /// Constructs a sequence array using two integer values (with the same ptype).
51
    pub fn new(
16,866✔
52
        base: PValue,
16,866✔
53
        multiplier: PValue,
16,866✔
54
        ptype: PType,
16,866✔
55
        nullability: Nullability,
16,866✔
56
        length: usize,
16,866✔
57
    ) -> VortexResult<Self> {
16,866✔
58
        if !ptype.is_int() {
16,866✔
UNCOV
59
            vortex_bail!("only integer ptype are supported in SequenceArray currently")
×
60
        }
16,866✔
61

16,866✔
62
        Self::try_last(base, multiplier, ptype, length).map_err(|e| {
16,866✔
63
            e.with_context(format!(
2✔
64
                "final value not expressible, base = {:?}, multiplier = {:?}, len = {} ",
2✔
65
                base, multiplier, length
2✔
66
            ))
2✔
67
        })?;
16,866✔
68

69
        Ok(Self::unchecked_new(
16,864✔
70
            base,
16,864✔
71
            multiplier,
16,864✔
72
            ptype,
16,864✔
73
            nullability,
16,864✔
74
            length,
16,864✔
75
        ))
16,864✔
76
    }
16,866✔
77

78
    pub(crate) fn unchecked_new(
17,371✔
79
        base: PValue,
17,371✔
80
        multiplier: PValue,
17,371✔
81
        ptype: PType,
17,371✔
82
        nullability: Nullability,
17,371✔
83
        length: usize,
17,371✔
84
    ) -> Self {
17,371✔
85
        let dtype = DType::Primitive(ptype, nullability);
17,371✔
86
        Self {
17,371✔
87
            base,
17,371✔
88
            multiplier,
17,371✔
89
            dtype,
17,371✔
90
            length,
17,371✔
91
            // TODO(joe): add stats, on construct or on use?
17,371✔
92
            stats_set: Default::default(),
17,371✔
93
        }
17,371✔
94
    }
17,371✔
95

96
    pub fn ptype(&self) -> PType {
866✔
97
        self.dtype.as_ptype()
866✔
98
    }
866✔
99

100
    pub fn base(&self) -> PValue {
1,131✔
101
        self.base
1,131✔
102
    }
1,131✔
103

104
    pub fn multiplier(&self) -> PValue {
1,130✔
105
        self.multiplier
1,130✔
106
    }
1,130✔
107

108
    pub(crate) fn try_last(
27,059✔
109
        base: PValue,
27,059✔
110
        multiplier: PValue,
27,059✔
111
        ptype: PType,
27,059✔
112
        length: usize,
27,059✔
113
    ) -> VortexResult<PValue> {
27,059✔
114
        match_each_integer_ptype!(ptype, |P| {
27,059✔
115
            let len_t = <P>::from_usize(length - 1)
1,732✔
116
                .ok_or_else(|| vortex_err!("cannot convert length {} into {}", length, ptype))?;
1,732✔
117

118
            let base = base.as_primitive::<P>()?;
1,660✔
119
            let multiplier = multiplier.as_primitive::<P>()?;
1,660✔
120

121
            let last = len_t
1,660✔
122
                .checked_mul(multiplier)
1,660✔
123
                .and_then(|offset| offset.checked_add(base))
26,875✔
124
                .ok_or_else(|| vortex_err!("last value computation overflows"))?;
1,660✔
125
            Ok(PValue::from(last))
1,660✔
126
        })
127
    }
27,059✔
128

129
    fn index_value(&self, idx: usize) -> VortexResult<PValue> {
236✔
130
        if idx > self.length {
236✔
UNCOV
131
            vortex_bail!("out of bounds")
×
132
        }
236✔
133
        match_each_native_ptype!(self.ptype(), |P| {
236✔
134
            let base = self.base.as_primitive::<P>()?;
2✔
135
            let multiplier = self.multiplier.as_primitive::<P>()?;
2✔
136
            let value = base + (multiplier * <P>::from_usize(idx).vortex_expect("must fit"));
2✔
137

2✔
138
            Ok(PValue::from(value))
2✔
139
        })
140
    }
236✔
141

142
    /// Returns the validated final value of a sequence array
143
    pub fn last(&self) -> PValue {
1✔
144
        Self::try_last(self.base, self.multiplier, self.ptype(), self.length)
1✔
145
            .vortex_expect("validated array")
1✔
146
    }
1✔
147
}
148

149
impl VTable for SequenceVTable {
150
    type Array = SequenceArray;
151
    type Encoding = SequenceEncoding;
152

153
    type ArrayVTable = Self;
154
    type CanonicalVTable = Self;
155
    type OperationsVTable = Self;
156
    type ValidityVTable = Self;
157
    type VisitorVTable = Self;
158
    type ComputeVTable = NotSupported;
159
    type EncodeVTable = Self;
160
    type SerdeVTable = Self;
161

162
    fn id(_encoding: &Self::Encoding) -> EncodingId {
12,723✔
163
        EncodingId::new_ref("vortex.sequence")
12,723✔
164
    }
12,723✔
165

166
    fn encoding(_array: &Self::Array) -> EncodingRef {
6,236✔
167
        EncodingRef::new_ref(SequenceEncoding.as_ref())
6,236✔
168
    }
6,236✔
169
}
170

171
impl ArrayVTable<SequenceVTable> for SequenceVTable {
172
    fn len(array: &SequenceArray) -> usize {
8,959✔
173
        array.length
8,959✔
174
    }
8,959✔
175

176
    fn dtype(array: &SequenceArray) -> &DType {
8,243✔
177
        &array.dtype
8,243✔
178
    }
8,243✔
179

180
    fn stats(array: &SequenceArray) -> StatsSetRef<'_> {
3,429✔
181
        array.stats_set.to_ref(array.as_ref())
3,429✔
182
    }
3,429✔
183
}
184

185
impl CanonicalVTable<SequenceVTable> for SequenceVTable {
186
    fn canonicalize(array: &SequenceArray) -> VortexResult<Canonical> {
596✔
187
        let prim = match_each_native_ptype!(array.ptype(), |P| {
596✔
188
            let base = array.base().as_primitive::<P>()?;
52✔
189
            let multiplier = array.multiplier().as_primitive::<P>()?;
52✔
190
            let values = BufferMut::from_iter(
52✔
191
                (0..array.len())
52✔
192
                    .map(|i| base + <P>::from_usize(i).vortex_expect("must fit") * multiplier),
2,593,080✔
193
            );
52✔
194
            PrimitiveArray::new(values, array.dtype.nullability().into())
52✔
195
        });
196

197
        Ok(Canonical::Primitive(prim))
596✔
198
    }
596✔
199
}
200

201
impl OperationsVTable<SequenceVTable> for SequenceVTable {
202
    fn slice(array: &SequenceArray, start: usize, stop: usize) -> VortexResult<ArrayRef> {
33✔
203
        Ok(SequenceArray::unchecked_new(
33✔
204
            array.index_value(start)?,
33✔
205
            array.multiplier,
33✔
206
            array.ptype(),
33✔
207
            array.dtype().nullability(),
33✔
208
            stop - start,
33✔
209
        )
33✔
210
        .to_array())
33✔
211
    }
33✔
212

213
    fn scalar_at(array: &SequenceArray, index: usize) -> VortexResult<Scalar> {
203✔
214
        // Ok(Scalar::from(array.index_value(index)))
203✔
215
        Ok(Scalar::new(
203✔
216
            array.dtype().clone(),
203✔
217
            ScalarValue::from(array.index_value(index)?),
203✔
218
        ))
219
    }
203✔
220
}
221

222
impl ValidityVTable<SequenceVTable> for SequenceVTable {
223
    fn is_valid(_array: &SequenceArray, _index: usize) -> VortexResult<bool> {
203✔
224
        Ok(true)
203✔
225
    }
203✔
226

227
    fn all_valid(_array: &SequenceArray) -> VortexResult<bool> {
722✔
228
        Ok(true)
722✔
229
    }
722✔
230

231
    fn all_invalid(_array: &SequenceArray) -> VortexResult<bool> {
816✔
232
        Ok(false)
816✔
233
    }
816✔
234

235
    fn validity_mask(array: &SequenceArray) -> VortexResult<Mask> {
101✔
236
        Ok(Mask::AllTrue(array.len()))
101✔
237
    }
101✔
238
}
239

240
impl VisitorVTable<SequenceVTable> for SequenceVTable {
241
    fn visit_buffers(_array: &SequenceArray, _visitor: &mut dyn ArrayBufferVisitor) {
1,941✔
242
        // TODO(joe): expose scalar values
1,941✔
243
    }
1,941✔
244

245
    fn visit_children(_array: &SequenceArray, _visitor: &mut dyn ArrayChildVisitor) {}
2,166✔
246
}
247

248
#[derive(Clone, Debug)]
249
pub struct SequenceEncoding;
250

251
#[cfg(test)]
252
mod tests {
253
    use vortex_array::arrays::PrimitiveArray;
254
    use vortex_dtype::Nullability;
255
    use vortex_scalar::{Scalar, ScalarValue};
256

257
    use crate::array::SequenceArray;
258

259
    #[test]
260
    fn test_sequence_canonical() {
1✔
261
        let arr = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4).unwrap();
1✔
262

1✔
263
        let canon = PrimitiveArray::from_iter((0..4).map(|i| 2i64 + i * 3));
4✔
264

1✔
265
        assert_eq!(
1✔
266
            arr.to_canonical()
1✔
267
                .unwrap()
1✔
268
                .into_primitive()
1✔
269
                .unwrap()
1✔
270
                .as_slice::<i64>(),
1✔
271
            canon.as_slice::<i64>()
1✔
272
        )
1✔
273
    }
1✔
274

275
    #[test]
276
    fn test_sequence_slice_canonical() {
1✔
277
        let arr = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4)
1✔
278
            .unwrap()
1✔
279
            .slice(2, 3)
1✔
280
            .unwrap();
1✔
281

1✔
282
        let canon = PrimitiveArray::from_iter((2..3).map(|i| 2i64 + i * 3));
1✔
283

1✔
284
        assert_eq!(
1✔
285
            arr.to_canonical()
1✔
286
                .unwrap()
1✔
287
                .into_primitive()
1✔
288
                .unwrap()
1✔
289
                .as_slice::<i64>(),
1✔
290
            canon.as_slice::<i64>()
1✔
291
        )
1✔
292
    }
1✔
293

294
    #[test]
295
    fn test_sequence_scalar_at() {
1✔
296
        let scalar = SequenceArray::typed_new(2i64, 3, Nullability::NonNullable, 4)
1✔
297
            .unwrap()
1✔
298
            .scalar_at(2)
1✔
299
            .unwrap();
1✔
300

1✔
301
        assert_eq!(
1✔
302
            scalar,
1✔
303
            Scalar::new(scalar.dtype().clone(), ScalarValue::from(8i64))
1✔
304
        )
1✔
305
    }
1✔
306

307
    #[test]
308
    fn test_sequence_min_max() {
1✔
309
        assert!(SequenceArray::typed_new(-127i8, -1i8, Nullability::NonNullable, 2).is_ok());
1✔
310
        assert!(SequenceArray::typed_new(126i8, -1i8, Nullability::NonNullable, 2).is_ok());
1✔
311
    }
1✔
312

313
    #[test]
314
    fn test_sequence_too_big() {
1✔
315
        assert!(SequenceArray::typed_new(127i8, 1i8, Nullability::NonNullable, 2).is_err());
1✔
316
        assert!(SequenceArray::typed_new(-128i8, -1i8, Nullability::NonNullable, 2).is_err());
1✔
317
    }
1✔
318
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc