44use std:: mem:: transmute;
55
66use itertools:: Itertools ;
7+ use num_traits:: AsPrimitive ;
78use vortex_array:: arrays:: { PrimitiveArray , patch_chunk} ;
89use vortex_array:: patches:: Patches ;
910use vortex_array:: validity:: Validity ;
@@ -169,21 +170,27 @@ pub fn decompress_chunked(
169170 let exponents = array. exponents ( ) ;
170171 let patches_offset = patches. offset ( ) ;
171172
172- // We need to drop ALPArray here in case converting encoded buffer into primitive didn't create a copy. In that case
173- // both alp_encoded and array will hold a reference to the buffer we want to mutate.
173+ // We need to drop ALPArray here in case converting encoded buffer into
174+ // primitive didn't create a copy. In that case both alp_encoded and array
175+ // will hold a reference to the buffer we want to mutate.
174176 drop ( array) ;
175177
176178 match_each_alp_float_ptype ! ( ptype, |T | {
177179 let patches_values = patches_values. as_slice:: <T >( ) ;
178180 let mut alp_buffer = encoded. into_buffer_mut( ) ;
179181 match_each_unsigned_integer_ptype!( patches_chunk_offsets. ptype( ) , |C | {
180182 let patches_chunk_offsets = patches_chunk_offsets. as_slice:: <C >( ) ;
183+ // There always is at least one chunk offset.
184+ let base_offset = patches_chunk_offsets[ 0 ] ;
185+ let offset_within_chunk = patches. offset_within_chunk( ) . unwrap_or( 0 ) ;
186+
181187 match_each_unsigned_integer_ptype!( patches_indices. ptype( ) , |I | {
182188 let patches_indices = patches_indices. as_slice:: <I >( ) ;
183189
184190 for ( chunk_idx, chunk_start) in ( 0 ..array_len) . step_by( 1024 ) . enumerate( ) {
185191 let chunk_end = ( chunk_start + 1024 ) . min( array_len) ;
186192 let chunk_slice = & mut alp_buffer. as_mut_slice( ) [ chunk_start..chunk_end] ;
193+
187194 <T >:: decode_slice_inplace( chunk_slice, exponents) ;
188195
189196 let decoded_chunk: & mut [ T ] = unsafe { transmute( chunk_slice) } ;
@@ -194,6 +201,8 @@ pub fn decompress_chunked(
194201 patches_offset,
195202 patches_chunk_offsets,
196203 chunk_idx,
204+ base_offset. as_( ) ,
205+ offset_within_chunk,
197206 ) ;
198207 }
199208
@@ -214,8 +223,9 @@ fn decompress_unchunked(array: ALPArray) -> PrimitiveArray {
214223 let exponents = array. exponents ( ) ;
215224 let ptype = array. dtype ( ) . as_ptype ( ) ;
216225
217- // We need to drop ALPArray here in case converting encoded buffer into primitive didn't create a copy. In that case
218- // both alp_encoded and array will hold a reference to the buffer we want to mutate.
226+ // We need to drop ALPArray here in case converting encoded buffer into
227+ // primitive didn't create a copy. In that case both alp_encoded and array
228+ // will hold a reference to the buffer we want to mutate.
219229 drop ( array) ;
220230
221231 let decoded = match_each_alp_float_ptype ! ( ptype, |T | {
@@ -503,6 +513,27 @@ mod tests {
503513 assert ! ( encoded. patches( ) . is_some( ) ) ;
504514 }
505515
516+ #[ test]
517+ fn test_slice_across_chunks_with_patches_roundtrip ( ) {
518+ let mut values = vec ! [ 1.0f64 ; 2048 ] ;
519+ values[ 100 ] = PI ;
520+ values[ 200 ] = E ;
521+ values[ 600 ] = 42.42 ;
522+ values[ 800 ] = 42.42 ;
523+ values[ 1000 ] = 42.42 ;
524+ values[ 1023 ] = 42.42 ;
525+
526+ let original = PrimitiveArray :: new ( Buffer :: from ( values) , Validity :: NonNullable ) ;
527+ let encoded = alp_encode ( & original, None ) . unwrap ( ) ;
528+
529+ let sliced_alp = encoded. slice ( 1023 ..1025 ) ;
530+ let decoded = sliced_alp. to_primitive ( ) ;
531+
532+ let expected_slice = original. slice ( 1023 ..1025 ) . to_primitive ( ) ;
533+ assert_eq ! ( expected_slice. as_slice:: <f64 >( ) , decoded. as_slice:: <f64 >( ) ) ;
534+ assert ! ( encoded. patches( ) . is_some( ) ) ;
535+ }
536+
506537 #[ test]
507538 fn test_slice_half_chunk_nullable_roundtrip ( ) {
508539 let values = ( 0 ..1024 )
0 commit comments