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