@@ -296,33 +296,15 @@ impl<O: IntegerPType, S: IntegerPType> ArrayBuilder for ListViewBuilder<O, S> {
296296 return ;
297297 }
298298
299- // If we do not have the guarantee that the array is zero-copyable to a list, then we have
300- // to manually append each scalar.
301- if !listview. is_zero_copy_to_list ( ) {
302- for i in 0 ..listview. len ( ) {
303- let list = listview
304- . scalar_at ( i)
305- . vortex_expect ( "scalar_at failed in extend_from_array_unchecked" ) ;
306-
307- self . append_scalar ( & list)
308- . vortex_expect ( "was unable to extend the `ListViewBuilder`" )
309- }
310-
311- return ;
312- }
313-
314- // Otherwise, after removing any leading and trailing elements, we can simply bulk append
315- // the entire array.
299+ // Normalize to an exact zero-copy-to-list layout and then bulk append. This avoids the
300+ // very expensive scalar_at-per-list path for overlapping / out-of-order list views.
316301 let listview = listview
317302 . rebuild ( ListViewRebuildMode :: MakeExact )
318303 . vortex_expect ( "ListViewArray::rebuild(MakeExact) failed in extend_from_array" ) ;
319304 debug_assert ! ( listview. is_zero_copy_to_list( ) ) ;
320305
321- self . nulls . append_validity_mask (
322- array
323- . validity_mask ( )
324- . vortex_expect ( "validity_mask in extend_from_array_unchecked" ) ,
325- ) ;
306+ self . nulls
307+ . append_validity_mask ( listview. listview_validity_mask ( ) ) ;
326308
327309 // Bulk append the new elements (which should have no gaps or overlaps).
328310 let old_elements_len = self . elements_builder . len ( ) ;
@@ -429,11 +411,13 @@ fn adjust_and_extend_offsets<'a, O: IntegerPType, A: IntegerPType>(
429411mod tests {
430412 use std:: sync:: Arc ;
431413
414+ use vortex_buffer:: buffer;
432415 use vortex_error:: VortexExpect ;
433416
434417 use super :: ListViewBuilder ;
435418 use crate :: IntoArray ;
436419 use crate :: arrays:: ListArray ;
420+ use crate :: arrays:: ListViewArray ;
437421 use crate :: arrays:: listview:: ListViewArrayExt ;
438422 use crate :: assert_arrays_eq;
439423 use crate :: builders:: ArrayBuilder ;
@@ -443,6 +427,7 @@ mod tests {
443427 use crate :: dtype:: Nullability :: Nullable ;
444428 use crate :: dtype:: PType :: I32 ;
445429 use crate :: scalar:: Scalar ;
430+ use crate :: validity:: Validity ;
446431
447432 #[ test]
448433 fn test_empty ( ) {
@@ -696,6 +681,50 @@ mod tests {
696681 ) ;
697682 }
698683
684+ #[ test]
685+ fn test_extend_from_array_overlapping_listview ( ) {
686+ let dtype: Arc < DType > = Arc :: new ( I32 . into ( ) ) ;
687+
688+ // Non-ZCTL source:
689+ // - List 0: [10, 20]
690+ // - List 1: null (size is intentionally non-zero in source metadata)
691+ // - List 2: [10]
692+ let source = unsafe {
693+ ListViewArray :: new_unchecked (
694+ buffer ! [ 10i32 , 20 , 30 ] . into_array ( ) ,
695+ buffer ! [ 0u32 , 1 , 0 ] . into_array ( ) ,
696+ buffer ! [ 2u8 , 2 , 1 ] . into_array ( ) ,
697+ Validity :: from_iter ( [ true , false , true ] ) ,
698+ )
699+ } ;
700+ assert ! ( !source. is_zero_copy_to_list( ) ) ;
701+
702+ let mut builder =
703+ ListViewBuilder :: < u32 , u8 > :: with_capacity ( Arc :: clone ( & dtype) , Nullable , 0 , 0 ) ;
704+ builder. extend_from_array ( & source. into_array ( ) ) ;
705+
706+ let listview = builder. finish_into_listview ( ) ;
707+ assert_eq ! ( listview. len( ) , 3 ) ;
708+ assert ! ( listview. is_zero_copy_to_list( ) ) ;
709+
710+ assert_arrays_eq ! (
711+ listview. list_elements_at( 0 ) . unwrap( ) ,
712+ PrimitiveArray :: from_iter( [ 10i32 , 20 ] )
713+ ) ;
714+ assert ! (
715+ !listview
716+ . validity( )
717+ . vortex_expect( "listview validity should be derivable" )
718+ . is_valid( 1 )
719+ . unwrap( )
720+ ) ;
721+ assert_eq ! ( listview. list_elements_at( 1 ) . unwrap( ) . len( ) , 0 ) ;
722+ assert_arrays_eq ! (
723+ listview. list_elements_at( 2 ) . unwrap( ) ,
724+ PrimitiveArray :: from_iter( [ 10i32 ] )
725+ ) ;
726+ }
727+
699728 #[ test]
700729 fn test_error_append_null_to_non_nullable ( ) {
701730 let dtype: Arc < DType > = Arc :: new ( I32 . into ( ) ) ;
@@ -719,8 +748,6 @@ mod tests {
719748
720749 #[ test]
721750 fn test_append_array_as_list ( ) {
722- use vortex_buffer:: buffer;
723-
724751 let dtype: Arc < DType > = Arc :: new ( I32 . into ( ) ) ;
725752 let mut builder =
726753 ListViewBuilder :: < u32 , u32 > :: with_capacity ( Arc :: clone ( & dtype) , NonNullable , 20 , 10 ) ;
0 commit comments