1616// under the License.
1717
1818use super :: { _MutableArrayData, ArrayData , Extend } ;
19- use arrow_buffer:: { ArrowNativeType , Buffer , ToByteSlice } ;
19+ use arrow_buffer:: { ArrowNativeType , ToByteSlice } ;
2020use arrow_schema:: DataType ;
2121use num_traits:: CheckedAdd ;
2222
@@ -58,8 +58,9 @@ pub fn extend_nulls(mutable: &mut _MutableArrayData, len: usize) {
5858 macro_rules! extend_nulls_impl {
5959 ( $run_end_type: ty) => { {
6060 let last_run_end = get_last_run_end:: <$run_end_type>( & mutable. child_data[ 0 ] ) ;
61- let new_value = last_run_end
62- . checked_add( <$run_end_type as ArrowNativeType >:: usize_as( len) )
61+ let len = <$run_end_type as ArrowNativeType >:: from_usize( len) ;
62+ let new_value = len
63+ . and_then( |len| last_run_end. checked_add( len) )
6364 . expect( "run end overflow" ) ;
6465 mutable. child_data[ 0 ]
6566 . data
@@ -81,7 +82,7 @@ pub fn extend_nulls(mutable: &mut _MutableArrayData, len: usize) {
8182
8283/// Build run ends bytes and values range directly for batch processing
8384fn build_extend_arrays < T : ArrowNativeType + std:: ops:: Add < Output = T > + CheckedAdd > (
84- buffer : & Buffer ,
85+ typed_slice : & [ T ] ,
8586 length : usize ,
8687 start : usize ,
8788 len : usize ,
@@ -93,9 +94,6 @@ fn build_extend_arrays<T: ArrowNativeType + std::ops::Add<Output = T> + CheckedA
9394 let mut prev_end = 0 ;
9495 let mut current_run_end = dest_last_run_end;
9596
96- // Convert buffer to typed slice once
97- let typed_slice: & [ T ] = buffer. typed_data ( ) ;
98-
9997 for i in 0 ..length {
10098 if i < typed_slice. len ( ) {
10199 let run_end = typed_slice[ i] . to_usize ( ) . unwrap ( ) ;
@@ -188,6 +186,8 @@ pub fn build_extend(array: &ArrayData) -> Extend<'_> {
188186
189187 // We need to analyze the source array's run structure
190188 let source_run_ends = & array. child_data ( ) [ 0 ] ;
189+ let source_buffer_offset = source_run_ends. offset ( ) ;
190+ let source_buffer_len = source_run_ends. len ( ) ;
191191 let source_buffer = & source_run_ends. buffers ( ) [ 0 ] ;
192192
193193 // Get the run end type from the mutable array
@@ -201,6 +201,8 @@ pub fn build_extend(array: &ArrayData) -> Extend<'_> {
201201 // Build run ends and values indices directly for batch processing
202202 macro_rules! build_and_process_impl {
203203 ( $run_end_type: ty) => { {
204+ let source_buffer = & source_buffer. typed_data( )
205+ [ source_buffer_offset..source_buffer_offset + source_buffer_len] ;
204206 let dest_last_run_end =
205207 get_last_run_end:: <$run_end_type>( & mutable. child_data[ 0 ] ) ;
206208 let ( run_ends_bytes, values_range) = build_extend_arrays:: <$run_end_type>(
@@ -511,7 +513,8 @@ mod tests {
511513 #[ test]
512514 fn test_build_extend_arrays_int16 ( ) {
513515 let buffer = Buffer :: from_vec ( vec ! [ 3i16 , 5i16 , 8i16 ] ) ;
514- let ( run_ends_bytes, values_range) = build_extend_arrays :: < i16 > ( & buffer, 3 , 2 , 4 , 0i16 ) ;
516+ let ( run_ends_bytes, values_range) =
517+ build_extend_arrays :: < i16 > ( buffer. typed_data ( ) , 3 , 2 , 4 , 0i16 ) ;
515518
516519 // Logical array: [A, A, A, B, B, C, C, C]
517520 // Requesting indices 2-6 should give us:
@@ -533,7 +536,8 @@ mod tests {
533536 #[ test]
534537 fn test_build_extend_arrays_int64 ( ) {
535538 let buffer = Buffer :: from_vec ( vec ! [ 3i64 , 5i64 , 8i64 ] ) ;
536- let ( run_ends_bytes, values_range) = build_extend_arrays :: < i64 > ( & buffer, 3 , 2 , 4 , 0i64 ) ;
539+ let ( run_ends_bytes, values_range) =
540+ build_extend_arrays :: < i64 > ( buffer. typed_data ( ) , 3 , 2 , 4 , 0i64 ) ;
537541
538542 // Same logic as above but with i64
539543 assert_eq ! ( run_ends_bytes. len( ) , 3 * std:: mem:: size_of:: <i64 >( ) ) ;
@@ -644,4 +648,45 @@ mod tests {
644648 // This should cause overflow: (i32::MAX - 50) + 100 > i32::MAX
645649 mutable. extend ( 0 , 0 , 100 ) ;
646650 }
651+
652+ #[ test]
653+ #[ should_panic( expected = "run end overflow" ) ]
654+ fn test_extend_nulls_overflow ( ) {
655+ let values = create_int32_array_data ( vec ! [ 10 ] ) ;
656+ let array = create_run_array_data_int16 ( vec ! [ 100 ] , values) ;
657+
658+ let mut mutable = MutableArrayData :: new ( vec ! [ & array] , true , 10 ) ;
659+ mutable. extend_nulls ( i16:: MAX as usize + 1 ) ;
660+ }
661+
662+ #[ test]
663+ fn test_extend_accounts_for_offset ( ) {
664+ let dt = DataType :: RunEndEncoded (
665+ Arc :: new ( Field :: new ( "run_ends" , DataType :: Int32 , false ) ) ,
666+ Arc :: new ( Field :: new ( "values" , DataType :: Float32 , true ) ) ,
667+ ) ;
668+
669+ let runs = ArrayData :: builder ( DataType :: Int32 )
670+ . len ( 2 )
671+ . offset ( 2 )
672+ . add_buffer ( vec ! [ -10_i32 , -20 , 1_i32 , 4 , 0 , 100 ] . into ( ) )
673+ . build ( )
674+ . unwrap ( ) ;
675+ let values = ArrayData :: builder ( DataType :: Float32 )
676+ . len ( 2 )
677+ . add_buffer ( vec ! [ 1.5 , 2.5 ] . into ( ) )
678+ . build ( )
679+ . unwrap ( ) ;
680+
681+ let source_data = ArrayDataBuilder :: new ( dt)
682+ . len ( 3 )
683+ . child_data ( vec ! [ runs, values] )
684+ . build ( )
685+ . unwrap ( ) ;
686+
687+ let mut mutable = MutableArrayData :: new ( vec ! [ & source_data] , true , 10 ) ;
688+ mutable. extend ( 0 , 0 , 1 ) ;
689+ let data = mutable. freeze ( ) ;
690+ assert_eq ! ( data, source_data. slice( 0 , 1 ) ) ;
691+ }
647692}
0 commit comments