@@ -10,6 +10,7 @@ use std::hash::Hasher;
1010use std:: sync:: Arc ;
1111
1212use vortex_buffer:: Buffer ;
13+ use vortex_error:: VortexExpect ;
1314use vortex_error:: VortexResult ;
1415use vortex_error:: vortex_bail;
1516use vortex_error:: vortex_ensure;
@@ -34,6 +35,8 @@ use crate::arrays::patched::patch_lanes;
3435use crate :: arrays:: patched:: vtable:: kernels:: PARENT_KERNELS ;
3536use crate :: arrays:: primitive:: PrimitiveArrayParts ;
3637use crate :: buffer:: BufferHandle ;
38+ use crate :: builders:: ArrayBuilder ;
39+ use crate :: builders:: PrimitiveBuilder ;
3740use crate :: dtype:: DType ;
3841use crate :: dtype:: NativePType ;
3942use crate :: match_each_native_ptype;
@@ -169,6 +172,61 @@ impl VTable for Patched {
169172 Ok ( ProstMetadata ( inner) )
170173 }
171174
175+ fn append_to_builder (
176+ array : & Self :: Array ,
177+ builder : & mut dyn ArrayBuilder ,
178+ ctx : & mut ExecutionCtx ,
179+ ) -> VortexResult < ( ) > {
180+ let dtype = array. dtype ( ) ;
181+
182+ if !dtype. is_primitive ( ) {
183+ // Default pathway: canonicalize and propagate.
184+ let canonical = array
185+ . clone ( )
186+ . into_array ( )
187+ . execute :: < Canonical > ( ctx) ?
188+ . into_array ( ) ;
189+ builder. extend_from_array ( & canonical) ;
190+ return Ok ( ( ) ) ;
191+ }
192+
193+ let ptype = dtype. as_ptype ( ) ;
194+
195+ let len = array. len ( ) ;
196+ array. inner . append_to_builder ( builder, ctx) ?;
197+
198+ let offset = array. offset ;
199+ let lane_offsets: Buffer < u32 > =
200+ Buffer :: from_byte_buffer ( array. lane_offsets . clone ( ) . unwrap_host ( ) ) ;
201+ let indices: Buffer < u16 > = Buffer :: from_byte_buffer ( array. indices . clone ( ) . unwrap_host ( ) ) ;
202+ let values = array. values . clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
203+
204+ match_each_native_ptype ! ( ptype, |V | {
205+ let typed_builder = builder
206+ . as_any_mut( )
207+ . downcast_mut:: <PrimitiveBuilder <V >>( )
208+ . vortex_expect( "correctly typed builder" ) ;
209+
210+ // Overwrite the last `len` elements of the builder. These would have been
211+ // populated by the inner.append_to_builder() call above.
212+ let output = typed_builder. values_mut( ) ;
213+ let trailer = output. len( ) - len;
214+
215+ apply_patches_primitive:: <V >(
216+ & mut output[ trailer..] ,
217+ offset,
218+ len,
219+ array. n_chunks,
220+ array. n_lanes,
221+ & lane_offsets,
222+ & indices,
223+ values. as_slice:: <V >( ) ,
224+ ) ;
225+ } ) ;
226+
227+ Ok ( ( ) )
228+ }
229+
172230 fn build (
173231 dtype : & DType ,
174232 len : usize ,
@@ -320,9 +378,13 @@ mod tests {
320378 use crate :: ExecutionCtx ;
321379 use crate :: IntoArray ;
322380 use crate :: arrays:: PatchedArray ;
381+ use crate :: arrays:: PrimitiveArray ;
382+ use crate :: assert_arrays_eq;
383+ use crate :: builders:: builder_with_capacity;
323384 use crate :: dtype:: Nullability ;
324385 use crate :: patches:: Patches ;
325386 use crate :: scalar:: Scalar ;
387+ use crate :: validity:: Validity ;
326388
327389 #[ test]
328390 fn test_execute ( ) {
@@ -393,4 +455,83 @@ mod tests {
393455 Scalar :: primitive( 1u16 , Nullability :: NonNullable )
394456 ) ;
395457 }
458+
459+ #[ test]
460+ fn test_append_to_builder_non_nullable ( ) {
461+ let values = PrimitiveArray :: new ( buffer ! [ 0u16 ; 1024 ] , Validity :: NonNullable ) . into_array ( ) ;
462+ let patches = Patches :: new (
463+ 1024 ,
464+ 0 ,
465+ buffer ! [ 1u32 , 2 , 3 ] . into_array ( ) ,
466+ buffer ! [ 10u16 , 20 , 30 ] . into_array ( ) ,
467+ None ,
468+ )
469+ . unwrap ( ) ;
470+
471+ let session = VortexSession :: empty ( ) ;
472+ let mut ctx = ExecutionCtx :: new ( session) ;
473+
474+ let array = PatchedArray :: from_array_and_patches ( values, & patches, & mut ctx)
475+ . unwrap ( )
476+ . into_array ( ) ;
477+
478+ let mut builder = builder_with_capacity ( array. dtype ( ) , array. len ( ) ) ;
479+ array. append_to_builder ( builder. as_mut ( ) , & mut ctx) . unwrap ( ) ;
480+
481+ let result = builder. finish ( ) ;
482+
483+ let mut expected = buffer_mut ! [ 0u16 ; 1024 ] ;
484+ expected[ 1 ] = 10 ;
485+ expected[ 2 ] = 20 ;
486+ expected[ 3 ] = 30 ;
487+ let expected = expected. into_array ( ) ;
488+
489+ assert_arrays_eq ! ( expected, result) ;
490+ }
491+
492+ #[ test]
493+ fn test_append_to_builder_with_validity ( ) {
494+ // Create inner array with nulls at indices 0 and 5.
495+ let validity = Validity :: from_iter ( ( 0 ..10 ) . map ( |i| i != 0 && i != 5 ) ) ;
496+ let values = PrimitiveArray :: new ( buffer ! [ 0u16 ; 10 ] , validity) . into_array ( ) ;
497+
498+ // Apply patches at indices 1, 2, 3.
499+ let patches = Patches :: new (
500+ 10 ,
501+ 0 ,
502+ buffer ! [ 1u32 , 2 , 3 ] . into_array ( ) ,
503+ buffer ! [ 10u16 , 20 , 30 ] . into_array ( ) ,
504+ None ,
505+ )
506+ . unwrap ( ) ;
507+
508+ let session = VortexSession :: empty ( ) ;
509+ let mut ctx = ExecutionCtx :: new ( session) ;
510+
511+ let array = PatchedArray :: from_array_and_patches ( values, & patches, & mut ctx)
512+ . unwrap ( )
513+ . into_array ( ) ;
514+
515+ let mut builder = builder_with_capacity ( array. dtype ( ) , array. len ( ) ) ;
516+ array. append_to_builder ( builder. as_mut ( ) , & mut ctx) . unwrap ( ) ;
517+
518+ let result = builder. finish ( ) ;
519+
520+ // Expected: null at 0, patched 10/20/30 at 1/2/3, zero at 4, null at 5, zeros at 6-9.
521+ let expected = PrimitiveArray :: from_option_iter ( [
522+ None ,
523+ Some ( 10u16 ) ,
524+ Some ( 20 ) ,
525+ Some ( 30 ) ,
526+ Some ( 0 ) ,
527+ None ,
528+ Some ( 0 ) ,
529+ Some ( 0 ) ,
530+ Some ( 0 ) ,
531+ Some ( 0 ) ,
532+ ] )
533+ . into_array ( ) ;
534+
535+ assert_arrays_eq ! ( expected, result) ;
536+ }
396537}
0 commit comments