vortex_fastlanes/delta/vtable/
operations.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::cmp::min;
5use std::ops::Range;
6
7use vortex_array::Array;
8use vortex_array::ArrayRef;
9use vortex_array::IntoArray;
10use vortex_array::ToCanonical;
11use vortex_array::vtable::OperationsVTable;
12use vortex_scalar::Scalar;
13
14use super::DeltaVTable;
15use crate::DeltaArray;
16
17impl OperationsVTable<DeltaVTable> for DeltaVTable {
18    fn slice(array: &DeltaArray, range: Range<usize>) -> ArrayRef {
19        let physical_start = range.start + array.offset();
20        let physical_stop = range.end + array.offset();
21
22        let start_chunk = physical_start / 1024;
23        let stop_chunk = physical_stop.div_ceil(1024);
24
25        let bases = array.bases();
26        let deltas = array.deltas();
27        let lanes = array.lanes();
28
29        let new_bases = bases.slice(
30            min(start_chunk * lanes, array.bases_len())..min(stop_chunk * lanes, array.bases_len()),
31        );
32
33        let new_deltas = deltas.slice(
34            min(start_chunk * 1024, array.deltas_len())..min(stop_chunk * 1024, array.deltas_len()),
35        );
36
37        // SAFETY: slicing valid bases/deltas preserves correctness
38        unsafe {
39            DeltaArray::new_unchecked(new_bases, new_deltas, physical_start % 1024, range.len())
40                .into_array()
41        }
42    }
43
44    fn scalar_at(array: &DeltaArray, index: usize) -> Scalar {
45        let decompressed = array.slice(index..index + 1).to_primitive();
46        decompressed.scalar_at(0)
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use rstest::rstest;
53    use vortex_array::IntoArray;
54    use vortex_array::arrays::PrimitiveArray;
55    use vortex_array::assert_arrays_eq;
56    use vortex_array::compute::conformance::binary_numeric::test_binary_numeric_array;
57    use vortex_array::compute::conformance::consistency::test_array_consistency;
58
59    use super::*;
60    use crate::DeltaArray;
61
62    #[test]
63    fn test_slice_non_jagged_array_first_chunk_of_two() {
64        let delta = DeltaArray::try_from_vec((0u32..2048).collect()).unwrap();
65
66        let actual = delta.slice(10..250);
67        let expected = PrimitiveArray::from_iter(10u32..250).into_array();
68        assert_arrays_eq!(actual, expected);
69    }
70
71    #[test]
72    fn test_slice_non_jagged_array_second_chunk_of_two() {
73        let delta = DeltaArray::try_from_vec((0u32..2048).collect()).unwrap();
74
75        let actual = delta.slice(1024 + 10..1024 + 250);
76        let expected = PrimitiveArray::from_iter((1024 + 10u32)..(1024 + 250)).into_array();
77        assert_arrays_eq!(actual, expected);
78    }
79
80    #[test]
81    fn test_slice_non_jagged_array_span_two_chunks_chunk_of_two() {
82        let delta = DeltaArray::try_from_vec((0u32..2048).collect()).unwrap();
83
84        let actual = delta.slice(1000..1048);
85        let expected = PrimitiveArray::from_iter(1000u32..1048).into_array();
86        assert_arrays_eq!(actual, expected);
87    }
88
89    #[test]
90    fn test_slice_non_jagged_array_span_two_chunks_chunk_of_four() {
91        let delta = DeltaArray::try_from_vec((0u32..4096).collect()).unwrap();
92
93        let actual = delta.slice(2040..2050);
94        let expected = PrimitiveArray::from_iter(2040u32..2050).into_array();
95        assert_arrays_eq!(actual, expected);
96    }
97
98    #[test]
99    fn test_slice_non_jagged_array_whole() {
100        let delta = DeltaArray::try_from_vec((0u32..4096).collect()).unwrap();
101
102        let actual = delta.slice(0..4096);
103        let expected = PrimitiveArray::from_iter(0u32..4096).into_array();
104        assert_arrays_eq!(actual, expected);
105    }
106
107    #[test]
108    fn test_slice_non_jagged_array_empty() {
109        let delta = DeltaArray::try_from_vec((0u32..4096).collect()).unwrap();
110
111        let actual = delta.slice(0..0);
112        let expected = PrimitiveArray::from_iter(Vec::<u32>::new()).into_array();
113        assert_arrays_eq!(actual, expected);
114
115        let actual = delta.slice(4096..4096);
116        let expected = PrimitiveArray::from_iter(Vec::<u32>::new()).into_array();
117        assert_arrays_eq!(actual, expected);
118
119        let actual = delta.slice(1024..1024);
120        let expected = PrimitiveArray::from_iter(Vec::<u32>::new()).into_array();
121        assert_arrays_eq!(actual, expected);
122    }
123
124    #[test]
125    fn test_slice_jagged_array_second_chunk_of_two() {
126        let delta = DeltaArray::try_from_vec((0u32..2000).collect()).unwrap();
127
128        let actual = delta.slice(1024 + 10..1024 + 250);
129        let expected = PrimitiveArray::from_iter((1024 + 10u32)..(1024 + 250)).into_array();
130        assert_arrays_eq!(actual, expected);
131    }
132
133    #[test]
134    fn test_slice_jagged_array_empty() {
135        let delta = DeltaArray::try_from_vec((0u32..4000).collect()).unwrap();
136
137        let actual = delta.slice(0..0);
138        let expected = PrimitiveArray::from_iter(Vec::<u32>::new()).into_array();
139        assert_arrays_eq!(actual, expected);
140
141        let actual = delta.slice(4000..4000);
142        let expected = PrimitiveArray::from_iter(Vec::<u32>::new()).into_array();
143        assert_arrays_eq!(actual, expected);
144
145        let actual = delta.slice(1024..1024);
146        let expected = PrimitiveArray::from_iter(Vec::<u32>::new()).into_array();
147        assert_arrays_eq!(actual, expected);
148    }
149
150    #[test]
151    fn test_slice_of_slice_of_non_jagged() {
152        let delta = DeltaArray::try_from_vec((0u32..2048).collect()).unwrap();
153
154        let sliced = delta.slice(10..1013);
155        let sliced_again = sliced.slice(0..2);
156
157        let expected = PrimitiveArray::from_iter(vec![10u32, 11]).into_array();
158        assert_arrays_eq!(sliced_again, expected);
159    }
160
161    #[test]
162    fn test_slice_of_slice_of_jagged() {
163        let delta = DeltaArray::try_from_vec((0u32..2000).collect()).unwrap();
164
165        let sliced = delta.slice(10..1013);
166        let sliced_again = sliced.slice(0..2);
167
168        let expected = PrimitiveArray::from_iter(vec![10u32, 11]).into_array();
169        assert_arrays_eq!(sliced_again, expected);
170    }
171
172    #[test]
173    fn test_slice_of_slice_second_chunk_of_non_jagged() {
174        let delta = DeltaArray::try_from_vec((0u32..2048).collect()).unwrap();
175
176        let sliced = delta.slice(1034..1050);
177        let sliced_again = sliced.slice(0..2);
178
179        let expected = PrimitiveArray::from_iter(vec![1034u32, 1035]).into_array();
180        assert_arrays_eq!(sliced_again, expected);
181    }
182
183    #[test]
184    fn test_slice_of_slice_second_chunk_of_jagged() {
185        let delta = DeltaArray::try_from_vec((0u32..2000).collect()).unwrap();
186
187        let sliced = delta.slice(1034..1050);
188        let sliced_again = sliced.slice(0..2);
189
190        let expected = PrimitiveArray::from_iter(vec![1034u32, 1035]).into_array();
191        assert_arrays_eq!(sliced_again, expected);
192    }
193
194    #[test]
195    fn test_slice_of_slice_spanning_two_chunks_of_non_jagged() {
196        let delta = DeltaArray::try_from_vec((0u32..2048).collect()).unwrap();
197
198        let sliced = delta.slice(1010..1050);
199        let sliced_again = sliced.slice(5..20);
200
201        let expected = PrimitiveArray::from_iter(1015u32..1030).into_array();
202        assert_arrays_eq!(sliced_again, expected);
203    }
204
205    #[test]
206    fn test_slice_of_slice_spanning_two_chunks_of_jagged() {
207        let delta = DeltaArray::try_from_vec((0u32..2000).collect()).unwrap();
208
209        let sliced = delta.slice(1010..1050);
210        let sliced_again = sliced.slice(5..20);
211
212        let expected = PrimitiveArray::from_iter(1015u32..1030).into_array();
213        assert_arrays_eq!(sliced_again, expected);
214    }
215
216    #[test]
217    fn test_scalar_at_non_jagged_array() {
218        let delta = DeltaArray::try_from_vec((0u32..2048).collect())
219            .unwrap()
220            .into_array();
221
222        let expected = PrimitiveArray::from_iter(0u32..2048).into_array();
223        assert_arrays_eq!(delta, expected);
224    }
225
226    #[test]
227    #[should_panic]
228    fn test_scalar_at_non_jagged_array_oob() {
229        let delta = DeltaArray::try_from_vec((0u32..2048).collect())
230            .unwrap()
231            .into_array();
232        delta.scalar_at(2048);
233    }
234    #[test]
235    fn test_scalar_at_jagged_array() {
236        let delta = DeltaArray::try_from_vec((0u32..2000).collect())
237            .unwrap()
238            .into_array();
239
240        let expected = PrimitiveArray::from_iter(0u32..2000).into_array();
241        assert_arrays_eq!(delta, expected);
242    }
243
244    #[test]
245    #[should_panic]
246    fn test_scalar_at_jagged_array_oob() {
247        let delta = DeltaArray::try_from_vec((0u32..2000).collect())
248            .unwrap()
249            .into_array();
250        delta.scalar_at(2000);
251    }
252
253    #[rstest]
254    // Basic delta arrays
255    #[case::delta_u32(DeltaArray::try_from_vec((0u32..100).collect()).unwrap())]
256    #[case::delta_u64(DeltaArray::try_from_vec((0..100).map(|i| i as u64 * 10).collect()).unwrap())]
257    // Large arrays (multiple chunks)
258    #[case::delta_large_u32(DeltaArray::try_from_vec((0u32..2048).collect()).unwrap())]
259    #[case::delta_large_u64(DeltaArray::try_from_vec((0u64..2048).collect()).unwrap())]
260    // Single element
261    #[case::delta_single(DeltaArray::try_from_vec(vec![42u32]).unwrap())]
262    fn test_delta_consistency(#[case] array: DeltaArray) {
263        test_array_consistency(array.as_ref());
264    }
265
266    #[rstest]
267    #[case::delta_u8_basic(DeltaArray::try_from_vec(vec![1u8, 1, 1, 1, 1]).unwrap())]
268    #[case::delta_u16_basic(DeltaArray::try_from_vec(vec![1u16, 1, 1, 1, 1]).unwrap())]
269    #[case::delta_u32_basic(DeltaArray::try_from_vec(vec![1u32, 1, 1, 1, 1]).unwrap())]
270    #[case::delta_u64_basic(DeltaArray::try_from_vec(vec![1u64, 1, 1, 1, 1]).unwrap())]
271    #[case::delta_u32_large(DeltaArray::try_from_vec(vec![1u32; 100]).unwrap())]
272    fn test_delta_binary_numeric(#[case] array: DeltaArray) {
273        test_binary_numeric_array(array.into_array());
274    }
275}