11// SPDX-License-Identifier: Apache-2.0
22// SPDX-FileCopyrightText: Copyright the Vortex contributors
33
4+ use std:: iter;
45use std:: ptr;
6+ use std:: sync:: Arc ;
57
68use itertools:: Itertools as _;
9+ use num_traits:: AsPrimitive ;
710use vortex_buffer:: BitBufferMut ;
11+ use vortex_buffer:: Buffer ;
812use vortex_buffer:: BufferMut ;
913use vortex_buffer:: ByteBufferMut ;
1014use vortex_error:: VortexExpect ;
1115use vortex_error:: VortexResult ;
1216use vortex_error:: vortex_ensure;
1317use vortex_error:: vortex_err;
1418use vortex_error:: vortex_panic;
19+ use vortex_mask:: AllOr ;
1520use vortex_mask:: Mask ;
1621
1722use crate :: ArrayRef ;
@@ -22,17 +27,21 @@ use crate::arrays::PiecewiseSequence;
2227use crate :: arrays:: PrimitiveArray ;
2328use crate :: arrays:: VarBin ;
2429use crate :: arrays:: VarBinArray ;
30+ use crate :: arrays:: VarBinViewArray ;
2531use crate :: arrays:: dict:: TakeExecute ;
2632use crate :: arrays:: piecewise_sequence:: constant_unsigned_usize;
2733use crate :: arrays:: piecewise_sequence:: maybe_contiguous_slices;
2834use crate :: arrays:: primitive:: PrimitiveArrayExt ;
2935use crate :: arrays:: varbin:: VarBinArrayExt ;
3036use crate :: arrays:: varbin:: VarBinArraySlotsExt ;
37+ use crate :: arrays:: varbinview:: BinaryView ;
38+ use crate :: arrays:: varbinview:: build_views:: MAX_BUFFER_LEN ;
3139use crate :: dtype:: DType ;
3240use crate :: dtype:: IntegerPType ;
3341use crate :: dtype:: PType ;
3442use crate :: dtype:: UnsignedPType ;
3543use crate :: executor:: ExecutionCtx ;
44+ use crate :: match_each_integer_ptype;
3645use crate :: match_each_unsigned_integer_ptype;
3746use crate :: validity:: Validity ;
3847
@@ -138,88 +147,149 @@ impl TakeExecute for VarBin {
138147 indices : & ArrayRef ,
139148 ctx : & mut ExecutionCtx ,
140149 ) -> VortexResult < Option < ArrayRef > > {
141- if let Some ( piecewise_indices) = indices. as_opt :: < PiecewiseSequence > ( )
142- && let Some ( taken) = take_contiguous_ranges ( array, piecewise_indices, indices, ctx) ?
143- {
144- return Ok ( Some ( taken) ) ;
150+ let offsets = array. offsets ( ) . clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
151+ let offsets = offsets. reinterpret_cast ( offsets. ptype ( ) . to_unsigned ( ) ) ;
152+ let last_offset = match_each_unsigned_integer_ptype ! ( offsets. ptype( ) , |O | {
153+ offsets. as_slice:: <O >( ) . last( ) . map_or( 0usize , |& o| o. as_( ) )
154+ } ) ;
155+
156+ // VarBinView can't hold this buffer, so we can't canonicalize and
157+ // take() (take panics). Convert to VarBin
158+ if last_offset > MAX_BUFFER_LEN {
159+ return Ok ( Some ( take_varbin ( array, indices, ctx) ?. into_array ( ) ) ) ;
145160 }
146161
147- // TODO(joe): Be lazy with execute
148- let offsets = array. offsets ( ) . clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
149- let data = array. bytes ( ) ;
150- let indices = indices. clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
162+ let data = array. bytes ( ) . clone ( ) ;
151163 let dtype = array
152164 . dtype ( )
153165 . clone ( )
154166 . union_nullability ( indices. dtype ( ) . nullability ( ) ) ;
155- let array_validity = array
156- . varbin_validity ( )
157- . execute_mask ( array . as_ref ( ) . len ( ) , ctx) ?;
158- let indices_validity = indices
167+ let validity = array. validity ( ) ? . take ( indices ) ? ;
168+
169+ let indices = indices . clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
170+ let indices_mask = indices
159171 . as_ref ( )
160172 . validity ( ) ?
161173 . execute_mask ( indices. as_ref ( ) . len ( ) , ctx) ?;
162174
163- // Offsets and indices are non-negative; read them through their unsigned reinterpretations
164- // so we only monomorphize over the 4 unsigned widths each (4x4 instead of 8x8). On take,
165- // offsets get widened to either 32- or 64-bit (to avoid overflow); the built output offsets
166- // are reinterpreted back to `out_offset_ptype` to preserve the result's offset signedness.
167- let out_offset_ptype = taken_offset_ptype ( offsets. ptype ( ) ) ;
168- let offsets = offsets. reinterpret_cast ( offsets. ptype ( ) . to_unsigned ( ) ) ;
169- let indices = indices. reinterpret_cast ( indices. ptype ( ) . to_unsigned ( ) ) ;
170-
171- let array = match_each_unsigned_integer_ptype ! ( indices. ptype( ) , |I | {
172- match offsets. ptype( ) {
173- PType :: U8 => take:: <I , u8 >(
174- dtype,
175- offsets. as_slice:: <u8 >( ) ,
176- data. as_slice( ) ,
177- indices. as_slice:: <I >( ) ,
178- array_validity,
179- indices_validity,
180- out_offset_ptype,
181- ) ,
182- PType :: U16 => take:: <I , u16 >(
183- dtype,
184- offsets. as_slice:: <u16 >( ) ,
185- data. as_slice( ) ,
186- indices. as_slice:: <I >( ) ,
187- array_validity,
188- indices_validity,
189- out_offset_ptype,
190- ) ,
191- PType :: U32 => take:: <I , u32 >(
192- dtype,
193- offsets. as_slice:: <u32 >( ) ,
175+ let views = match_each_unsigned_integer_ptype ! ( offsets. ptype( ) , |O | {
176+ match_each_integer_ptype!( indices. ptype( ) , |I | {
177+ take_views(
178+ offsets. as_slice:: <O >( ) ,
194179 data. as_slice( ) ,
195180 indices. as_slice:: <I >( ) ,
196- array_validity,
197- indices_validity,
198- out_offset_ptype,
199- ) ,
200- PType :: U64 => take:: <I , u64 >(
201- dtype,
202- offsets. as_slice:: <u64 >( ) ,
203- data. as_slice( ) ,
204- indices. as_slice:: <I >( ) ,
205- array_validity,
206- indices_validity,
207- out_offset_ptype,
208- ) ,
209- _ => unreachable!( "invalid PType for offsets" ) ,
210- }
181+ & indices_mask,
182+ )
183+ } )
211184 } ) ;
212185
213- Ok ( Some ( array?. into_array ( ) ) )
186+ // SAFETY: every view references buffer 0 which is inside shared data buffer
187+ unsafe {
188+ Ok ( Some (
189+ VarBinViewArray :: new_unchecked ( views, Arc :: from ( [ data] ) , dtype, validity)
190+ . into_array ( ) ,
191+ ) )
192+ }
214193 }
215194}
216195
196+ fn take_views < O : UnsignedPType , I : IntegerPType + AsPrimitive < usize > > (
197+ offsets : & [ O ] ,
198+ data : & [ u8 ] ,
199+ indices : & [ I ] ,
200+ mask : & Mask ,
201+ ) -> Buffer < BinaryView > {
202+ let build = |idx : usize | -> BinaryView {
203+ let start: usize = offsets[ idx] . as_ ( ) ;
204+ let stop: usize = offsets[ idx + 1 ] . as_ ( ) ;
205+ let value = & data[ start..stop] ;
206+ let len = stop - start;
207+
208+ // Caller guarantees every offset is <= MAX_BUFFER_LEN
209+ let start: u32 = start. as_ ( ) ;
210+ if len > BinaryView :: MAX_INLINED_SIZE {
211+ let mut prefix = [ 0u8 ; 4 ] ;
212+ prefix. copy_from_slice ( & value[ ..4 ] ) ;
213+ let len: u32 = len. as_ ( ) ;
214+ BinaryView :: new_ref ( len, prefix, 0 , start)
215+ } else {
216+ BinaryView :: make_view ( value, 0 , start)
217+ }
218+ } ;
219+
220+ match mask. bit_buffer ( ) {
221+ AllOr :: All => Buffer :: from_trusted_len_iter ( indices. iter ( ) . map ( |i| build ( i. as_ ( ) ) ) ) ,
222+ AllOr :: None => {
223+ Buffer :: from_trusted_len_iter ( iter:: repeat_n ( BinaryView :: default ( ) , indices. len ( ) ) )
224+ }
225+ AllOr :: Some ( buffer) => {
226+ Buffer :: from_trusted_len_iter ( buffer. iter ( ) . zip ( indices. iter ( ) ) . map ( |( valid, i) | {
227+ if valid {
228+ build ( i. as_ ( ) )
229+ } else {
230+ BinaryView :: default ( )
231+ }
232+ } ) )
233+ }
234+ }
235+ }
236+
237+ /// Take from a VarBin. Referenced bytes are copied
238+ pub fn take_varbin (
239+ array : ArrayView < ' _ , VarBin > ,
240+ indices : & ArrayRef ,
241+ ctx : & mut ExecutionCtx ,
242+ ) -> VortexResult < VarBinArray > {
243+ if let Some ( piecewise_indices) = indices. as_opt :: < PiecewiseSequence > ( )
244+ && let Some ( taken) = take_contiguous_ranges ( array, piecewise_indices, indices, ctx) ?
245+ {
246+ return Ok ( taken) ;
247+ }
248+
249+ let offsets = array. offsets ( ) . clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
250+ let data = array. bytes ( ) ;
251+ let indices = indices. clone ( ) . execute :: < PrimitiveArray > ( ctx) ?;
252+ let dtype = array
253+ . dtype ( )
254+ . clone ( )
255+ . union_nullability ( indices. dtype ( ) . nullability ( ) ) ;
256+ let array_validity = array
257+ . varbin_validity ( )
258+ . execute_mask ( array. as_ref ( ) . len ( ) , ctx) ?;
259+ let indices_validity = indices
260+ . as_ref ( )
261+ . validity ( ) ?
262+ . execute_mask ( indices. as_ref ( ) . len ( ) , ctx) ?;
263+
264+ // Offsets and indices are non-negative; read them through their unsigned reinterpretations
265+ // so we only monomorphize over the 4 unsigned widths each (4x4 instead of 8x8). On take,
266+ // offsets get widened to either 32- or 64-bit (to avoid overflow); the built output offsets
267+ // are reinterpreted back to `out_offset_ptype` to preserve the result's offset signedness.
268+ let out_offset_ptype = taken_offset_ptype ( offsets. ptype ( ) ) ;
269+ let offsets = offsets. reinterpret_cast ( offsets. ptype ( ) . to_unsigned ( ) ) ;
270+ let indices = indices. reinterpret_cast ( indices. ptype ( ) . to_unsigned ( ) ) ;
271+
272+ match_each_unsigned_integer_ptype ! ( indices. ptype( ) , |I | {
273+ match_each_unsigned_integer_ptype!( offsets. ptype( ) , |O | {
274+ take:: <I , O >(
275+ dtype,
276+ offsets. as_slice:: <O >( ) ,
277+ data. as_slice( ) ,
278+ indices. as_slice:: <I >( ) ,
279+ array_validity,
280+ indices_validity,
281+ out_offset_ptype,
282+ )
283+ } )
284+ } )
285+ }
286+
217287fn take_contiguous_ranges (
218288 array : ArrayView < ' _ , VarBin > ,
219289 indices : ArrayView < ' _ , PiecewiseSequence > ,
220290 indices_ref : & ArrayRef ,
221291 ctx : & mut ExecutionCtx ,
222- ) -> VortexResult < Option < ArrayRef > > {
292+ ) -> VortexResult < Option < VarBinArray > > {
223293 let Some ( ( starts, lengths) ) = maybe_contiguous_slices ( indices, ctx) ? else {
224294 return Ok ( None ) ;
225295 } ;
@@ -261,10 +331,12 @@ fn take_contiguous_ranges(
261331 // SAFETY: output offsets are built from valid input offsets, start at zero, are monotonically
262332 // non-decreasing, and the copied data buffer has exactly the referenced byte length.
263333 unsafe {
264- Ok ( Some (
265- VarBinArray :: new_unchecked ( result. offsets , result. data . freeze ( ) , dtype, validity)
266- . into_array ( ) ,
267- ) )
334+ Ok ( Some ( VarBinArray :: new_unchecked (
335+ result. offsets ,
336+ result. data . freeze ( ) ,
337+ dtype,
338+ validity,
339+ ) ) )
268340 }
269341}
270342
0 commit comments