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_ensure_eq;
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_eq!(
593 computed_len,
594 output_len,
595 "PiecewiseSequenceArray expanded length does not match declared length",
596 );
597
598 let mut new_offsets = Offsets::with_capacity(out_offset_ptype, output_len + 1);
599 new_offsets.push(0);
600 let mut output_bytes = 0usize;
601
602 for start in starts {
603 let start = start.as_();
604 if length == 0 {
605 continue;
606 }
607
608 let offset_range = &offsets[start..][..=length];
609 let byte_start = offset_range[0].as_();
610 let byte_end = offset_range[length].as_();
611 vortex_ensure!(
612 byte_start <= byte_end && byte_end <= data.len(),
613 "VarBin offsets range {byte_start}..{byte_end} exceeds data length {}",
614 data.len()
615 );
616
617 for &offset in &offset_range[1..] {
618 let offset = offset.as_();
619 let relative = offset.checked_sub(byte_start).ok_or_else(|| {
620 vortex_err!("VarBin offsets are not monotonic at offset {offset}")
621 })?;
622 let output_offset = output_bytes.checked_add(relative).ok_or_else(|| {
623 vortex_err!("PiecewiseSequence VarBin output byte length overflow")
624 })?;
625 new_offsets.push(output_offset);
626 }
627
628 output_bytes = output_bytes
629 .checked_add(byte_end - byte_start)
630 .ok_or_else(|| vortex_err!("PiecewiseSequence VarBin output byte length overflow"))?;
631 }
632
633 let mut new_data = ByteBufferMut::with_capacity(output_bytes);
634 let spare = &mut new_data.spare_capacity_mut()[..output_bytes];
635 let mut cursor = 0usize;
636 for start in starts {
637 let start = start.as_();
638 if length == 0 {
639 continue;
640 }
641
642 let offset_range = &offsets[start..][..=length];
643 let byte_start = offset_range[0].as_();
644 let byte_end = offset_range[length].as_();
645 let src = &data[byte_start..byte_end];
646 spare[cursor..][..src.len()].write_copy_of_slice(src);
647 cursor += src.len();
648 }
649 unsafe { new_data.set_len(cursor) };
651 vortex_ensure_eq!(
652 new_data.len(),
653 output_bytes,
654 "PiecewiseSequenceArray gathered byte length does not match declared byte length",
655 );
656
657 let offsets = new_offsets.into_array();
658 Ok(GatheredPiecewiseVarBin {
659 offsets,
660 data: new_data,
661 })
662}
663
664fn gather_slices<S, L, Offset>(
665 offsets: &[Offset],
666 data: &[u8],
667 starts: &[S],
668 lengths: &[L],
669 output_len: usize,
670 out_offset_ptype: PType,
671) -> VortexResult<GatheredPiecewiseVarBin>
672where
673 S: UnsignedPType,
674 L: UnsignedPType,
675 Offset: IntegerPType,
676{
677 let mut new_offsets = Offsets::with_capacity(out_offset_ptype, output_len + 1);
678 new_offsets.push(0);
679 let mut output_bytes = 0usize;
680
681 for (&start, &length) in starts.iter().zip_eq(lengths) {
682 let start = start.as_();
683 let length = length.as_();
684 if length == 0 {
685 continue;
686 }
687
688 let offset_range = &offsets[start..][..=length];
689 let byte_start = offset_range[0].as_();
690 let byte_end = offset_range[length].as_();
691 vortex_ensure!(
692 byte_start <= byte_end && byte_end <= data.len(),
693 "VarBin offsets range {byte_start}..{byte_end} exceeds data length {}",
694 data.len()
695 );
696
697 for &offset in &offset_range[1..] {
698 let offset = offset.as_();
699 let relative = offset.checked_sub(byte_start).ok_or_else(|| {
700 vortex_err!("VarBin offsets are not monotonic at offset {offset}")
701 })?;
702 let output_offset = output_bytes.checked_add(relative).ok_or_else(|| {
703 vortex_err!("PiecewiseSequence VarBin output byte length overflow")
704 })?;
705 new_offsets.push(output_offset);
706 }
707
708 output_bytes = output_bytes
709 .checked_add(byte_end - byte_start)
710 .ok_or_else(|| vortex_err!("PiecewiseSequence VarBin output byte length overflow"))?;
711 }
712 vortex_ensure_eq!(
713 new_offsets.len(),
714 output_len + 1,
715 "PiecewiseSequenceArray expanded offsets length does not match declared length plus one",
716 );
717
718 let mut new_data = ByteBufferMut::with_capacity(output_bytes);
719 let spare = &mut new_data.spare_capacity_mut()[..output_bytes];
720 let mut cursor = 0usize;
721 for (&start, &length) in starts.iter().zip_eq(lengths) {
722 let start = start.as_();
723 let length = length.as_();
724 if length == 0 {
725 continue;
726 }
727
728 let offset_range = &offsets[start..][..=length];
729 let byte_start = offset_range[0].as_();
730 let byte_end = offset_range[length].as_();
731 let src = &data[byte_start..byte_end];
732 spare[cursor..][..src.len()].write_copy_of_slice(src);
733 cursor += src.len();
734 }
735 unsafe { new_data.set_len(cursor) };
737 vortex_ensure_eq!(
738 new_data.len(),
739 output_bytes,
740 "PiecewiseSequenceArray gathered byte length does not match declared byte length",
741 );
742
743 let offsets = new_offsets.into_array();
744 Ok(GatheredPiecewiseVarBin {
745 offsets,
746 data: new_data,
747 })
748}
749
750fn take_nullable<Index: IntegerPType, Offset: IntegerPType>(
751 dtype: DType,
752 offsets: &[Offset],
753 data: &[u8],
754 indices: &[Index],
755 data_validity: Mask,
756 indices_validity: Mask,
757 out_offset_ptype: PType,
758) -> VarBinArray {
759 let mut new_offsets = Offsets::with_capacity(out_offset_ptype, indices.len() + 1);
760 new_offsets.push(0);
761 let mut current_offset = 0usize;
762
763 let mut validity_buffer = BitBufferMut::with_capacity(indices.len());
764
765 let mut valid_indices = Vec::with_capacity(indices.len());
767
768 for (data_idx, index_valid) in indices.iter().zip(indices_validity.iter()) {
770 if !index_valid {
771 validity_buffer.append(false);
772 new_offsets.push(current_offset);
773 continue;
774 }
775 let data_idx_usize = data_idx
776 .to_usize()
777 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", data_idx));
778 if data_validity.value(data_idx_usize) {
779 validity_buffer.append(true);
780 let start = offsets[data_idx_usize];
781 let stop = offsets[data_idx_usize + 1];
782 current_offset += (stop - start)
783 .to_usize()
784 .vortex_expect("Failed to cast offset to usize");
785 new_offsets.push(current_offset);
786 valid_indices.push(data_idx_usize);
787 } else {
788 validity_buffer.append(false);
789 new_offsets.push(current_offset);
790 }
791 }
792
793 let mut new_data = ByteBufferMut::with_capacity(current_offset);
794
795 for data_idx in valid_indices {
797 let start = offsets[data_idx]
798 .to_usize()
799 .vortex_expect("Failed to cast max offset to usize");
800 let stop = offsets[data_idx + 1]
801 .to_usize()
802 .vortex_expect("Failed to cast max offset to usize");
803 new_data.extend_from_slice(&data[start..stop]);
804 }
805
806 let array_validity = Validity::from(validity_buffer.freeze());
807 let new_offsets = new_offsets.into_array();
808
809 unsafe { VarBinArray::new_unchecked(new_offsets, new_data.freeze(), dtype, array_validity) }
812}
813
814#[cfg(test)]
815mod tests {
816 use std::iter;
817
818 use rstest::rstest;
819 use vortex_buffer::ByteBuffer;
820 use vortex_buffer::buffer;
821 use vortex_error::VortexResult;
822
823 use crate::IntoArray;
824 use crate::VortexSessionExecute;
825 use crate::array_session;
826 use crate::arrays::VarBinArray;
827 use crate::arrays::VarBinViewArray;
828 use crate::arrays::varbin::compute::take::PrimitiveArray;
829 use crate::assert_arrays_eq;
830 use crate::compute::conformance::take::test_take_conformance;
831 use crate::dtype::DType;
832 use crate::dtype::Nullability;
833 use crate::dtype::PType;
834 use crate::validity::Validity;
835
836 #[test]
837 fn test_null_take() {
838 let arr = VarBinArray::from_iter([Some("h")], DType::Utf8(Nullability::NonNullable));
839
840 let idx1: PrimitiveArray = (0..1).collect();
841
842 assert_eq!(
843 arr.take(idx1.into_array()).unwrap().dtype(),
844 &DType::Utf8(Nullability::NonNullable)
845 );
846
847 let idx2: PrimitiveArray = PrimitiveArray::from_option_iter(vec![Some(0)]);
848
849 assert_eq!(
850 arr.take(idx2.into_array()).unwrap().dtype(),
851 &DType::Utf8(Nullability::Nullable)
852 );
853 }
854
855 #[rstest]
856 #[case(VarBinArray::from_iter(
857 ["hello", "world", "test", "data", "array"].map(Some),
858 DType::Utf8(Nullability::NonNullable),
859 ))]
860 #[case(VarBinArray::from_iter(
861 [Some("hello"), None, Some("test"), Some("data"), None],
862 DType::Utf8(Nullability::Nullable),
863 ))]
864 #[case(VarBinArray::from_iter(
865 [b"hello".as_slice(), b"world", b"test", b"data", b"array"].map(Some),
866 DType::Binary(Nullability::NonNullable),
867 ))]
868 #[case(VarBinArray::from_iter(["single"].map(Some), DType::Utf8(Nullability::NonNullable)))]
869 fn test_take_varbin_conformance(#[case] array: VarBinArray) {
870 test_take_conformance(
871 &array.into_array(),
872 &mut array_session().create_execution_ctx(),
873 );
874 }
875
876 #[test]
877 fn test_take_overflow() {
878 let mut ctx = array_session().create_execution_ctx();
879 let scream = iter::once("a").cycle().take(128).collect::<String>();
880 let bytes = ByteBuffer::copy_from(scream.as_bytes());
881 let offsets = buffer![0u8, 128u8].into_array();
882
883 let array = VarBinArray::new(
884 offsets,
885 bytes,
886 DType::Utf8(Nullability::NonNullable),
887 Validity::NonNullable,
888 );
889
890 let indices = buffer![0u32; 3].into_array();
891 let taken = array.take(indices).unwrap();
892
893 let expected = VarBinViewArray::from_iter(
894 [Some(scream.clone()), Some(scream.clone()), Some(scream)],
895 DType::Utf8(Nullability::NonNullable),
896 );
897 assert_arrays_eq!(expected, taken, &mut ctx);
898 }
899
900 #[rstest]
901 #[case(PType::U32, u32::MAX as usize, PType::U32)]
902 #[case(PType::U32, u32::MAX as usize + 1, PType::U64)]
903 #[case(PType::I32, i32::MAX as usize, PType::I32)]
904 #[case(PType::I32, i32::MAX as usize + 1, PType::I64)]
905 #[case(PType::U64, 8, PType::U64)]
906 #[case(PType::I64, 8, PType::I64)]
907 fn test_offsets_widen(
908 #[case] out_offset_ptype: PType,
909 #[case] max_offset: usize,
910 #[case] expected: PType,
911 ) {
912 let mut sink = super::Offsets::with_capacity(out_offset_ptype, 2);
913 sink.push(0);
914 sink.push(max_offset);
915 assert_eq!(
916 PType::try_from(sink.into_array().dtype()).unwrap(),
917 expected
918 );
919 }
920
921 #[test]
922 fn test_offset_widen_values() -> VortexResult<()> {
923 let mut ctx = array_session().create_execution_ctx();
924 let big = u32::MAX as usize + 5;
925 let mut sink = super::Offsets::with_capacity(PType::U32, 3);
926 sink.push(0);
927 sink.push(7);
928 sink.push(big);
929
930 let array = sink.into_array().execute::<PrimitiveArray>(&mut ctx)?;
931 assert_eq!(array.as_slice::<u64>(), &[0, 7, big as u64]);
932 Ok(())
933 }
934
935 #[test]
936 fn test_take_signed() {
937 let mut ctx = array_session().create_execution_ctx();
938 let array = VarBinArray::new(
939 buffer![0i32, 5, 10].into_array(),
940 ByteBuffer::copy_from(b"helloworld"),
941 DType::Utf8(Nullability::NonNullable),
942 Validity::NonNullable,
943 );
944
945 let taken = array.take(buffer![1u32, 0].into_array()).unwrap();
946
947 let expected = VarBinViewArray::from_iter(
948 [Some("world"), Some("hello")],
949 DType::Utf8(Nullability::NonNullable),
950 );
951 assert_arrays_eq!(expected, taken, &mut ctx);
952 }
953}