1use itertools::Itertools as _;
5use vortex_buffer::BufferMut;
6use vortex_error::VortexExpect;
7use vortex_error::VortexResult;
8use vortex_error::vortex_ensure_eq;
9use vortex_error::vortex_err;
10use vortex_mask::Mask;
11
12use crate::ArrayRef;
13use crate::Columnar;
14use crate::IntoArray;
15use crate::array::ArrayView;
16use crate::arrays::ConstantArray;
17use crate::arrays::List;
18use crate::arrays::ListArray;
19use crate::arrays::PiecewiseSequence;
20use crate::arrays::PiecewiseSequenceArray;
21use crate::arrays::Primitive;
22use crate::arrays::PrimitiveArray;
23use crate::arrays::dict::TakeExecute;
24use crate::arrays::list::ListArrayExt;
25use crate::arrays::list::ListArraySlotsExt;
26use crate::arrays::piecewise_sequence::constant_unsigned_usize;
27use crate::arrays::piecewise_sequence::maybe_contiguous_slices;
28use crate::arrays::primitive::PrimitiveArrayExt;
29use crate::dtype::IntegerPType;
30use crate::dtype::UnsignedPType;
31use crate::executor::ExecutionCtx;
32use crate::match_each_unsigned_integer_ptype;
33use crate::match_smallest_offset_type;
34use crate::validity::Validity;
35
36impl TakeExecute for List {
40 #[expect(clippy::cognitive_complexity)]
46 fn take(
47 array: ArrayView<'_, List>,
48 indices: &ArrayRef,
49 ctx: &mut ExecutionCtx,
50 ) -> VortexResult<Option<ArrayRef>> {
51 if let Some(piecewise_indices) = indices.as_opt::<PiecewiseSequence>()
52 && let Some(taken) = take_slices(array, piecewise_indices, indices, ctx)?
53 {
54 return Ok(Some(taken));
55 }
56
57 let new_validity = array.validity()?.take(indices)?;
58 let indices = indices.clone().execute::<PrimitiveArray>(ctx)?;
59 let indices = indices.reinterpret_cast(indices.ptype().to_unsigned());
60 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
61 let offsets = offsets.reinterpret_cast(offsets.ptype().to_unsigned());
62 let validity_mask = new_validity.execute_mask(indices.len(), ctx)?;
63 let total_approx = array.elements().len().saturating_mul(indices.len());
65
66 match_each_unsigned_integer_ptype!(offsets.ptype(), |O| {
67 match_each_unsigned_integer_ptype!(indices.ptype(), |I| {
68 match_smallest_offset_type!(total_approx, |OutOffset| {
69 take_with_piecewise_elements::<I, O, OutOffset>(
70 array,
71 offsets.as_view(),
72 indices.as_view(),
73 new_validity,
74 &validity_mask,
75 )
76 .map(Some)
77 })
78 })
79 })
80 }
81}
82
83fn take_with_piecewise_elements<I: IntegerPType, O: IntegerPType, OutOffset: IntegerPType>(
84 array: ArrayView<'_, List>,
85 offsets_array: ArrayView<'_, Primitive>,
86 indices_array: ArrayView<'_, Primitive>,
87 new_validity: Validity,
88 validity_mask: &Mask,
89) -> VortexResult<ArrayRef> {
90 let offsets: &[O] = offsets_array.as_slice();
91 let indices: &[I] = indices_array.as_slice();
92
93 let offsets_capacity = indices
94 .len()
95 .checked_add(1)
96 .ok_or_else(|| vortex_err!("List take offsets length overflow"))?;
97 let mut new_offsets = BufferMut::<OutOffset>::with_capacity(offsets_capacity);
98 let mut element_starts = BufferMut::<u64>::with_capacity(indices.len());
99 let mut element_lengths = BufferMut::<u64>::with_capacity(indices.len());
100
101 let mut current_offset = 0usize;
102 new_offsets.push(OutOffset::zero());
103
104 for (&data_idx, is_valid) in indices.iter().zip_eq(validity_mask.iter()) {
105 if !is_valid {
106 new_offsets.push(new_offset_value::<OutOffset>(current_offset));
107 element_starts.push(0);
108 element_lengths.push(0);
109 continue;
110 }
111
112 let data_idx: usize = data_idx.as_();
113
114 let start = offsets[data_idx];
115 let stop = offsets[data_idx + 1];
116 let start: usize = start.as_();
117 let stop: usize = stop.as_();
118 let length = stop - start;
119
120 current_offset = current_offset
121 .checked_add(length)
122 .ok_or_else(|| vortex_err!("List take output elements length overflow"))?;
123 new_offsets.push(new_offset_value::<OutOffset>(current_offset));
124 element_starts.push(start as u64);
125 element_lengths.push(length as u64);
126 }
127
128 let new_offsets = PrimitiveArray::new(new_offsets.freeze(), Validity::NonNullable).into_array();
129 let multipliers = ConstantArray::new(1u64, element_starts.len()).into_array();
130
131 let element_indices = unsafe {
135 PiecewiseSequenceArray::new_unchecked(
136 element_starts.into_array(),
137 element_lengths.into_array(),
138 multipliers,
139 current_offset,
140 )
141 };
142 let new_elements = array.elements().take(element_indices.into_array())?;
143
144 Ok(unsafe { ListArray::new_unchecked(new_elements, new_offsets, new_validity) }.into_array())
147}
148
149fn take_slices(
150 array: ArrayView<'_, List>,
151 indices: ArrayView<'_, PiecewiseSequence>,
152 indices_ref: &ArrayRef,
153 ctx: &mut ExecutionCtx,
154) -> VortexResult<Option<ArrayRef>> {
155 let Some((starts, lengths)) = maybe_contiguous_slices(indices, ctx)? else {
156 return Ok(None);
157 };
158 let data_validity = array
159 .list_validity()
160 .execute_mask(array.as_ref().len(), ctx)?;
161 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
162 let offsets = offsets.reinterpret_cast(offsets.ptype().to_unsigned());
163 let output_len = indices_ref.len();
164
165 let taken = match lengths {
166 Columnar::Constant(lengths) => {
167 let length = constant_unsigned_usize(&lengths);
168 take_slices_constant_start_dispatch(
169 array,
170 &starts,
171 length,
172 &offsets,
173 indices_ref,
174 output_len,
175 &data_validity,
176 )?
177 }
178 Columnar::Canonical(lengths) => {
179 let lengths = lengths.into_primitive();
180 take_slices_start_dispatch(
181 array,
182 &starts,
183 &lengths,
184 &offsets,
185 indices_ref,
186 output_len,
187 &data_validity,
188 )?
189 }
190 };
191 Ok(Some(taken))
192}
193
194fn take_slices_constant_start_dispatch(
195 array: ArrayView<'_, List>,
196 starts: &PrimitiveArray,
197 length: usize,
198 offsets: &PrimitiveArray,
199 indices_ref: &ArrayRef,
200 output_len: usize,
201 data_validity: &Mask,
202) -> VortexResult<ArrayRef> {
203 match_each_unsigned_integer_ptype!(starts.ptype(), |S| {
204 take_slices_constant_offset_dispatch::<S>(
205 array,
206 starts,
207 length,
208 offsets,
209 indices_ref,
210 output_len,
211 data_validity,
212 )
213 })
214}
215
216fn take_slices_constant_offset_dispatch<S>(
217 array: ArrayView<'_, List>,
218 starts: &PrimitiveArray,
219 length: usize,
220 offsets: &PrimitiveArray,
221 indices_ref: &ArrayRef,
222 output_len: usize,
223 data_validity: &Mask,
224) -> VortexResult<ArrayRef>
225where
226 S: UnsignedPType,
227{
228 match_each_unsigned_integer_ptype!(offsets.ptype(), |O| {
229 take_slices_constant_length::<S, O>(
230 array,
231 starts.as_slice::<S>(),
232 length,
233 offsets.as_slice::<O>(),
234 indices_ref,
235 output_len,
236 data_validity,
237 )
238 })
239}
240
241fn take_slices_start_dispatch(
242 array: ArrayView<'_, List>,
243 starts: &PrimitiveArray,
244 lengths: &PrimitiveArray,
245 offsets: &PrimitiveArray,
246 indices_ref: &ArrayRef,
247 output_len: usize,
248 data_validity: &Mask,
249) -> VortexResult<ArrayRef> {
250 match_each_unsigned_integer_ptype!(starts.ptype(), |S| {
251 take_slices_length_dispatch::<S>(
252 array,
253 starts,
254 lengths,
255 offsets,
256 indices_ref,
257 output_len,
258 data_validity,
259 )
260 })
261}
262
263fn take_slices_length_dispatch<S>(
264 array: ArrayView<'_, List>,
265 starts: &PrimitiveArray,
266 lengths: &PrimitiveArray,
267 offsets: &PrimitiveArray,
268 indices_ref: &ArrayRef,
269 output_len: usize,
270 data_validity: &Mask,
271) -> VortexResult<ArrayRef>
272where
273 S: UnsignedPType,
274{
275 match_each_unsigned_integer_ptype!(lengths.ptype(), |L| {
276 take_slices_offset_dispatch::<S, L>(
277 array,
278 starts,
279 lengths,
280 offsets,
281 indices_ref,
282 output_len,
283 data_validity,
284 )
285 })
286}
287
288fn take_slices_offset_dispatch<S, L>(
289 array: ArrayView<'_, List>,
290 starts: &PrimitiveArray,
291 lengths: &PrimitiveArray,
292 offsets: &PrimitiveArray,
293 indices_ref: &ArrayRef,
294 output_len: usize,
295 data_validity: &Mask,
296) -> VortexResult<ArrayRef>
297where
298 S: UnsignedPType,
299 L: UnsignedPType,
300{
301 match_each_unsigned_integer_ptype!(offsets.ptype(), |O| {
302 take_slices_typed::<S, L, O>(
303 array,
304 starts.as_slice::<S>(),
305 lengths.as_slice::<L>(),
306 offsets.as_slice::<O>(),
307 indices_ref,
308 output_len,
309 data_validity,
310 )
311 })
312}
313
314fn take_slices_constant_length<S, Offset>(
315 array: ArrayView<'_, List>,
316 starts: &[S],
317 length: usize,
318 offsets: &[Offset],
319 indices_ref: &ArrayRef,
320 output_len: usize,
321 data_validity: &Mask,
322) -> VortexResult<ArrayRef>
323where
324 S: UnsignedPType,
325 Offset: UnsignedPType,
326{
327 let computed_len = starts
328 .len()
329 .checked_mul(length)
330 .ok_or_else(|| vortex_err!("PiecewiseSequenceArray output length overflows usize"))?;
331 vortex_ensure_eq!(
332 computed_len,
333 output_len,
334 "PiecewiseSequenceArray expanded length does not match declared length",
335 );
336 let all_valid = data_validity.all_true();
337 let total_elements = if all_valid {
338 piecewise_list_elements_len_constant(offsets, starts, length)?
339 } else {
340 piecewise_list_elements_len_constant_validity(offsets, starts, length, data_validity)?
341 };
342 let validity = array.validity()?.take(indices_ref)?;
343
344 match_smallest_offset_type!(total_elements, |OutOffset| {
345 let gathered = if all_valid {
346 gather_piecewise_list_constant_length::<S, Offset, OutOffset>(
347 array.elements(),
348 offsets,
349 starts,
350 length,
351 output_len,
352 total_elements,
353 )?
354 } else {
355 gather_piecewise_list_constant_length_validity::<S, Offset, OutOffset>(
356 array.elements(),
357 offsets,
358 starts,
359 length,
360 output_len,
361 total_elements,
362 data_validity,
363 )?
364 };
365
366 Ok(
370 unsafe { ListArray::new_unchecked(gathered.elements, gathered.offsets, validity) }
371 .into_array(),
372 )
373 })
374}
375
376fn take_slices_typed<S, L, Offset>(
377 array: ArrayView<'_, List>,
378 starts: &[S],
379 lengths: &[L],
380 offsets: &[Offset],
381 indices_ref: &ArrayRef,
382 output_len: usize,
383 data_validity: &Mask,
384) -> VortexResult<ArrayRef>
385where
386 S: UnsignedPType,
387 L: UnsignedPType,
388 Offset: UnsignedPType,
389{
390 let mut computed_len = 0usize;
391 for &length in lengths {
392 let length: usize = length.as_();
393 computed_len = computed_len
394 .checked_add(length)
395 .ok_or_else(|| vortex_err!("PiecewiseSequenceArray output length overflows usize"))?;
396 }
397 vortex_ensure_eq!(
398 computed_len,
399 output_len,
400 "PiecewiseSequenceArray expanded length does not match declared length",
401 );
402 let all_valid = data_validity.all_true();
403 let total_elements = if all_valid {
404 piecewise_list_elements_len(offsets, starts, lengths)?
405 } else {
406 piecewise_list_elements_len_validity(offsets, starts, lengths, data_validity)?
407 };
408
409 match_smallest_offset_type!(total_elements, |OutOffset| {
410 let gathered = if all_valid {
411 gather_piecewise_list::<S, L, Offset, OutOffset>(
412 array.elements(),
413 offsets,
414 starts,
415 lengths,
416 output_len,
417 total_elements,
418 )?
419 } else {
420 gather_piecewise_list_validity::<S, L, Offset, OutOffset>(
421 array.elements(),
422 offsets,
423 starts,
424 lengths,
425 output_len,
426 total_elements,
427 data_validity,
428 )?
429 };
430 let validity = array.validity()?.take(indices_ref)?;
431
432 Ok(
436 unsafe { ListArray::new_unchecked(gathered.elements, gathered.offsets, validity) }
437 .into_array(),
438 )
439 })
440}
441
442struct GatheredList {
443 elements: ArrayRef,
444 offsets: ArrayRef,
445}
446
447struct ValidPieceGather<OutOffset> {
448 new_offsets: BufferMut<OutOffset>,
449 element_starts: BufferMut<u64>,
450 element_lengths: BufferMut<u64>,
451 output_elements: usize,
452}
453
454fn piecewise_list_elements_len_constant<S, Offset>(
455 offsets: &[Offset],
456 starts: &[S],
457 length: usize,
458) -> VortexResult<usize>
459where
460 S: UnsignedPType,
461 Offset: UnsignedPType,
462{
463 if length == 0 {
464 return Ok(0);
465 }
466
467 let mut total = 0usize;
468 for start in starts {
469 let start: usize = start.as_();
470 let offset_range = &offsets[start..][..=length];
471 let element_start: usize = offset_range[0].as_();
472 let element_end: usize = offset_range[length].as_();
473 total = total
474 .checked_add(element_end - element_start)
475 .ok_or_else(|| vortex_err!("List take output elements length overflow"))?;
476 }
477 Ok(total)
478}
479
480fn piecewise_list_elements_len_constant_validity<S, Offset>(
481 offsets: &[Offset],
482 starts: &[S],
483 length: usize,
484 data_validity: &Mask,
485) -> VortexResult<usize>
486where
487 S: UnsignedPType,
488 Offset: UnsignedPType,
489{
490 if length == 0 {
491 return Ok(0);
492 }
493
494 let mut total = 0usize;
495 for start in starts {
496 let start: usize = start.as_();
497 let additional = valid_piece_elements_len(offsets, data_validity, start, length)?;
498 total = total
499 .checked_add(additional)
500 .ok_or_else(|| vortex_err!("List take output elements length overflow"))?;
501 }
502 Ok(total)
503}
504
505fn piecewise_list_elements_len<S, L, Offset>(
506 offsets: &[Offset],
507 starts: &[S],
508 lengths: &[L],
509) -> VortexResult<usize>
510where
511 S: UnsignedPType,
512 L: UnsignedPType,
513 Offset: UnsignedPType,
514{
515 let mut total = 0usize;
516 for (&start, &length) in starts.iter().zip_eq(lengths) {
517 let start: usize = start.as_();
518 let length: usize = length.as_();
519 let offset_range = &offsets[start..][..=length];
520 let element_start: usize = offset_range[0].as_();
521 let element_end: usize = offset_range[length].as_();
522 total = total
523 .checked_add(element_end - element_start)
524 .ok_or_else(|| vortex_err!("List take output elements length overflow"))?;
525 }
526 Ok(total)
527}
528
529fn piecewise_list_elements_len_validity<S, L, Offset>(
530 offsets: &[Offset],
531 starts: &[S],
532 lengths: &[L],
533 data_validity: &Mask,
534) -> VortexResult<usize>
535where
536 S: UnsignedPType,
537 L: UnsignedPType,
538 Offset: UnsignedPType,
539{
540 let mut total = 0usize;
541 for (&start, &length) in starts.iter().zip_eq(lengths) {
542 let start: usize = start.as_();
543 let length: usize = length.as_();
544 let additional = valid_piece_elements_len(offsets, data_validity, start, length)?;
545 total = total
546 .checked_add(additional)
547 .ok_or_else(|| vortex_err!("List take output elements length overflow"))?;
548 }
549 Ok(total)
550}
551
552fn valid_piece_elements_len<Offset>(
553 offsets: &[Offset],
554 data_validity: &Mask,
555 start: usize,
556 length: usize,
557) -> VortexResult<usize>
558where
559 Offset: UnsignedPType,
560{
561 let offset_range = &offsets[start..][..=length];
562 let mut total = 0usize;
563 for (data_idx, window) in (start..).zip(offset_range.windows(2)) {
564 if !data_validity.value(data_idx) {
565 continue;
566 }
567 let element_start: usize = window[0].as_();
568 let element_end: usize = window[1].as_();
569 total = total
570 .checked_add(element_end - element_start)
571 .ok_or_else(|| vortex_err!("List take output elements length overflow"))?;
572 }
573 Ok(total)
574}
575
576fn gather_piecewise_list_constant_length<S, Offset, OutOffset>(
577 elements: &ArrayRef,
578 offsets: &[Offset],
579 starts: &[S],
580 length: usize,
581 output_len: usize,
582 total_elements: usize,
583) -> VortexResult<GatheredList>
584where
585 S: UnsignedPType,
586 Offset: UnsignedPType,
587 OutOffset: IntegerPType,
588{
589 let offsets_capacity = output_len
590 .checked_add(1)
591 .ok_or_else(|| vortex_err!("List take offsets length overflow"))?;
592 let mut new_offsets = BufferMut::<OutOffset>::with_capacity(offsets_capacity);
593 let mut element_starts = BufferMut::<u64>::with_capacity(starts.len());
594 let mut element_lengths = BufferMut::<u64>::with_capacity(starts.len());
595 let mut output_elements = 0usize;
596
597 new_offsets.push(OutOffset::zero());
598 for start in starts {
599 let start: usize = start.as_();
600 if length == 0 {
601 continue;
602 }
603
604 let offset_range = &offsets[start..][..=length];
605 let element_start: usize = offset_range[0].as_();
606 let element_end: usize = offset_range[length].as_();
607 for &offset in &offset_range[1..] {
608 let offset: usize = offset.as_();
609 let relative = offset - element_start;
610 let output_offset = output_elements + relative;
611 new_offsets.push(new_offset_value::<OutOffset>(output_offset));
612 }
613
614 let element_length = element_end - element_start;
615 element_starts.push(element_start as u64);
616 element_lengths.push(element_length as u64);
617 output_elements += element_length;
618 }
619 debug_assert_eq!(output_elements, total_elements);
620
621 let offsets = PrimitiveArray::new(new_offsets.freeze(), Validity::NonNullable).into_array();
622 let multipliers = ConstantArray::new(1u64, element_starts.len()).into_array();
623 let element_indices = unsafe {
626 PiecewiseSequenceArray::new_unchecked(
627 element_starts.into_array(),
628 element_lengths.into_array(),
629 multipliers,
630 total_elements,
631 )
632 };
633 let elements = elements.take(element_indices.into_array())?;
634
635 Ok(GatheredList { elements, offsets })
636}
637
638fn gather_piecewise_list_constant_length_validity<S, Offset, OutOffset>(
639 elements: &ArrayRef,
640 offsets: &[Offset],
641 starts: &[S],
642 length: usize,
643 output_len: usize,
644 total_elements: usize,
645 data_validity: &Mask,
646) -> VortexResult<GatheredList>
647where
648 S: UnsignedPType,
649 Offset: UnsignedPType,
650 OutOffset: IntegerPType,
651{
652 let offsets_capacity = output_len
653 .checked_add(1)
654 .ok_or_else(|| vortex_err!("List take offsets length overflow"))?;
655 let mut gather = ValidPieceGather {
656 new_offsets: BufferMut::<OutOffset>::with_capacity(offsets_capacity),
657 element_starts: BufferMut::<u64>::with_capacity(output_len),
658 element_lengths: BufferMut::<u64>::with_capacity(output_len),
659 output_elements: 0,
660 };
661
662 gather.new_offsets.push(OutOffset::zero());
663 for start in starts {
664 let start: usize = start.as_();
665 if length == 0 {
666 continue;
667 }
668
669 gather_valid_piece(offsets, data_validity, start, length, &mut gather);
670 }
671 debug_assert_eq!(gather.output_elements, total_elements);
672
673 let offsets =
674 PrimitiveArray::new(gather.new_offsets.freeze(), Validity::NonNullable).into_array();
675 let multipliers = ConstantArray::new(1u64, gather.element_starts.len()).into_array();
676 let element_indices = unsafe {
679 PiecewiseSequenceArray::new_unchecked(
680 gather.element_starts.into_array(),
681 gather.element_lengths.into_array(),
682 multipliers,
683 total_elements,
684 )
685 };
686 let elements = elements.take(element_indices.into_array())?;
687
688 Ok(GatheredList { elements, offsets })
689}
690
691fn gather_piecewise_list<S, L, Offset, OutOffset>(
692 elements: &ArrayRef,
693 offsets: &[Offset],
694 starts: &[S],
695 lengths: &[L],
696 output_len: usize,
697 total_elements: usize,
698) -> VortexResult<GatheredList>
699where
700 S: UnsignedPType,
701 L: UnsignedPType,
702 Offset: UnsignedPType,
703 OutOffset: IntegerPType,
704{
705 let offsets_capacity = output_len
706 .checked_add(1)
707 .ok_or_else(|| vortex_err!("List take offsets length overflow"))?;
708 let mut new_offsets = BufferMut::<OutOffset>::with_capacity(offsets_capacity);
709 let mut element_starts = BufferMut::<u64>::with_capacity(starts.len());
710 let mut element_lengths = BufferMut::<u64>::with_capacity(lengths.len());
711 let mut output_elements = 0usize;
712
713 new_offsets.push(OutOffset::zero());
714 for (&start, &length) in starts.iter().zip_eq(lengths) {
715 let start: usize = start.as_();
716 let length: usize = length.as_();
717 if length == 0 {
718 continue;
719 }
720
721 let offset_range = &offsets[start..][..=length];
722 let element_start: usize = offset_range[0].as_();
723 let element_end: usize = offset_range[length].as_();
724 for &offset in &offset_range[1..] {
725 let offset: usize = offset.as_();
726 let relative = offset - element_start;
727 let output_offset = output_elements + relative;
728 new_offsets.push(new_offset_value::<OutOffset>(output_offset));
729 }
730
731 let element_length = element_end - element_start;
732 element_starts.push(element_start as u64);
733 element_lengths.push(element_length as u64);
734 output_elements += element_length;
735 }
736 debug_assert_eq!(output_elements, total_elements);
737
738 let offsets = PrimitiveArray::new(new_offsets.freeze(), Validity::NonNullable).into_array();
739 let multipliers = ConstantArray::new(1u64, element_starts.len()).into_array();
740 let element_indices = unsafe {
743 PiecewiseSequenceArray::new_unchecked(
744 element_starts.into_array(),
745 element_lengths.into_array(),
746 multipliers,
747 total_elements,
748 )
749 };
750 let elements = elements.take(element_indices.into_array())?;
751
752 Ok(GatheredList { elements, offsets })
753}
754
755fn gather_piecewise_list_validity<S, L, Offset, OutOffset>(
756 elements: &ArrayRef,
757 offsets: &[Offset],
758 starts: &[S],
759 lengths: &[L],
760 output_len: usize,
761 total_elements: usize,
762 data_validity: &Mask,
763) -> VortexResult<GatheredList>
764where
765 S: UnsignedPType,
766 L: UnsignedPType,
767 Offset: UnsignedPType,
768 OutOffset: IntegerPType,
769{
770 let offsets_capacity = output_len
771 .checked_add(1)
772 .ok_or_else(|| vortex_err!("List take offsets length overflow"))?;
773 let mut gather = ValidPieceGather {
774 new_offsets: BufferMut::<OutOffset>::with_capacity(offsets_capacity),
775 element_starts: BufferMut::<u64>::with_capacity(output_len),
776 element_lengths: BufferMut::<u64>::with_capacity(output_len),
777 output_elements: 0,
778 };
779
780 gather.new_offsets.push(OutOffset::zero());
781 for (&start, &length) in starts.iter().zip_eq(lengths) {
782 let start: usize = start.as_();
783 let length: usize = length.as_();
784 if length == 0 {
785 continue;
786 }
787
788 gather_valid_piece(offsets, data_validity, start, length, &mut gather);
789 }
790 debug_assert_eq!(gather.output_elements, total_elements);
791
792 let offsets =
793 PrimitiveArray::new(gather.new_offsets.freeze(), Validity::NonNullable).into_array();
794 let multipliers = ConstantArray::new(1u64, gather.element_starts.len()).into_array();
795 let element_indices = unsafe {
798 PiecewiseSequenceArray::new_unchecked(
799 gather.element_starts.into_array(),
800 gather.element_lengths.into_array(),
801 multipliers,
802 total_elements,
803 )
804 };
805 let elements = elements.take(element_indices.into_array())?;
806
807 Ok(GatheredList { elements, offsets })
808}
809
810fn gather_valid_piece<Offset, OutOffset>(
811 offsets: &[Offset],
812 data_validity: &Mask,
813 start: usize,
814 length: usize,
815 gather: &mut ValidPieceGather<OutOffset>,
816) where
817 Offset: UnsignedPType,
818 OutOffset: IntegerPType,
819{
820 let offset_range = &offsets[start..][..=length];
821 for (data_idx, window) in (start..).zip(offset_range.windows(2)) {
822 if !data_validity.value(data_idx) {
823 gather
824 .new_offsets
825 .push(new_offset_value::<OutOffset>(gather.output_elements));
826 continue;
827 }
828
829 let element_start: usize = window[0].as_();
830 let element_end: usize = window[1].as_();
831 let element_length = element_end - element_start;
832 if element_length != 0 {
833 gather.element_starts.push(element_start as u64);
834 gather.element_lengths.push(element_length as u64);
835 gather.output_elements += element_length;
836 }
837 gather
838 .new_offsets
839 .push(new_offset_value::<OutOffset>(gather.output_elements));
840 }
841}
842
843fn new_offset_value<T: IntegerPType>(value: usize) -> T {
844 T::from_usize(value).vortex_expect("output offset fits selected offset type")
845}
846
847#[cfg(test)]
848mod test {
849 use std::sync::Arc;
850
851 use rstest::rstest;
852 use vortex_buffer::buffer;
853 use vortex_error::VortexResult;
854
855 use crate::IntoArray as _;
856 use crate::VortexSessionExecute;
857 use crate::array_session;
858 use crate::arrays::BoolArray;
859 use crate::arrays::ConstantArray;
860 use crate::arrays::ListArray;
861 use crate::arrays::ListViewArray;
862 use crate::arrays::PiecewiseSequenceArray;
863 use crate::arrays::PrimitiveArray;
864 use crate::arrays::listview::ListViewArrayExt;
865 use crate::assert_arrays_eq;
866 use crate::compute::conformance::take::test_take_conformance;
867 use crate::dtype::DType;
868 use crate::dtype::Nullability;
869 use crate::dtype::PType::I32;
870 use crate::scalar::Scalar;
871 use crate::validity::Validity;
872
873 #[test]
874 fn nullable_take() {
875 let mut ctx = array_session().create_execution_ctx();
876 let list = ListArray::try_new(
877 buffer![0i32, 5, 3, 4].into_array(),
878 buffer![0, 2, 3, 4, 4].into_array(),
879 Validity::Array(BoolArray::from_iter(vec![true, true, false, true]).into_array()),
880 )
881 .unwrap()
882 .into_array();
883
884 let idx =
885 PrimitiveArray::from_option_iter(vec![Some(0), None, Some(1), Some(3)]).into_array();
886
887 let result = list.take(idx).unwrap();
888
889 assert_eq!(
890 result.dtype(),
891 &DType::List(
892 Arc::new(DType::Primitive(I32, Nullability::NonNullable)),
893 Nullability::Nullable
894 )
895 );
896
897 let result = result.execute::<ListViewArray>(&mut ctx).unwrap();
898
899 assert_eq!(result.len(), 4);
900
901 let element_dtype: Arc<DType> = Arc::new(I32.into());
902
903 assert!(
904 result
905 .is_valid(0, &mut array_session().create_execution_ctx())
906 .unwrap()
907 );
908 assert_eq!(
909 result
910 .execute_scalar(0, &mut array_session().create_execution_ctx())
911 .unwrap(),
912 Scalar::list(
913 Arc::clone(&element_dtype),
914 vec![0i32.into(), 5.into()],
915 Nullability::Nullable
916 )
917 );
918
919 assert!(
920 result
921 .is_invalid(1, &mut array_session().create_execution_ctx())
922 .unwrap()
923 );
924
925 assert!(
926 result
927 .is_valid(2, &mut array_session().create_execution_ctx())
928 .unwrap()
929 );
930 assert_eq!(
931 result
932 .execute_scalar(2, &mut array_session().create_execution_ctx())
933 .unwrap(),
934 Scalar::list(
935 Arc::clone(&element_dtype),
936 vec![3i32.into()],
937 Nullability::Nullable
938 )
939 );
940
941 assert!(
942 result
943 .is_valid(3, &mut array_session().create_execution_ctx())
944 .unwrap()
945 );
946 assert_eq!(
947 result
948 .execute_scalar(3, &mut array_session().create_execution_ctx())
949 .unwrap(),
950 Scalar::list(element_dtype, vec![], Nullability::Nullable)
951 );
952 }
953
954 #[test]
955 fn null_index_ignores_out_of_bounds_payload() {
956 let mut ctx = array_session().create_execution_ctx();
957 let list = ListArray::try_new(
958 buffer![1i32, 2, 3, 4].into_array(),
959 buffer![0u32, 2, 4].into_array(),
960 Validity::NonNullable,
961 )
962 .unwrap()
963 .into_array();
964
965 let idx = PrimitiveArray::new(
966 buffer![1u32, 99, 0],
967 Validity::from_iter([true, false, true]),
968 )
969 .into_array();
970 let result = list.take(idx).unwrap();
971
972 let expected = ListArray::new(
973 buffer![3i32, 4, 1, 2].into_array(),
974 buffer![0u32, 2, 2, 4].into_array(),
975 Validity::from_iter([true, false, true]),
976 );
977 assert_arrays_eq!(expected, result, &mut ctx);
978 }
979
980 #[test]
981 fn null_source_row_uses_valid_empty_output_range() {
982 let mut ctx = array_session().create_execution_ctx();
983 let list = ListArray::new(
984 buffer![1i32, 2, 7, 8].into_array(),
985 buffer![0u32, 2, 4].into_array(),
986 Validity::from_iter([true, false]),
987 )
988 .into_array();
989
990 let idx = buffer![0u32, 1].into_array();
991 let result = list.take(idx).unwrap();
992
993 let expected = ListArray::new(
994 buffer![1i32, 2].into_array(),
995 buffer![0u32, 2, 2].into_array(),
996 Validity::from_iter([true, false]),
997 );
998 assert_arrays_eq!(expected, result, &mut ctx);
999 }
1000
1001 #[test]
1002 fn change_validity() {
1003 let list = ListArray::try_new(
1004 buffer![0i32, 5, 3, 4].into_array(),
1005 buffer![0, 2, 3].into_array(),
1006 Validity::NonNullable,
1007 )
1008 .unwrap()
1009 .into_array();
1010
1011 let idx = PrimitiveArray::from_option_iter(vec![Some(0), Some(1), None]).into_array();
1012 let result = list.take(idx).unwrap();
1015 assert_eq!(
1016 result.dtype(),
1017 &DType::List(
1018 Arc::new(DType::Primitive(I32, Nullability::NonNullable)),
1019 Nullability::Nullable
1020 )
1021 );
1022 }
1023
1024 #[test]
1025 fn non_nullable_take() {
1026 let mut ctx = array_session().create_execution_ctx();
1027 let list = ListArray::try_new(
1028 buffer![0i32, 5, 3, 4].into_array(),
1029 buffer![0, 2, 3, 3, 4].into_array(),
1030 Validity::NonNullable,
1031 )
1032 .unwrap()
1033 .into_array();
1034
1035 let idx = buffer![1, 0, 2].into_array();
1036
1037 let result = list.take(idx).unwrap();
1038
1039 assert_eq!(
1040 result.dtype(),
1041 &DType::List(
1042 Arc::new(DType::Primitive(I32, Nullability::NonNullable)),
1043 Nullability::NonNullable
1044 )
1045 );
1046
1047 let result = result.execute::<ListViewArray>(&mut ctx).unwrap();
1048
1049 assert_eq!(result.len(), 3);
1050
1051 let element_dtype: Arc<DType> = Arc::new(I32.into());
1052
1053 assert!(
1054 result
1055 .is_valid(0, &mut array_session().create_execution_ctx())
1056 .unwrap()
1057 );
1058 assert_eq!(
1059 result
1060 .execute_scalar(0, &mut array_session().create_execution_ctx())
1061 .unwrap(),
1062 Scalar::list(
1063 Arc::clone(&element_dtype),
1064 vec![3i32.into()],
1065 Nullability::NonNullable
1066 )
1067 );
1068
1069 assert!(
1070 result
1071 .is_valid(1, &mut array_session().create_execution_ctx())
1072 .unwrap()
1073 );
1074 assert_eq!(
1075 result
1076 .execute_scalar(1, &mut array_session().create_execution_ctx())
1077 .unwrap(),
1078 Scalar::list(
1079 Arc::clone(&element_dtype),
1080 vec![0i32.into(), 5.into()],
1081 Nullability::NonNullable
1082 )
1083 );
1084
1085 assert!(
1086 result
1087 .is_valid(2, &mut array_session().create_execution_ctx())
1088 .unwrap()
1089 );
1090 assert_eq!(
1091 result
1092 .execute_scalar(2, &mut array_session().create_execution_ctx())
1093 .unwrap(),
1094 Scalar::list(element_dtype, vec![], Nullability::NonNullable)
1095 );
1096 }
1097
1098 #[test]
1099 fn piecewise_sequence_take() {
1100 let mut ctx = array_session().create_execution_ctx();
1101 let list = ListArray::try_new(
1102 buffer![0i32, 1, 2, 3, 4, 5, 6].into_array(),
1103 buffer![0u32, 2, 5, 5, 7].into_array(),
1104 Validity::NonNullable,
1105 )
1106 .unwrap()
1107 .into_array();
1108 let idx = PiecewiseSequenceArray::try_new(
1109 buffer![1u64, 0].into_array(),
1110 buffer![2u64, 1].into_array(),
1111 ConstantArray::new(1u64, 2).into_array(),
1112 3,
1113 )
1114 .unwrap()
1115 .into_array();
1116
1117 let result = list
1118 .take(idx)
1119 .unwrap()
1120 .execute::<ListViewArray>(&mut ctx)
1121 .unwrap();
1122
1123 let element_dtype: Arc<DType> = Arc::new(I32.into());
1124 assert_eq!(
1125 result.execute_scalar(0, &mut ctx).unwrap(),
1126 Scalar::list(
1127 Arc::clone(&element_dtype),
1128 vec![2i32.into(), 3.into(), 4.into()],
1129 Nullability::NonNullable
1130 )
1131 );
1132 assert_eq!(
1133 result.execute_scalar(1, &mut ctx).unwrap(),
1134 Scalar::list(Arc::clone(&element_dtype), vec![], Nullability::NonNullable)
1135 );
1136 assert_eq!(
1137 result.execute_scalar(2, &mut ctx).unwrap(),
1138 Scalar::list(
1139 element_dtype,
1140 vec![0i32.into(), 1.into()],
1141 Nullability::NonNullable
1142 )
1143 );
1144 }
1145
1146 #[test]
1147 fn piecewise_sequence_take_nullable_list_constant_lengths() -> VortexResult<()> {
1148 let mut ctx = array_session().create_execution_ctx();
1149 let list = ListArray::try_new(
1150 buffer![0i32, 1, 99, 100, 2, 3, 4, 5].into_array(),
1151 buffer![0u32, 2, 4, 7, 8].into_array(),
1152 Validity::Array(BoolArray::from_iter([true, false, true, true]).into_array()),
1153 )?
1154 .into_array();
1155 let idx = PiecewiseSequenceArray::try_new(
1156 buffer![0u64].into_array(),
1157 ConstantArray::new(4u64, 1).into_array(),
1158 ConstantArray::new(1u64, 1).into_array(),
1159 4,
1160 )?
1161 .into_array();
1162
1163 let result = list.take(idx)?.execute::<ListViewArray>(&mut ctx)?;
1164 assert_eq!(result.offset_at(0), 0);
1165 assert_eq!(result.size_at(0), 2);
1166 assert_eq!(result.offset_at(1), 2);
1167 assert_eq!(result.size_at(1), 0);
1168 assert_eq!(result.offset_at(2), 2);
1169 assert_eq!(result.size_at(2), 3);
1170 assert_eq!(result.offset_at(3), 5);
1171 assert_eq!(result.size_at(3), 1);
1172
1173 let element_dtype: Arc<DType> = Arc::new(I32.into());
1174 assert_eq!(
1175 result.execute_scalar(0, &mut ctx)?,
1176 Scalar::list(
1177 Arc::clone(&element_dtype),
1178 vec![0i32.into(), 1.into()],
1179 Nullability::Nullable
1180 )
1181 );
1182 assert!(result.is_invalid(1, &mut ctx)?);
1183 assert_eq!(
1184 result.execute_scalar(2, &mut ctx)?,
1185 Scalar::list(
1186 Arc::clone(&element_dtype),
1187 vec![2i32.into(), 3.into(), 4.into()],
1188 Nullability::Nullable
1189 )
1190 );
1191 assert_eq!(
1192 result.execute_scalar(3, &mut ctx)?,
1193 Scalar::list(element_dtype, vec![5i32.into()], Nullability::Nullable)
1194 );
1195 Ok(())
1196 }
1197
1198 #[test]
1199 fn piecewise_sequence_take_nullable_list_array_lengths() -> VortexResult<()> {
1200 let mut ctx = array_session().create_execution_ctx();
1201 let list = ListArray::try_new(
1202 buffer![0i32, 1, 99, 100, 2, 3, 4, 5].into_array(),
1203 buffer![0u32, 2, 4, 7, 8].into_array(),
1204 Validity::Array(BoolArray::from_iter([true, false, true, true]).into_array()),
1205 )?
1206 .into_array();
1207 let idx = PiecewiseSequenceArray::try_new(
1208 buffer![1u64, 0].into_array(),
1209 buffer![2u64, 1].into_array(),
1210 ConstantArray::new(1u64, 2).into_array(),
1211 3,
1212 )?
1213 .into_array();
1214
1215 let result = list.take(idx)?.execute::<ListViewArray>(&mut ctx)?;
1216 assert_eq!(result.offset_at(0), 0);
1217 assert_eq!(result.size_at(0), 0);
1218 assert_eq!(result.offset_at(1), 0);
1219 assert_eq!(result.size_at(1), 3);
1220 assert_eq!(result.offset_at(2), 3);
1221 assert_eq!(result.size_at(2), 2);
1222
1223 let element_dtype: Arc<DType> = Arc::new(I32.into());
1224 assert!(result.is_invalid(0, &mut ctx)?);
1225 assert_eq!(
1226 result.execute_scalar(1, &mut ctx)?,
1227 Scalar::list(
1228 Arc::clone(&element_dtype),
1229 vec![2i32.into(), 3.into(), 4.into()],
1230 Nullability::Nullable
1231 )
1232 );
1233 assert_eq!(
1234 result.execute_scalar(2, &mut ctx)?,
1235 Scalar::list(
1236 element_dtype,
1237 vec![0i32.into(), 1.into()],
1238 Nullability::Nullable
1239 )
1240 );
1241 Ok(())
1242 }
1243
1244 #[test]
1245 fn test_take_empty_array() {
1246 let list = ListArray::try_new(
1247 buffer![0i32, 5, 3, 4].into_array(),
1248 buffer![0].into_array(),
1249 Validity::NonNullable,
1250 )
1251 .unwrap()
1252 .into_array();
1253
1254 let idx = PrimitiveArray::empty::<i32>(Nullability::Nullable).into_array();
1255
1256 let result = list.take(idx).unwrap();
1257 assert_eq!(
1258 result.dtype(),
1259 &DType::List(
1260 Arc::new(DType::Primitive(I32, Nullability::NonNullable)),
1261 Nullability::Nullable
1262 )
1263 );
1264 assert_eq!(result.len(), 0,);
1265 }
1266
1267 #[rstest]
1268 #[case(ListArray::try_new(
1269 buffer![0i32, 1, 2, 3, 4, 5].into_array(),
1270 buffer![0, 2, 3, 5, 5, 6].into_array(),
1271 Validity::NonNullable,
1272 ).unwrap())]
1273 #[case(ListArray::try_new(
1274 buffer![10i32, 20, 30, 40, 50].into_array(),
1275 buffer![0, 2, 3, 4, 5].into_array(),
1276 Validity::Array(BoolArray::from_iter(vec![true, false, true, true]).into_array()),
1277 ).unwrap())]
1278 #[case(ListArray::try_new(
1279 buffer![1i32, 2, 3].into_array(),
1280 buffer![0, 0, 2, 2, 3].into_array(), Validity::NonNullable,
1282 ).unwrap())]
1283 #[case(ListArray::try_new(
1284 buffer![42i32, 43].into_array(),
1285 buffer![0, 2].into_array(),
1286 Validity::NonNullable,
1287 ).unwrap())]
1288 #[case({
1289 let elements = buffer![0i32..200].into_array();
1290 let mut offsets = vec![0u64];
1291 for i in 1..=50 {
1292 offsets.push(offsets[i - 1] + (i as u64 % 5)); }
1294 ListArray::try_new(
1295 elements,
1296 PrimitiveArray::from_iter(offsets).into_array(),
1297 Validity::NonNullable,
1298 ).unwrap()
1299 })]
1300 #[case(ListArray::try_new(
1301 PrimitiveArray::from_option_iter([Some(1i32), None, Some(3), Some(4), None]).into_array(),
1302 buffer![0, 2, 3, 5].into_array(),
1303 Validity::NonNullable,
1304 ).unwrap())]
1305 fn test_take_list_conformance(#[case] list: ListArray) {
1306 test_take_conformance(
1307 &list.into_array(),
1308 &mut array_session().create_execution_ctx(),
1309 );
1310 }
1311
1312 #[test]
1313 fn test_u64_offset_accumulation_non_nullable() {
1314 let mut ctx = array_session().create_execution_ctx();
1315 let elements = buffer![0i32; 200].into_array();
1316 let offsets = buffer![0u8, 200].into_array();
1317 let list = ListArray::try_new(elements, offsets, Validity::NonNullable)
1318 .unwrap()
1319 .into_array();
1320
1321 let idx = buffer![0u8, 0].into_array();
1323 let result = list.take(idx).unwrap();
1324
1325 assert_eq!(result.len(), 2);
1326
1327 let result_view = result.execute::<ListViewArray>(&mut ctx).unwrap();
1328 assert_eq!(result_view.len(), 2);
1329 assert!(
1330 result_view
1331 .is_valid(0, &mut array_session().create_execution_ctx())
1332 .unwrap()
1333 );
1334 assert!(
1335 result_view
1336 .is_valid(1, &mut array_session().create_execution_ctx())
1337 .unwrap()
1338 );
1339 }
1340
1341 #[test]
1342 fn test_u64_offset_accumulation_nullable() {
1343 let mut ctx = array_session().create_execution_ctx();
1344 let elements = buffer![0i32; 150].into_array();
1345 let offsets = buffer![0u8, 150, 150].into_array();
1346 let validity = BoolArray::from_iter(vec![true, false]).into_array();
1347 let list = ListArray::try_new(elements, offsets, Validity::Array(validity))
1348 .unwrap()
1349 .into_array();
1350
1351 let idx = PrimitiveArray::from_option_iter(vec![Some(0u8), None, Some(0u8)]).into_array();
1353 let result = list.take(idx).unwrap();
1354
1355 assert_eq!(result.len(), 3);
1356
1357 let result_view = result.execute::<ListViewArray>(&mut ctx).unwrap();
1358 assert_eq!(result_view.len(), 3);
1359 assert!(
1360 result_view
1361 .is_valid(0, &mut array_session().create_execution_ctx())
1362 .unwrap()
1363 );
1364 assert!(
1365 result_view
1366 .is_invalid(1, &mut array_session().create_execution_ctx())
1367 .unwrap()
1368 );
1369 assert!(
1370 result_view
1371 .is_valid(2, &mut array_session().create_execution_ctx())
1372 .unwrap()
1373 );
1374 }
1375
1376 #[test]
1381 fn test_take_validity_length_mismatch_regression() {
1382 let list = ListArray::try_new(
1384 buffer![1i32, 2, 3, 4].into_array(),
1385 buffer![0, 2, 4].into_array(),
1386 Validity::Array(BoolArray::from_iter(vec![true, true]).into_array()),
1387 )
1388 .unwrap()
1389 .into_array();
1390
1391 let idx = buffer![0u32, 1, 0, 1].into_array();
1393
1394 let result = list.take(idx).unwrap();
1396 assert_eq!(result.len(), 4);
1397 }
1398}