@@ -23,9 +23,12 @@ use crate::arrays::dict::TakeExecute;
2323use crate :: arrays:: fixed_size_list:: FixedSizeListArrayExt ;
2424use crate :: arrays:: primitive:: PrimitiveArrayExt ;
2525use crate :: builders:: builder_with_capacity;
26+ use crate :: builtins:: ArrayBuiltins ;
27+ use crate :: dtype:: DType ;
2628use crate :: dtype:: IntegerPType ;
2729use crate :: executor:: ExecutionCtx ;
2830use crate :: match_each_unsigned_integer_ptype;
31+ use crate :: scalar:: Scalar ;
2932use crate :: validity:: Validity ;
3033
3134/// Take implementation for [`FixedSizeListArray`].
@@ -43,40 +46,86 @@ impl TakeExecute for FixedSizeList {
4346 return take_empty_fsl ( array, indices, ctx) . map ( Some ) ;
4447 }
4548
46- let indices_ptype = indices. dtype ( ) . as_ptype ( ) . to_unsigned ( ) ;
47- match_each_unsigned_integer_ptype ! ( indices_ptype, |I | {
48- take_non_empty_with_indices:: <I >( array, indices, ctx)
49- } )
50- . map ( Some )
49+ take_non_empty_fsl ( array, indices, ctx) . map ( Some )
5150 }
5251}
5352
53+ fn take_non_empty_fsl (
54+ array : ArrayView < ' _ , FixedSizeList > ,
55+ indices : & ArrayRef ,
56+ ctx : & mut ExecutionCtx ,
57+ ) -> VortexResult < ArrayRef > {
58+ debug_assert ! ( !array. is_empty( ) ) ;
59+
60+ let DType :: Primitive ( ptype, nullability) = indices. dtype ( ) else {
61+ vortex_bail ! ( "Invalid indices dtype: {}" , indices. dtype( ) )
62+ } ;
63+ if !ptype. is_int ( ) {
64+ vortex_bail ! ( "Invalid indices dtype: {}" , indices. dtype( ) ) ;
65+ }
66+
67+ let indices_validity = indices. validity ( ) ?;
68+ let indices_validity_mask = indices_validity. execute_mask ( indices. len ( ) , ctx) ?;
69+ // Null index lanes are semantically ignored. Zero them before checked signed-to-unsigned casts
70+ // so a negative physical payload in a null lane does not fail the take.
71+ let indices_nulls_zeroed = if indices_validity_mask. all_true ( ) {
72+ indices. clone ( )
73+ } else {
74+ indices
75+ . clone ( )
76+ . fill_null ( Scalar :: from ( 0 ) . cast ( indices. dtype ( ) ) ?) ?
77+ } ;
78+
79+ let unsigned_indices = if ptype. is_unsigned_int ( ) {
80+ indices_nulls_zeroed. execute :: < PrimitiveArray > ( ctx) ?
81+ } else {
82+ indices_nulls_zeroed
83+ . cast ( DType :: Primitive ( ptype. to_unsigned ( ) , * nullability) ) ?
84+ . execute :: < PrimitiveArray > ( ctx) ?
85+ } ;
86+
87+ match_each_unsigned_integer_ptype ! ( unsigned_indices. ptype( ) , |I | {
88+ take_non_empty_with_indices:: <I >(
89+ array,
90+ indices,
91+ unsigned_indices. as_view( ) ,
92+ & indices_validity_mask,
93+ nullability. is_nullable( ) ,
94+ ctx,
95+ )
96+ } )
97+ }
98+
5499fn take_non_empty_with_indices < I : IntegerPType > (
55100 array : ArrayView < ' _ , FixedSizeList > ,
56101 indices : & ArrayRef ,
102+ indices_array : ArrayView < ' _ , Primitive > ,
103+ indices_validity : & Mask ,
104+ indices_are_nullable : bool ,
57105 ctx : & mut ExecutionCtx ,
58106) -> VortexResult < ArrayRef > {
59107 debug_assert ! ( !array. is_empty( ) ) ;
60108
61109 let list_size = array. list_size ( ) as usize ;
62110
63- let indices_array = indices. clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
64- // Bit-identical reinterpret so `as_slice::<I>` (with unsigned `I`) matches. Negative signed
65- // inputs become large unsigned values and are rejected by the bounds check below.
66- let indices_array = indices_array. reinterpret_cast ( indices_array. ptype ( ) . to_unsigned ( ) ) ;
67-
68111 if list_size == 0 {
69- return take_non_empty_degenerate_fsl :: < I > ( array, indices, indices_array. as_view ( ) , ctx ) ;
112+ return take_non_empty_degenerate_fsl :: < I > ( array, indices, indices_array, indices_validity ) ;
70113 }
71114
72- take_non_empty_non_degenerate_fsl :: < I > ( array, indices_array. as_view ( ) , ctx)
115+ take_non_empty_non_degenerate_fsl :: < I > (
116+ array,
117+ indices_array,
118+ indices_validity,
119+ indices_are_nullable,
120+ ctx,
121+ )
73122}
74123
75124fn take_non_empty_degenerate_fsl < I : IntegerPType > (
76125 array : ArrayView < ' _ , FixedSizeList > ,
77126 indices : & ArrayRef ,
78127 indices_array : ArrayView < ' _ , Primitive > ,
79- ctx : & mut ExecutionCtx ,
128+ indices_validity : & Mask ,
80129) -> VortexResult < ArrayRef > {
81130 debug_assert ! ( !array. is_empty( ) ) ;
82131 debug_assert_eq ! ( array. list_size( ) , 0 ) ;
@@ -85,7 +134,7 @@ fn take_non_empty_degenerate_fsl<I: IntegerPType>(
85134 "degenerate list must have empty elements"
86135 ) ;
87136
88- validate_valid_indices :: < I > ( & indices_array, array. as_ref ( ) . len ( ) , ctx ) ?;
137+ validate_valid_indices :: < I > ( & indices_array, indices_validity , array. as_ref ( ) . len ( ) ) ?;
89138 let new_validity = array. validity ( ) ?. take ( indices) ?;
90139 let new_len = indices_array. len ( ) ;
91140
@@ -139,13 +188,15 @@ fn take_empty_fsl(
139188fn take_non_empty_non_degenerate_fsl < I : IntegerPType > (
140189 array : ArrayView < ' _ , FixedSizeList > ,
141190 indices_array : ArrayView < ' _ , Primitive > ,
191+ indices_validity : & Mask ,
192+ indices_are_nullable : bool ,
142193 ctx : & mut ExecutionCtx ,
143194) -> VortexResult < ArrayRef > {
144195 debug_assert ! ( !array. is_empty( ) ) ;
145196 debug_assert_ne ! ( array. list_size( ) , 0 ) ;
146197
147- if array. dtype ( ) . is_nullable ( ) || indices_array . dtype ( ) . is_nullable ( ) {
148- take_nullable_non_empty_fsl :: < I > ( array, indices_array, ctx)
198+ if array. dtype ( ) . is_nullable ( ) || indices_are_nullable {
199+ take_nullable_non_empty_fsl :: < I > ( array, indices_array, indices_validity , ctx)
149200 } else {
150201 take_non_nullable_non_empty_fsl :: < I > ( array, indices_array)
151202 }
@@ -195,6 +246,7 @@ fn take_non_nullable_non_empty_fsl<I: IntegerPType>(
195246fn take_nullable_non_empty_fsl < I : IntegerPType > (
196247 array : ArrayView < ' _ , FixedSizeList > ,
197248 indices_array : ArrayView < ' _ , Primitive > ,
249+ indices_validity : & Mask ,
198250 ctx : & mut ExecutionCtx ,
199251) -> VortexResult < ArrayRef > {
200252 debug_assert ! ( !array. is_empty( ) ) ;
@@ -209,7 +261,6 @@ fn take_nullable_non_empty_fsl<I: IntegerPType>(
209261 let array_validity = array
210262 . fixed_size_list_validity ( )
211263 . execute_mask ( array. as_ref ( ) . len ( ) , ctx) ?;
212- let indices_validity = indices_validity_mask ( & indices_array, ctx) ?;
213264
214265 let mut starts = BufferMut :: < u64 > :: with_capacity ( new_len) ;
215266 let mut new_validity_builder = BitBufferMut :: with_capacity ( new_len) ;
@@ -254,22 +305,12 @@ fn take_nullable_non_empty_fsl<I: IntegerPType>(
254305 . into_array ( ) )
255306}
256307
257- fn indices_validity_mask (
258- indices_array : & ArrayView < ' _ , Primitive > ,
259- ctx : & mut ExecutionCtx ,
260- ) -> VortexResult < Mask > {
261- indices_array
262- . validity ( ) ?
263- . execute_mask ( indices_array. as_ref ( ) . len ( ) , ctx)
264- }
265-
266308fn validate_valid_indices < I : IntegerPType > (
267309 indices_array : & ArrayView < ' _ , Primitive > ,
310+ indices_validity : & Mask ,
268311 array_len : usize ,
269- ctx : & mut ExecutionCtx ,
270312) -> VortexResult < ( ) > {
271313 let indices: & [ I ] = indices_array. as_slice :: < I > ( ) ;
272- let indices_validity = indices_validity_mask ( indices_array, ctx) ?;
273314
274315 for ( & data_idx, is_index_valid) in indices. iter ( ) . zip ( indices_validity. iter ( ) ) {
275316 if is_index_valid {
0 commit comments