1use std::iter;
5use std::ptr;
6use std::sync::Arc;
7
8use itertools::Itertools as _;
9use num_traits::AsPrimitive;
10use vortex_buffer::BitBufferMut;
11use vortex_buffer::Buffer;
12use vortex_buffer::BufferMut;
13use vortex_buffer::ByteBufferMut;
14use vortex_error::VortexExpect;
15use vortex_error::VortexResult;
16use vortex_error::vortex_ensure;
17use vortex_error::vortex_err;
18use vortex_error::vortex_panic;
19use vortex_mask::AllOr;
20use vortex_mask::Mask;
21
22use crate::ArrayRef;
23use crate::Columnar;
24use crate::IntoArray;
25use crate::array::ArrayView;
26use crate::arrays::PiecewiseSequence;
27use crate::arrays::PrimitiveArray;
28use crate::arrays::VarBin;
29use crate::arrays::VarBinArray;
30use crate::arrays::VarBinViewArray;
31use crate::arrays::dict::TakeExecute;
32use crate::arrays::piecewise_sequence::constant_unsigned_usize;
33use crate::arrays::piecewise_sequence::maybe_contiguous_slices;
34use crate::arrays::primitive::PrimitiveArrayExt;
35use crate::arrays::varbin::VarBinArrayExt;
36use crate::arrays::varbin::VarBinArraySlotsExt;
37use crate::arrays::varbinview::BinaryView;
38use crate::arrays::varbinview::build_views::MAX_BUFFER_LEN;
39use crate::dtype::DType;
40use crate::dtype::IntegerPType;
41use crate::dtype::PType;
42use crate::dtype::UnsignedPType;
43use crate::executor::ExecutionCtx;
44use crate::match_each_integer_ptype;
45use crate::match_each_unsigned_integer_ptype;
46use crate::validity::Validity;
47
48fn taken_offset_ptype(offsets_ptype: PType) -> PType {
51 match offsets_ptype {
52 PType::U8 | PType::U16 | PType::U32 => PType::U32,
53 PType::U64 => PType::U64,
54 PType::I8 | PType::I16 | PType::I32 => PType::I32,
55 PType::I64 => PType::I64,
56 _ => unreachable!("invalid PType for offsets"),
57 }
58}
59
60enum Offsets {
63 U32 {
64 offsets: BufferMut<u32>,
65 signed: bool,
66 },
67 U64 {
68 offsets: BufferMut<u64>,
69 signed: bool,
70 },
71}
72
73impl Offsets {
74 fn with_capacity(offset_ptype: PType, capacity: usize) -> Self {
75 let signed = offset_ptype.is_signed_int();
76 match offset_ptype {
77 PType::U64 | PType::I64 => Self::U64 {
78 offsets: BufferMut::with_capacity(capacity),
79 signed,
80 },
81 _ => Self::U32 {
82 offsets: BufferMut::with_capacity(capacity),
83 signed,
84 },
85 }
86 }
87
88 fn len(&self) -> usize {
89 match self {
90 Self::U32 { offsets, .. } => offsets.len(),
91 Self::U64 { offsets, .. } => offsets.len(),
92 }
93 }
94
95 fn push(&mut self, offset: usize) {
96 let (offsets, signed) = match self {
97 Self::U64 { offsets, .. } => {
98 offsets.push(offset as u64);
99 return;
100 }
101 Self::U32 { offsets, signed } => (offsets, *signed),
102 };
103 let max_narrow = if signed {
104 i32::MAX as usize
105 } else {
106 u32::MAX as usize
107 };
108 if offset <= max_narrow {
109 offsets.push(u32::try_from(offset).vortex_expect("offset fits u32"));
110 return;
111 }
112
113 let mut wide = BufferMut::<u64>::with_capacity(offsets.capacity() + 1);
121 wide.extend(offsets.iter().map(|&o| u64::from(o)));
122 wide.push(offset as u64);
123 *self = Self::U64 {
124 offsets: wide,
125 signed,
126 };
127 }
128
129 fn into_array(self) -> ArrayRef {
130 let (offsets, out_offset_ptype) = match self {
131 Self::U32 { offsets, signed } => (
132 PrimitiveArray::new(offsets.freeze(), Validity::NonNullable),
133 if signed { PType::I32 } else { PType::U32 },
134 ),
135 Self::U64 { offsets, signed } => (
136 PrimitiveArray::new(offsets.freeze(), Validity::NonNullable),
137 if signed { PType::I64 } else { PType::U64 },
138 ),
139 };
140 offsets.reinterpret_cast(out_offset_ptype).into_array()
141 }
142}
143
144impl TakeExecute for VarBin {
145 fn take(
146 array: ArrayView<'_, VarBin>,
147 indices: &ArrayRef,
148 ctx: &mut ExecutionCtx,
149 ) -> VortexResult<Option<ArrayRef>> {
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 if last_offset > MAX_BUFFER_LEN {
159 return Ok(Some(take_varbin(array, indices, ctx)?.into_array()));
160 }
161
162 let data = array.bytes().clone();
163 let dtype = array
164 .dtype()
165 .clone()
166 .union_nullability(indices.dtype().nullability());
167 let validity = array.validity()?.take(indices)?;
168
169 let indices = indices.clone().execute::<PrimitiveArray>(ctx)?;
170 let indices_mask = indices
171 .as_ref()
172 .validity()?
173 .execute_mask(indices.as_ref().len(), ctx)?;
174
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>(),
179 data.as_slice(),
180 indices.as_slice::<I>(),
181 &indices_mask,
182 )
183 })
184 });
185
186 unsafe {
188 Ok(Some(
189 VarBinViewArray::new_unchecked(views, Arc::from([data]), dtype, validity)
190 .into_array(),
191 ))
192 }
193 }
194}
195
196fn 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 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
237pub 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 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
287fn take_contiguous_ranges(
288 array: ArrayView<'_, VarBin>,
289 indices: ArrayView<'_, PiecewiseSequence>,
290 indices_ref: &ArrayRef,
291 ctx: &mut ExecutionCtx,
292) -> VortexResult<Option<VarBinArray>> {
293 let Some((starts, lengths)) = maybe_contiguous_slices(indices, ctx)? else {
294 return Ok(None);
295 };
296 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
297 let out_offset_ptype = taken_offset_ptype(offsets.ptype());
298 let offsets = offsets.reinterpret_cast(offsets.ptype().to_unsigned());
299 let bytes = array.bytes();
300 let data = bytes.as_slice();
301 let dtype = array.dtype().clone();
302 let output_len = indices_ref.len();
303
304 let result = match lengths {
305 Columnar::Constant(lengths) => {
306 let length = constant_unsigned_usize(&lengths);
307 gather_slices_constant_dispatch(
308 &starts,
309 length,
310 &offsets,
311 data,
312 output_len,
313 out_offset_ptype,
314 )?
315 }
316 Columnar::Canonical(lengths) => {
317 let lengths = lengths.into_primitive();
318 gather_slices_dispatch(
319 &starts,
320 &lengths,
321 &offsets,
322 data,
323 output_len,
324 out_offset_ptype,
325 )?
326 }
327 };
328
329 let validity = array.validity()?.take(indices_ref)?;
330
331 unsafe {
334 Ok(Some(VarBinArray::new_unchecked(
335 result.offsets,
336 result.data.freeze(),
337 dtype,
338 validity,
339 )))
340 }
341}
342
343fn take<Index: IntegerPType, Offset: IntegerPType>(
344 dtype: DType,
345 offsets: &[Offset],
346 data: &[u8],
347 indices: &[Index],
348 validity_mask: Mask,
349 indices_validity_mask: Mask,
350 out_offset_ptype: PType,
351) -> VortexResult<VarBinArray> {
352 if !validity_mask.all_true() || !indices_validity_mask.all_true() {
353 return Ok(take_nullable::<Index, Offset>(
354 dtype,
355 offsets,
356 data,
357 indices,
358 validity_mask,
359 indices_validity_mask,
360 out_offset_ptype,
361 ));
362 }
363
364 let mut new_offsets = Offsets::with_capacity(out_offset_ptype, indices.len() + 1);
365 new_offsets.push(0);
366 let mut current_offset = 0usize;
367
368 for &idx in indices {
369 let idx = idx
370 .to_usize()
371 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", idx));
372 let start = offsets[idx];
373 let stop = offsets[idx + 1];
374
375 current_offset += (stop - start)
376 .to_usize()
377 .vortex_expect("Failed to cast offset to usize");
378 new_offsets.push(current_offset);
379 }
380
381 let mut new_data = ByteBufferMut::with_capacity(current_offset);
382
383 for idx in indices {
384 let idx = idx
385 .to_usize()
386 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", idx));
387 let start = offsets[idx]
388 .to_usize()
389 .vortex_expect("Failed to cast max offset to usize");
390 let stop = offsets[idx + 1]
391 .to_usize()
392 .vortex_expect("Failed to cast max offset to usize");
393 new_data.extend_from_slice(&data[start..stop]);
394 }
395
396 let array_validity = Validity::from(dtype.nullability());
397 let new_offsets = new_offsets.into_array();
398
399 unsafe {
402 Ok(VarBinArray::new_unchecked(
403 new_offsets,
404 new_data.freeze(),
405 dtype,
406 array_validity,
407 ))
408 }
409}
410
411struct GatheredPiecewiseVarBin {
412 offsets: ArrayRef,
413 data: ByteBufferMut,
414}
415
416fn gather_slices_constant_dispatch(
417 starts: &PrimitiveArray,
418 length: usize,
419 offsets: &PrimitiveArray,
420 data: &[u8],
421 output_len: usize,
422 out_offset_ptype: PType,
423) -> VortexResult<GatheredPiecewiseVarBin> {
424 match_each_unsigned_integer_ptype!(starts.ptype(), |S| {
425 gather_slices_constant_start_dispatch::<S>(
426 starts,
427 length,
428 offsets,
429 data,
430 output_len,
431 out_offset_ptype,
432 )
433 })
434}
435
436fn gather_slices_constant_start_dispatch<S>(
437 starts: &PrimitiveArray,
438 length: usize,
439 offsets: &PrimitiveArray,
440 data: &[u8],
441 output_len: usize,
442 out_offset_ptype: PType,
443) -> VortexResult<GatheredPiecewiseVarBin>
444where
445 S: UnsignedPType,
446{
447 match offsets.ptype() {
448 PType::U8 => gather_slices_constant_length::<S, u8>(
449 offsets.as_slice::<u8>(),
450 data,
451 starts.as_slice::<S>(),
452 length,
453 output_len,
454 out_offset_ptype,
455 ),
456 PType::U16 => gather_slices_constant_length::<S, u16>(
457 offsets.as_slice::<u16>(),
458 data,
459 starts.as_slice::<S>(),
460 length,
461 output_len,
462 out_offset_ptype,
463 ),
464 PType::U32 => gather_slices_constant_length::<S, u32>(
465 offsets.as_slice::<u32>(),
466 data,
467 starts.as_slice::<S>(),
468 length,
469 output_len,
470 out_offset_ptype,
471 ),
472 PType::U64 => gather_slices_constant_length::<S, u64>(
473 offsets.as_slice::<u64>(),
474 data,
475 starts.as_slice::<S>(),
476 length,
477 output_len,
478 out_offset_ptype,
479 ),
480 _ => unreachable!("offsets were reinterpreted to an unsigned integer ptype"),
481 }
482}
483
484fn gather_slices_dispatch(
485 starts: &PrimitiveArray,
486 lengths: &PrimitiveArray,
487 offsets: &PrimitiveArray,
488 data: &[u8],
489 output_len: usize,
490 out_offset_ptype: PType,
491) -> VortexResult<GatheredPiecewiseVarBin> {
492 match_each_unsigned_integer_ptype!(starts.ptype(), |S| {
493 gather_slices_start_dispatch::<S>(
494 starts,
495 lengths,
496 offsets,
497 data,
498 output_len,
499 out_offset_ptype,
500 )
501 })
502}
503
504fn gather_slices_start_dispatch<S>(
505 starts: &PrimitiveArray,
506 lengths: &PrimitiveArray,
507 offsets: &PrimitiveArray,
508 data: &[u8],
509 output_len: usize,
510 out_offset_ptype: PType,
511) -> VortexResult<GatheredPiecewiseVarBin>
512where
513 S: UnsignedPType,
514{
515 match_each_unsigned_integer_ptype!(lengths.ptype(), |L| {
516 gather_slices_start_length_dispatch::<S, L>(
517 starts,
518 lengths,
519 offsets,
520 data,
521 output_len,
522 out_offset_ptype,
523 )
524 })
525}
526
527fn gather_slices_start_length_dispatch<S, L>(
528 starts: &PrimitiveArray,
529 lengths: &PrimitiveArray,
530 offsets: &PrimitiveArray,
531 data: &[u8],
532 output_len: usize,
533 out_offset_ptype: PType,
534) -> VortexResult<GatheredPiecewiseVarBin>
535where
536 S: UnsignedPType,
537 L: UnsignedPType,
538{
539 match offsets.ptype() {
540 PType::U8 => gather_slices::<S, L, u8>(
541 offsets.as_slice::<u8>(),
542 data,
543 starts.as_slice::<S>(),
544 lengths.as_slice::<L>(),
545 output_len,
546 out_offset_ptype,
547 ),
548 PType::U16 => gather_slices::<S, L, u16>(
549 offsets.as_slice::<u16>(),
550 data,
551 starts.as_slice::<S>(),
552 lengths.as_slice::<L>(),
553 output_len,
554 out_offset_ptype,
555 ),
556 PType::U32 => gather_slices::<S, L, u32>(
557 offsets.as_slice::<u32>(),
558 data,
559 starts.as_slice::<S>(),
560 lengths.as_slice::<L>(),
561 output_len,
562 out_offset_ptype,
563 ),
564 PType::U64 => gather_slices::<S, L, u64>(
565 offsets.as_slice::<u64>(),
566 data,
567 starts.as_slice::<S>(),
568 lengths.as_slice::<L>(),
569 output_len,
570 out_offset_ptype,
571 ),
572 _ => unreachable!("offsets were reinterpreted to an unsigned integer ptype"),
573 }
574}
575
576fn gather_slices_constant_length<S, Offset>(
577 offsets: &[Offset],
578 data: &[u8],
579 starts: &[S],
580 length: usize,
581 output_len: usize,
582 out_offset_ptype: PType,
583) -> VortexResult<GatheredPiecewiseVarBin>
584where
585 S: UnsignedPType,
586 Offset: IntegerPType,
587{
588 let computed_len = starts
589 .len()
590 .checked_mul(length)
591 .ok_or_else(|| vortex_err!("PiecewiseSequenceArray output length overflows usize"))?;
592 vortex_ensure!(
593 computed_len == output_len,
594 "PiecewiseSequenceArray expanded length {computed_len} does not match declared length {output_len}"
595 );
596
597 let mut new_offsets = Offsets::with_capacity(out_offset_ptype, output_len + 1);
598 new_offsets.push(0);
599 let mut output_bytes = 0usize;
600
601 for start in starts {
602 let start = start.as_();
603 if length == 0 {
604 continue;
605 }
606
607 let offset_range = &offsets[start..][..=length];
608 let byte_start = offset_range[0].as_();
609 let byte_end = offset_range[length].as_();
610 vortex_ensure!(
611 byte_start <= byte_end && byte_end <= data.len(),
612 "VarBin offsets range {byte_start}..{byte_end} exceeds data length {}",
613 data.len()
614 );
615
616 for &offset in &offset_range[1..] {
617 let offset = offset.as_();
618 let relative = offset.checked_sub(byte_start).ok_or_else(|| {
619 vortex_err!("VarBin offsets are not monotonic at offset {offset}")
620 })?;
621 let output_offset = output_bytes.checked_add(relative).ok_or_else(|| {
622 vortex_err!("PiecewiseSequence VarBin output byte length overflow")
623 })?;
624 new_offsets.push(output_offset);
625 }
626
627 output_bytes = output_bytes
628 .checked_add(byte_end - byte_start)
629 .ok_or_else(|| vortex_err!("PiecewiseSequence VarBin output byte length overflow"))?;
630 }
631
632 let mut new_data = ByteBufferMut::with_capacity(output_bytes);
633 let spare = &mut new_data.spare_capacity_mut()[..output_bytes];
634 let mut cursor = 0usize;
635 for start in starts {
636 let start = start.as_();
637 if length == 0 {
638 continue;
639 }
640
641 let offset_range = &offsets[start..][..=length];
642 let byte_start = offset_range[0].as_();
643 let byte_end = offset_range[length].as_();
644 let src = &data[byte_start..byte_end];
645 unsafe {
647 ptr::copy_nonoverlapping(
648 src.as_ptr(),
649 spare[cursor..][..src.len()].as_mut_ptr().cast::<u8>(),
650 src.len(),
651 );
652 }
653 cursor += src.len();
654 }
655 unsafe { new_data.set_len(cursor) };
657 vortex_ensure!(
658 new_data.len() == output_bytes,
659 "PiecewiseSequenceArray gathered byte length {} does not match declared byte length {output_bytes}",
660 new_data.len()
661 );
662
663 let offsets = new_offsets.into_array();
664 Ok(GatheredPiecewiseVarBin {
665 offsets,
666 data: new_data,
667 })
668}
669
670fn gather_slices<S, L, Offset>(
671 offsets: &[Offset],
672 data: &[u8],
673 starts: &[S],
674 lengths: &[L],
675 output_len: usize,
676 out_offset_ptype: PType,
677) -> VortexResult<GatheredPiecewiseVarBin>
678where
679 S: UnsignedPType,
680 L: UnsignedPType,
681 Offset: IntegerPType,
682{
683 let mut new_offsets = Offsets::with_capacity(out_offset_ptype, output_len + 1);
684 new_offsets.push(0);
685 let mut output_bytes = 0usize;
686
687 for (&start, &length) in starts.iter().zip_eq(lengths) {
688 let start = start.as_();
689 let length = length.as_();
690 if length == 0 {
691 continue;
692 }
693
694 let offset_range = &offsets[start..][..=length];
695 let byte_start = offset_range[0].as_();
696 let byte_end = offset_range[length].as_();
697 vortex_ensure!(
698 byte_start <= byte_end && byte_end <= data.len(),
699 "VarBin offsets range {byte_start}..{byte_end} exceeds data length {}",
700 data.len()
701 );
702
703 for &offset in &offset_range[1..] {
704 let offset = offset.as_();
705 let relative = offset.checked_sub(byte_start).ok_or_else(|| {
706 vortex_err!("VarBin offsets are not monotonic at offset {offset}")
707 })?;
708 let output_offset = output_bytes.checked_add(relative).ok_or_else(|| {
709 vortex_err!("PiecewiseSequence VarBin output byte length overflow")
710 })?;
711 new_offsets.push(output_offset);
712 }
713
714 output_bytes = output_bytes
715 .checked_add(byte_end - byte_start)
716 .ok_or_else(|| vortex_err!("PiecewiseSequence VarBin output byte length overflow"))?;
717 }
718 vortex_ensure!(
719 new_offsets.len() == output_len + 1,
720 "PiecewiseSequenceArray expanded length {} does not match declared length {output_len}",
721 new_offsets.len() - 1
722 );
723
724 let mut new_data = ByteBufferMut::with_capacity(output_bytes);
725 let spare = &mut new_data.spare_capacity_mut()[..output_bytes];
726 let mut cursor = 0usize;
727 for (&start, &length) in starts.iter().zip_eq(lengths) {
728 let start = start.as_();
729 let length = length.as_();
730 if length == 0 {
731 continue;
732 }
733
734 let offset_range = &offsets[start..][..=length];
735 let byte_start = offset_range[0].as_();
736 let byte_end = offset_range[length].as_();
737 let src = &data[byte_start..byte_end];
738 unsafe {
740 ptr::copy_nonoverlapping(
741 src.as_ptr(),
742 spare[cursor..][..src.len()].as_mut_ptr().cast::<u8>(),
743 src.len(),
744 );
745 }
746 cursor += src.len();
747 }
748 unsafe { new_data.set_len(cursor) };
750 vortex_ensure!(
751 new_data.len() == output_bytes,
752 "PiecewiseSequenceArray gathered byte length {} does not match declared byte length {output_bytes}",
753 new_data.len()
754 );
755
756 let offsets = new_offsets.into_array();
757 Ok(GatheredPiecewiseVarBin {
758 offsets,
759 data: new_data,
760 })
761}
762
763fn take_nullable<Index: IntegerPType, Offset: IntegerPType>(
764 dtype: DType,
765 offsets: &[Offset],
766 data: &[u8],
767 indices: &[Index],
768 data_validity: Mask,
769 indices_validity: Mask,
770 out_offset_ptype: PType,
771) -> VarBinArray {
772 let mut new_offsets = Offsets::with_capacity(out_offset_ptype, indices.len() + 1);
773 new_offsets.push(0);
774 let mut current_offset = 0usize;
775
776 let mut validity_buffer = BitBufferMut::with_capacity(indices.len());
777
778 let mut valid_indices = Vec::with_capacity(indices.len());
780
781 for (data_idx, index_valid) in indices.iter().zip(indices_validity.iter()) {
783 if !index_valid {
784 validity_buffer.append(false);
785 new_offsets.push(current_offset);
786 continue;
787 }
788 let data_idx_usize = data_idx
789 .to_usize()
790 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", data_idx));
791 if data_validity.value(data_idx_usize) {
792 validity_buffer.append(true);
793 let start = offsets[data_idx_usize];
794 let stop = offsets[data_idx_usize + 1];
795 current_offset += (stop - start)
796 .to_usize()
797 .vortex_expect("Failed to cast offset to usize");
798 new_offsets.push(current_offset);
799 valid_indices.push(data_idx_usize);
800 } else {
801 validity_buffer.append(false);
802 new_offsets.push(current_offset);
803 }
804 }
805
806 let mut new_data = ByteBufferMut::with_capacity(current_offset);
807
808 for data_idx in valid_indices {
810 let start = offsets[data_idx]
811 .to_usize()
812 .vortex_expect("Failed to cast max offset to usize");
813 let stop = offsets[data_idx + 1]
814 .to_usize()
815 .vortex_expect("Failed to cast max offset to usize");
816 new_data.extend_from_slice(&data[start..stop]);
817 }
818
819 let array_validity = Validity::from(validity_buffer.freeze());
820 let new_offsets = new_offsets.into_array();
821
822 unsafe { VarBinArray::new_unchecked(new_offsets, new_data.freeze(), dtype, array_validity) }
825}
826
827#[cfg(test)]
828mod tests {
829 use std::iter;
830
831 use rstest::rstest;
832 use vortex_buffer::ByteBuffer;
833 use vortex_buffer::buffer;
834 use vortex_error::VortexResult;
835
836 use crate::IntoArray;
837 use crate::VortexSessionExecute;
838 use crate::array_session;
839 use crate::arrays::VarBinArray;
840 use crate::arrays::VarBinViewArray;
841 use crate::arrays::varbin::compute::take::PrimitiveArray;
842 use crate::assert_arrays_eq;
843 use crate::compute::conformance::take::test_take_conformance;
844 use crate::dtype::DType;
845 use crate::dtype::Nullability;
846 use crate::dtype::PType;
847 use crate::validity::Validity;
848
849 #[test]
850 fn test_null_take() {
851 let arr = VarBinArray::from_iter([Some("h")], DType::Utf8(Nullability::NonNullable));
852
853 let idx1: PrimitiveArray = (0..1).collect();
854
855 assert_eq!(
856 arr.take(idx1.into_array()).unwrap().dtype(),
857 &DType::Utf8(Nullability::NonNullable)
858 );
859
860 let idx2: PrimitiveArray = PrimitiveArray::from_option_iter(vec![Some(0)]);
861
862 assert_eq!(
863 arr.take(idx2.into_array()).unwrap().dtype(),
864 &DType::Utf8(Nullability::Nullable)
865 );
866 }
867
868 #[rstest]
869 #[case(VarBinArray::from_iter(
870 ["hello", "world", "test", "data", "array"].map(Some),
871 DType::Utf8(Nullability::NonNullable),
872 ))]
873 #[case(VarBinArray::from_iter(
874 [Some("hello"), None, Some("test"), Some("data"), None],
875 DType::Utf8(Nullability::Nullable),
876 ))]
877 #[case(VarBinArray::from_iter(
878 [b"hello".as_slice(), b"world", b"test", b"data", b"array"].map(Some),
879 DType::Binary(Nullability::NonNullable),
880 ))]
881 #[case(VarBinArray::from_iter(["single"].map(Some), DType::Utf8(Nullability::NonNullable)))]
882 fn test_take_varbin_conformance(#[case] array: VarBinArray) {
883 test_take_conformance(
884 &array.into_array(),
885 &mut array_session().create_execution_ctx(),
886 );
887 }
888
889 #[test]
890 fn test_take_overflow() {
891 let mut ctx = array_session().create_execution_ctx();
892 let scream = iter::once("a").cycle().take(128).collect::<String>();
893 let bytes = ByteBuffer::copy_from(scream.as_bytes());
894 let offsets = buffer![0u8, 128u8].into_array();
895
896 let array = VarBinArray::new(
897 offsets,
898 bytes,
899 DType::Utf8(Nullability::NonNullable),
900 Validity::NonNullable,
901 );
902
903 let indices = buffer![0u32; 3].into_array();
904 let taken = array.take(indices).unwrap();
905
906 let expected = VarBinViewArray::from_iter(
907 [Some(scream.clone()), Some(scream.clone()), Some(scream)],
908 DType::Utf8(Nullability::NonNullable),
909 );
910 assert_arrays_eq!(expected, taken, &mut ctx);
911 }
912
913 #[rstest]
914 #[case(PType::U32, u32::MAX as usize, PType::U32)]
915 #[case(PType::U32, u32::MAX as usize + 1, PType::U64)]
916 #[case(PType::I32, i32::MAX as usize, PType::I32)]
917 #[case(PType::I32, i32::MAX as usize + 1, PType::I64)]
918 #[case(PType::U64, 8, PType::U64)]
919 #[case(PType::I64, 8, PType::I64)]
920 fn test_offsets_widen(
921 #[case] out_offset_ptype: PType,
922 #[case] max_offset: usize,
923 #[case] expected: PType,
924 ) {
925 let mut sink = super::Offsets::with_capacity(out_offset_ptype, 2);
926 sink.push(0);
927 sink.push(max_offset);
928 assert_eq!(
929 PType::try_from(sink.into_array().dtype()).unwrap(),
930 expected
931 );
932 }
933
934 #[test]
935 fn test_offset_widen_values() -> VortexResult<()> {
936 let mut ctx = array_session().create_execution_ctx();
937 let big = u32::MAX as usize + 5;
938 let mut sink = super::Offsets::with_capacity(PType::U32, 3);
939 sink.push(0);
940 sink.push(7);
941 sink.push(big);
942
943 let array = sink.into_array().execute::<PrimitiveArray>(&mut ctx)?;
944 assert_eq!(array.as_slice::<u64>(), &[0, 7, big as u64]);
945 Ok(())
946 }
947
948 #[test]
949 fn test_take_signed() {
950 let mut ctx = array_session().create_execution_ctx();
951 let array = VarBinArray::new(
952 buffer![0i32, 5, 10].into_array(),
953 ByteBuffer::copy_from(b"helloworld"),
954 DType::Utf8(Nullability::NonNullable),
955 Validity::NonNullable,
956 );
957
958 let taken = array.take(buffer![1u32, 0].into_array()).unwrap();
959
960 let expected = VarBinViewArray::from_iter(
961 [Some("world"), Some("hello")],
962 DType::Utf8(Nullability::NonNullable),
963 );
964 assert_arrays_eq!(expected, taken, &mut ctx);
965 }
966}