vortex_fastlanes/rle/vtable/
operations.rs1use vortex_array::scalar::Scalar;
5use vortex_array::vtable::OperationsVTable;
6use vortex_error::VortexExpect;
7use vortex_error::VortexResult;
8
9use super::RLEVTable;
10use crate::FL_CHUNK_SIZE;
11use crate::RLEArray;
12
13impl OperationsVTable<RLEVTable> for RLEVTable {
14 fn scalar_at(array: &RLEArray, index: usize) -> VortexResult<Scalar> {
15 let offset_in_chunk = array.offset();
16 let chunk_relative_idx = array.indices().scalar_at(offset_in_chunk + index)?;
17
18 let chunk_relative_idx = chunk_relative_idx
19 .as_primitive()
20 .as_::<usize>()
21 .vortex_expect("Index must not be null");
22
23 let chunk_id = (offset_in_chunk + index) / FL_CHUNK_SIZE;
24 let value_idx_offset = array.values_idx_offset(chunk_id);
25
26 let scalar = array
27 .values()
28 .scalar_at(value_idx_offset + chunk_relative_idx)?;
29
30 Scalar::try_new(array.dtype().clone(), scalar.into_value())
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use vortex_array::Array;
37 use vortex_array::IntoArray;
38 use vortex_array::ToCanonical;
39 use vortex_array::arrays::PrimitiveArray;
40 use vortex_array::assert_arrays_eq;
41 use vortex_array::validity::Validity;
42 use vortex_buffer::Buffer;
43 use vortex_buffer::buffer;
44
45 use super::*;
46
47 mod fixture {
48 use super::*;
49
50 pub(super) fn rle_array() -> RLEArray {
51 let values = PrimitiveArray::from_iter([10u32, 20u32, 30u32]).into_array();
52 let indices = PrimitiveArray::from_iter(
53 [0u16, 0u16, 1u16, 1u16, 1u16, 2u16, 0u16]
54 .iter()
55 .cycle()
56 .take(1024)
57 .copied(),
58 )
59 .into_array();
60 let values_idx_offsets = PrimitiveArray::from_iter([0u64]).into_array();
61
62 RLEArray::try_new(
63 values,
64 indices.clone(),
65 values_idx_offsets,
66 0,
67 indices.len(),
68 )
69 .unwrap()
70 }
71
72 pub(super) fn rle_array_with_nulls() -> RLEArray {
73 let values = PrimitiveArray::from_iter([10u32, 20u32, 30u32]).into_array();
74 let pattern = [0u16, 0u16, 1u16, 1u16, 1u16, 2u16, 0u16];
75 let values_idx_offsets = PrimitiveArray::from_iter([0u64]).into_array();
76
77 let validity = Validity::from_iter(
79 [true, false, true, true, false, true, true]
80 .iter()
81 .cycle()
82 .take(1024)
83 .copied(),
84 );
85
86 let indices = PrimitiveArray::new(
87 pattern
88 .iter()
89 .cycle()
90 .take(1024)
91 .copied()
92 .collect::<Buffer<u16>>(),
93 validity,
94 )
95 .into_array();
96
97 RLEArray::try_new(
98 values,
99 indices.clone(),
100 values_idx_offsets,
101 0,
102 indices.len(),
103 )
104 .unwrap()
105 }
106 }
107
108 #[test]
109 fn test_scalar_at() {
110 use vortex_array::assert_arrays_eq;
111
112 let array = fixture::rle_array();
113 let expected = PrimitiveArray::from_iter([10u32, 10, 20, 20, 20, 30, 10]);
114 assert_arrays_eq!(array.slice(0..7).unwrap(), expected);
115 }
116
117 #[test]
118 fn test_scalar_at_with_nulls() {
119 use vortex_array::assert_arrays_eq;
120
121 let array = fixture::rle_array_with_nulls();
122 let expected = PrimitiveArray::from_option_iter([
123 Some(10u32),
124 None,
125 Some(20),
126 Some(20),
127 None,
128 Some(30),
129 Some(10),
130 ]);
131 assert_arrays_eq!(array.slice(0..7).unwrap(), expected);
132 }
133
134 #[test]
135 fn test_scalar_at_slice() {
136 use vortex_array::assert_arrays_eq;
137
138 let array = fixture::rle_array();
139 let sliced = array.slice(2..6).unwrap(); assert_eq!(sliced.len(), 4);
142 let expected = PrimitiveArray::from_iter([20u32, 20, 20, 30]);
143 assert_arrays_eq!(sliced, expected);
144 }
145
146 #[test]
147 fn test_scalar_at_slice_with_nulls() {
148 use vortex_array::assert_arrays_eq;
149
150 let array = fixture::rle_array_with_nulls();
151 let sliced = array.slice(2..6).unwrap(); assert_eq!(sliced.len(), 4);
154 let expected = PrimitiveArray::from_option_iter([Some(20u32), Some(20), None, Some(30)]);
155 assert_arrays_eq!(sliced, expected);
156 }
157
158 #[test]
159 fn test_scalar_at_multiple_chunks() {
160 let values: Buffer<u16> = (0..3000).map(|i| (i / 50) as u16).collect();
162 let expected: Vec<u16> = (0..3000).map(|i| (i / 50) as u16).collect();
163 let array = values.into_array();
164
165 let encoded = RLEArray::encode(&array.to_primitive()).unwrap();
166
167 for &idx in &[1023, 1024, 1025, 2047, 2048, 2049] {
169 if idx < encoded.len() {
170 let original_value = expected[idx];
171 let encoded_value = encoded
172 .scalar_at(idx)
173 .unwrap()
174 .as_primitive()
175 .as_::<u16>()
176 .unwrap();
177 assert_eq!(original_value, encoded_value, "Mismatch at index {}", idx);
178 }
179 }
180 }
181
182 #[test]
183 #[should_panic]
184 fn test_scalar_at_out_of_bounds() {
185 let array = fixture::rle_array();
186 array.scalar_at(1025).unwrap();
187 }
188
189 #[test]
190 #[should_panic]
191 fn test_scalar_at_slice_out_of_bounds() {
192 let array = fixture::rle_array().slice(0..1).unwrap();
193 array.scalar_at(1).unwrap();
194 }
195
196 #[test]
197 fn test_slice_full_range() {
198 let array = fixture::rle_array_with_nulls();
199 let sliced = array.slice(0..7).unwrap();
200
201 let expected = PrimitiveArray::from_option_iter([
202 Some(10u32),
203 None,
204 Some(20),
205 Some(20),
206 None,
207 Some(30),
208 Some(10),
209 ]);
210 assert_arrays_eq!(sliced.to_array(), expected.to_array());
211 }
212
213 #[test]
214 fn test_slice_partial_range() {
215 let array = fixture::rle_array();
216 let sliced = array.slice(4..6).unwrap(); let expected = buffer![20u32, 30].into_array();
219 assert_arrays_eq!(sliced.to_array(), expected);
220 }
221
222 #[test]
223 fn test_slice_single_element() {
224 let array = fixture::rle_array();
225 let sliced = array.slice(5..6).unwrap(); let expected = buffer![30u32].into_array();
228 assert_arrays_eq!(sliced.to_array(), expected);
229 }
230
231 #[test]
232 fn test_slice_empty_range() {
233 let array = fixture::rle_array();
234 let sliced = array.slice(3..3).unwrap();
235
236 assert_eq!(sliced.len(), 0);
237 }
238
239 #[test]
240 fn test_slice_with_nulls() {
241 let array = fixture::rle_array_with_nulls();
242 let sliced = array.slice(1..4).unwrap(); let expected = PrimitiveArray::from_option_iter([Option::<u32>::None, Some(20), Some(20)]);
245 assert_arrays_eq!(sliced.to_array(), expected.to_array());
246 }
247
248 #[test]
249 fn test_slice_decode_with_nulls() {
250 let array = fixture::rle_array_with_nulls();
251 let sliced = array.slice(1..4).unwrap().to_array().to_primitive(); let expected = PrimitiveArray::from_option_iter([Option::<u32>::None, Some(20), Some(20)]);
254 assert_arrays_eq!(sliced.to_array(), expected.to_array());
255 }
256
257 #[test]
258 fn test_slice_preserves_dtype() {
259 let array = fixture::rle_array();
260 let sliced = array.slice(1..4).unwrap();
261
262 assert_eq!(array.dtype(), sliced.dtype());
263 }
264
265 #[test]
266 fn test_slice_across_chunk_boundaries() {
267 let values: Buffer<u32> = (0..2100).map(|i| (i / 100) as u32).collect();
268 let expected: Vec<u32> = (0..2100).map(|i| (i / 100) as u32).collect();
269 let array = values.into_array();
270
271 let encoded = RLEArray::encode(&array.to_primitive()).unwrap();
272
273 let slice = encoded.slice(500..1500).unwrap();
275 assert_arrays_eq!(
276 slice,
277 PrimitiveArray::from_iter(expected[500..1500].iter().copied())
278 );
279
280 let slice = encoded.slice(1000..2000).unwrap();
282 assert_arrays_eq!(
283 slice,
284 PrimitiveArray::from_iter(expected[1000..2000].iter().copied())
285 );
286 }
287}