1use itertools::Itertools;
5use num_traits::AsPrimitive;
6use vortex_buffer::Buffer;
7use vortex_buffer::BufferAllocatorRef;
8use vortex_buffer::BufferMut;
9use vortex_error::VortexResult;
10use vortex_error::vortex_bail;
11use vortex_error::vortex_ensure_eq;
12use vortex_error::vortex_err;
13use vortex_mask::Mask;
14
15use crate::ArrayRef;
16use crate::Canonical;
17use crate::Columnar;
18use crate::IntoArray;
19use crate::array::ArrayView;
20use crate::arrays::Chunked;
21use crate::arrays::ChunkedArray;
22use crate::arrays::ConstantArray;
23use crate::arrays::FixedSizeListArray;
24use crate::arrays::PiecewiseSequence;
25use crate::arrays::PiecewiseSequenceArray;
26use crate::arrays::PrimitiveArray;
27use crate::arrays::chunked::ChunkedArrayExt;
28use crate::arrays::dict::TakeExecute;
29use crate::arrays::piecewise_sequence::constant_unsigned_usize;
30use crate::arrays::piecewise_sequence::maybe_contiguous_slices;
31use crate::arrays::primitive::PrimitiveArrayExt;
32use crate::builders::ArrayBuilder;
33use crate::builders::builder_with_capacity_in;
34use crate::builtins::ArrayBuiltins;
35use crate::dtype::DType;
36use crate::dtype::PType;
37use crate::executor::ExecutionCtx;
38use crate::match_each_unsigned_integer_ptype;
39use crate::validity::Validity;
40
41enum ChunkFlattener {
45 Builder(Box<dyn ArrayBuilder>),
46 Chunks(Vec<ArrayRef>),
47}
48
49impl ChunkFlattener {
50 fn new(dtype: &DType, capacity: usize, allocator: &BufferAllocatorRef) -> Self {
51 if dtype.is_nested() {
52 Self::Chunks(Vec::new())
53 } else {
54 Self::Builder(builder_with_capacity_in(dtype, capacity, allocator))
55 }
56 }
57
58 fn push(&mut self, chunk: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<()> {
59 match self {
60 Self::Builder(builder) => chunk.append_to_builder(builder.as_mut(), ctx),
61 Self::Chunks(chunks) => {
62 chunks.push(chunk);
63 Ok(())
64 }
65 }
66 }
67
68 fn finish(self, dtype: &DType, ctx: &mut ExecutionCtx) -> VortexResult<ArrayRef> {
69 match self {
70 Self::Builder(mut builder) => Ok(builder.finish()),
71 Self::Chunks(chunks) => unsafe { ChunkedArray::new_unchecked(chunks, dtype.clone()) }
74 .into_array()
75 .execute::<Canonical>(ctx)
76 .map(IntoArray::into_array),
77 }
78 }
79}
80
81fn take_chunked_via_sort(
82 array: ArrayView<'_, Chunked>,
83 indices: &PrimitiveArray,
84 indices_mask: Mask,
85 ctx: &mut ExecutionCtx,
86) -> VortexResult<ArrayRef> {
87 let indices_values = indices.as_slice::<u64>();
88 let n = indices_values.len();
89 let mut pairs: Vec<(u64, usize)> = indices_values
90 .iter()
91 .enumerate()
92 .filter(|&(position, _)| indices_mask.value(position))
93 .map(|(position, &index)| (index, position))
94 .collect();
95 pairs.sort_unstable();
96
97 if let Some(&(index, _)) = pairs.last() {
98 let index = usize::try_from(index)?;
99 if index >= array.len() {
100 vortex_bail!(OutOfBounds: index, 0, array.len());
101 }
102 }
103
104 let chunk_offsets = array.chunk_offset_values();
105 let nchunks = array.nchunks();
106 let mut flattener = ChunkFlattener::new(array.dtype(), pairs.len(), ctx.allocator());
107 let mut final_take = BufferMut::<u64>::zeroed(n);
108 let mut cursor = 0usize;
109 let mut dedup_idx = 0u64;
110
111 for chunk_idx in 0..nchunks {
112 let chunk_start = chunk_offsets[chunk_idx];
113 let chunk_end = chunk_offsets[chunk_idx + 1];
114 let chunk_len = chunk_end - chunk_start;
115 let chunk_end_u64 = u64::try_from(chunk_end)?;
116 let range_end = cursor + pairs[cursor..].partition_point(|&(v, _)| v < chunk_end_u64);
117 let chunk_pairs = &pairs[cursor..range_end];
118
119 if !chunk_pairs.is_empty() {
120 let mut local_indices = Vec::new();
121 for (i, &(value, original_position)) in chunk_pairs.iter().enumerate() {
122 if cursor + i > 0 && value != pairs[cursor + i - 1].0 {
123 dedup_idx += 1;
124 }
125 let local_index = usize::try_from(value)? - chunk_start;
126 if local_indices.last() != Some(&local_index) {
127 local_indices.push(local_index);
128 }
129 final_take[original_position] = dedup_idx;
130 }
131
132 flattener.push(
133 array
134 .chunk(chunk_idx)
135 .filter(Mask::from_indices(chunk_len, local_indices))?,
136 ctx,
137 )?;
138 }
139
140 cursor = range_end;
141 }
142
143 let flat = flattener.finish(array.dtype(), ctx)?;
144 let take_validity = Validity::from_mask(indices_mask, indices.dtype().nullability());
145 flat.take(PrimitiveArray::new(final_take.freeze(), take_validity).into_array())
146}
147
148fn valid_indices_are_monotonic(indices: &[u64], indices_mask: &Mask) -> bool {
149 let mut previous = None;
150 for (position, &index) in indices.iter().enumerate() {
151 if !indices_mask.value(position) {
152 continue;
153 }
154 if previous.is_some_and(|previous| index < previous) {
155 return false;
156 }
157 previous = Some(index);
158 }
159 true
160}
161
162fn take_chunked(
164 array: ArrayView<'_, Chunked>,
165 indices: &ArrayRef,
166 ctx: &mut ExecutionCtx,
167) -> VortexResult<ArrayRef> {
168 let indices = indices
169 .cast(DType::Primitive(PType::U64, indices.dtype().nullability()))?
170 .execute::<PrimitiveArray>(ctx)?;
171
172 let indices_mask = indices
173 .as_ref()
174 .validity()?
175 .execute_mask(indices.as_ref().len(), ctx)?;
176 let indices_values = indices.as_slice::<u64>();
177 let n = indices_values.len();
178 let chunk_offsets = array.chunk_offset_values();
179 let nchunks = array.nchunks();
180
181 if !indices.as_ref().dtype().is_nullable() && indices_values.is_sorted_by(|a, b| a < b) {
184 return take_chunked_sorted(array, indices_values);
185 }
186
187 if matches!(array.dtype(), DType::FixedSizeList(..))
191 && n <= 64
192 && nchunks <= 16
193 && !valid_indices_are_monotonic(indices_values, &indices_mask)
194 {
195 return take_chunked_via_sort(array, &indices, indices_mask, ctx);
196 }
197
198 let mut buckets = vec![Vec::<(u64, usize)>::new(); nchunks];
201 let mut monotonic = true;
202 let mut last_index = None;
203 let mut sorted_chunk_idx = 0;
204
205 for (original_position, &index) in indices_values.iter().enumerate() {
206 if !indices_mask.value(original_position) {
207 continue;
208 }
209
210 let index = usize::try_from(index)?;
211 if index >= array.len() {
212 vortex_bail!(OutOfBounds: index, 0, array.len());
213 }
214
215 let still_sorted = last_index.is_none_or(|last_index| index >= last_index);
216 let chunk_idx = if monotonic && still_sorted {
217 while chunk_offsets[sorted_chunk_idx + 1] <= index {
218 sorted_chunk_idx += 1;
219 }
220 sorted_chunk_idx
221 } else {
222 monotonic = false;
223 chunk_offsets.partition_point(|&offset| offset <= index) - 1
224 };
225 last_index = Some(index);
226
227 let local_index = u64::try_from(index - chunk_offsets[chunk_idx])?;
228 buckets[chunk_idx].push((local_index, original_position));
229 }
230
231 let mut flattener =
232 ChunkFlattener::new(array.dtype(), indices_mask.true_count(), ctx.allocator());
233 let mut final_take =
234 (!monotonic || indices.dtype().is_nullable()).then(|| BufferMut::<u64>::zeroed(n));
235 let mut grouped_position = 0u64;
236
237 for (chunk_idx, bucket) in buckets.into_iter().enumerate() {
238 if bucket.is_empty() {
239 continue;
240 }
241
242 let mut local_indices = BufferMut::<u64>::with_capacity(bucket.len());
243 for (local_index, original_position) in bucket {
244 local_indices.push(local_index);
245 if let Some(final_take) = &mut final_take {
246 final_take[original_position] = grouped_position;
247 }
248 grouped_position += 1;
249 }
250
251 let local_indices =
252 PrimitiveArray::new(local_indices.freeze(), Validity::NonNullable).into_array();
253 flattener.push(array.chunk(chunk_idx).take(local_indices)?, ctx)?;
254 }
255
256 let flat = flattener.finish(array.dtype(), ctx)?;
258
259 let Some(final_take) = final_take else {
262 return Ok(flat);
263 };
264
265 let take_validity = Validity::from_mask(indices_mask, indices.dtype().nullability());
268 flat.take(PrimitiveArray::new(final_take.freeze(), take_validity).into_array())
269}
270
271fn take_chunked_sorted(
275 array: ArrayView<'_, Chunked>,
276 indices_values: &[u64],
277) -> VortexResult<ArrayRef> {
278 let chunk_offsets = array.chunk_offset_values();
279 let mut chunks = Vec::new();
280 let mut cursor = 0usize;
281
282 let first_chunk = match indices_values.first() {
285 Some(&first) => {
286 let first = usize::try_from(first)?;
287 chunk_offsets
288 .partition_point(|&offset| offset <= first)
289 .saturating_sub(1)
290 }
291 None => 0,
292 };
293
294 for chunk_idx in first_chunk..array.nchunks() {
295 if cursor == indices_values.len() {
296 break;
297 }
298 let chunk_start = chunk_offsets[chunk_idx];
299 let chunk_end = chunk_offsets[chunk_idx + 1];
300 let chunk_end_u64 = u64::try_from(chunk_end)?;
301
302 let range_end = cursor + indices_values[cursor..].partition_point(|&v| v < chunk_end_u64);
303 if range_end > cursor {
304 let chunk_start_u64 = u64::try_from(chunk_start)?;
305 let mut local_indices = BufferMut::<u64>::with_capacity(range_end - cursor);
306 for &val in &indices_values[cursor..range_end] {
307 local_indices.push(val - chunk_start_u64);
308 }
309 let local_indices =
310 PrimitiveArray::new(local_indices.freeze(), Validity::NonNullable).into_array();
311 chunks.push(array.chunk(chunk_idx).take(local_indices)?);
312 }
313 cursor = range_end;
314 }
315 if cursor != indices_values.len() {
316 vortex_bail!(
317 OutOfBounds: usize::try_from(indices_values[cursor])?, 0, array.as_ref().len()
318 );
319 }
320
321 if chunks.len() == 1 {
322 return Ok(chunks.swap_remove(0));
323 }
324 Ok(unsafe { ChunkedArray::new_unchecked(chunks, array.dtype().clone()) }.into_array())
327}
328
329impl TakeExecute for Chunked {
330 fn take(
331 array: ArrayView<'_, Chunked>,
332 indices: &ArrayRef,
333 ctx: &mut ExecutionCtx,
334 ) -> VortexResult<Option<ArrayRef>> {
335 if array.nchunks() == 1 {
336 return array.chunk(0).take(indices.clone()).map(Some);
337 }
338
339 if let Some(taken) = take_chunked_fsl(array, indices, ctx)? {
340 return Ok(Some(taken));
341 }
342
343 if let Some(piecewise_indices) = indices.as_opt::<PiecewiseSequence>()
344 && let Some(taken) = take_piecewise_chunked(array, piecewise_indices, ctx)?
345 {
346 return Ok(Some(taken));
347 }
348
349 take_chunked(array, indices, ctx).map(Some)
350 }
351}
352
353fn take_chunked_fsl(
358 array: ArrayView<'_, Chunked>,
359 indices: &ArrayRef,
360 ctx: &mut ExecutionCtx,
361) -> VortexResult<Option<ArrayRef>> {
362 if !matches!(array.dtype(), DType::FixedSizeList(..)) {
363 return Ok(None);
364 }
365
366 let fsl = array.as_ref().clone().execute::<FixedSizeListArray>(ctx)?;
367 fsl.into_array().take(indices.clone()).map(Some)
368}
369
370#[derive(Default)]
372struct ChunkGather {
373 starts: Vec<u64>,
374 lengths: Vec<u64>,
375 total: usize,
376}
377
378fn take_piecewise_chunked(
386 array: ArrayView<'_, Chunked>,
387 indices: ArrayView<'_, PiecewiseSequence>,
388 ctx: &mut ExecutionCtx,
389) -> VortexResult<Option<ArrayRef>> {
390 let Some((starts, lengths)) = maybe_contiguous_slices(indices, ctx)? else {
391 return Ok(None);
392 };
393
394 let output_len = indices.as_ref().len();
395 let starts: Vec<usize> = match_each_unsigned_integer_ptype!(starts.ptype(), |S| {
396 starts
397 .as_slice::<S>()
398 .iter()
399 .map(|&start| start.as_())
400 .collect()
401 });
402 let lengths: Vec<usize> = match lengths {
403 Columnar::Constant(lengths) => vec![constant_unsigned_usize(&lengths); starts.len()],
404 Columnar::Canonical(lengths) => {
405 let lengths = lengths.into_primitive();
406 match_each_unsigned_integer_ptype!(lengths.ptype(), |L| {
407 lengths
408 .as_slice::<L>()
409 .iter()
410 .map(|&length| length.as_())
411 .collect()
412 })
413 }
414 };
415
416 let array_len = array.as_ref().len();
417 let chunk_offsets = array.chunk_offset_values();
418 let nchunks = array.nchunks();
419
420 let mut plans: Vec<ChunkGather> = Vec::new();
421 plans.resize_with(nchunks, ChunkGather::default);
422 let mut sub_pieces: Vec<(usize, usize, usize)> = Vec::with_capacity(starts.len());
425 let mut monotonic = true;
426 let mut prev_chunk = 0usize;
427 let mut total_len = 0usize;
428
429 for (&start, &length) in starts.iter().zip_eq(&lengths) {
430 if length == 0 {
431 continue;
432 }
433 let end = start
434 .checked_add(length)
435 .ok_or_else(|| vortex_err!("PiecewiseSequenceArray range overflows usize"))?;
436 if end > array_len {
437 vortex_bail!(OutOfBounds: end - 1, 0, array_len);
438 }
439 total_len = total_len
440 .checked_add(length)
441 .ok_or_else(|| vortex_err!("PiecewiseSequenceArray output length overflows usize"))?;
442
443 let mut chunk_idx = chunk_offsets.partition_point(|&offset| offset <= start) - 1;
445 let mut cursor = start;
446 let mut remaining = length;
447 while remaining > 0 {
448 while chunk_offsets[chunk_idx + 1] <= cursor {
449 chunk_idx += 1;
450 }
451 let run = remaining.min(chunk_offsets[chunk_idx + 1] - cursor);
452 monotonic &= chunk_idx >= prev_chunk;
453 prev_chunk = chunk_idx;
454
455 let plan = &mut plans[chunk_idx];
456 match sub_pieces.last_mut() {
459 Some((last_chunk, _, last_run)) if *last_chunk == chunk_idx => *last_run += run,
460 _ => sub_pieces.push((chunk_idx, plan.total, run)),
461 }
462 let local_start = (cursor - chunk_offsets[chunk_idx]) as u64;
465 match (plan.starts.last(), plan.lengths.last_mut()) {
466 (Some(&prev_start), Some(prev_len)) if prev_start + *prev_len == local_start => {
467 *prev_len += run as u64;
468 }
469 _ => {
470 plan.starts.push(local_start);
471 plan.lengths.push(run as u64);
472 }
473 }
474 plan.total += run;
475
476 cursor += run;
477 remaining -= run;
478 }
479 }
480
481 vortex_ensure_eq!(
482 total_len,
483 output_len,
484 "PiecewiseSequenceArray expanded length does not match declared length",
485 );
486
487 if monotonic {
489 let mut gathered = Vec::new();
490 for (chunk_idx, plan) in plans.into_iter().enumerate() {
491 if plan.starts.is_empty() {
492 continue;
493 }
494 gathered.push(gather_chunk(array.chunk(chunk_idx), plan)?);
495 }
496 let result = if gathered.len() == 1 {
497 gathered.swap_remove(0)
498 } else {
499 unsafe { ChunkedArray::new_unchecked(gathered, array.dtype().clone()) }.into_array()
502 };
503 return Ok(Some(result));
504 }
505
506 let mut bases = vec![0usize; nchunks];
509 let mut running = 0usize;
510 let mut flattener = ChunkFlattener::new(array.dtype(), output_len, ctx.allocator());
511 for (chunk_idx, plan) in plans.into_iter().enumerate() {
512 if plan.starts.is_empty() {
513 continue;
514 }
515 bases[chunk_idx] = running;
516 running += plan.total;
517 flattener.push(gather_chunk(array.chunk(chunk_idx), plan)?, ctx)?;
518 }
519 let flat = flattener.finish(array.dtype(), ctx)?;
520
521 let mut reorder_starts = Vec::with_capacity(sub_pieces.len());
522 let mut reorder_lengths = Vec::with_capacity(sub_pieces.len());
523 for &(chunk_idx, offset, run) in &sub_pieces {
524 reorder_starts.push((bases[chunk_idx] + offset) as u64);
525 reorder_lengths.push(run as u64);
526 }
527 flat.take(contiguous_runs(reorder_starts, reorder_lengths, output_len))
528 .map(Some)
529}
530
531fn gather_chunk(chunk: &ArrayRef, plan: ChunkGather) -> VortexResult<ArrayRef> {
534 if let [start] = plan.starts.as_slice() {
535 let start = usize::try_from(*start)?;
536 return chunk.slice(start..start + plan.total);
537 }
538 chunk.take(contiguous_runs(plan.starts, plan.lengths, plan.total))
539}
540
541fn contiguous_runs(starts: Vec<u64>, lengths: Vec<u64>, total: usize) -> ArrayRef {
544 let count = starts.len();
545 debug_assert_eq!(count, lengths.len());
546 let starts = PrimitiveArray::new(Buffer::from(starts), Validity::NonNullable).into_array();
547 let lengths = match lengths.first() {
548 Some(&first) if lengths.iter().all(|&length| length == first) => {
549 ConstantArray::new(first, count).into_array()
550 }
551 _ => PrimitiveArray::new(Buffer::from(lengths), Validity::NonNullable).into_array(),
552 };
553 let multipliers = ConstantArray::new(1u64, count).into_array();
554 unsafe { PiecewiseSequenceArray::new_unchecked(starts, lengths, multipliers, total) }
557 .into_array()
558}
559
560#[cfg(test)]
561mod tests {
562 use vortex_buffer::Buffer;
563 use vortex_buffer::bitbuffer;
564 use vortex_buffer::buffer;
565 use vortex_error::VortexResult;
566
567 use crate::ArrayRef;
568 use crate::Canonical;
569 use crate::IntoArray;
570 use crate::VortexSessionExecute;
571 use crate::array_session;
572 use crate::arrays::BoolArray;
573 use crate::arrays::ChunkedArray;
574 use crate::arrays::ConstantArray;
575 use crate::arrays::FixedSizeListArray;
576 use crate::arrays::PiecewiseSequenceArray;
577 use crate::arrays::PrimitiveArray;
578 use crate::arrays::StructArray;
579 use crate::arrays::chunked::ChunkedArrayExt;
580 use crate::assert_arrays_eq;
581 use crate::compute::conformance::take::test_take_conformance;
582 use crate::dtype::DType;
583 use crate::dtype::FieldNames;
584 use crate::dtype::Nullability;
585 use crate::dtype::PType;
586 use crate::scalar::Scalar;
587 use crate::validity::Validity;
588
589 fn chunked_i32() -> VortexResult<ChunkedArray> {
590 ChunkedArray::try_new(
591 vec![
592 buffer![0i32, 1, 2, 3, 4].into_array(),
593 buffer![5i32, 6, 7, 8, 9].into_array(),
594 buffer![10i32, 11, 12, 13, 14].into_array(),
595 ],
596 DType::Primitive(PType::I32, Nullability::NonNullable),
597 )
598 }
599
600 fn contiguous_pieces(starts: &[u64], lengths: &[u64]) -> VortexResult<ArrayRef> {
601 let len = usize::try_from(lengths.iter().sum::<u64>())?;
602 Ok(PiecewiseSequenceArray::try_new(
603 starts.iter().copied().collect::<Buffer<u64>>().into_array(),
604 lengths
605 .iter()
606 .copied()
607 .collect::<Buffer<u64>>()
608 .into_array(),
609 ConstantArray::new(1u64, starts.len()).into_array(),
610 len,
611 )?
612 .into_array())
613 }
614
615 #[test]
616 fn test_take_piecewise_monotonic_spanning_chunks() -> VortexResult<()> {
617 let mut ctx = array_session().create_execution_ctx();
618 let arr = chunked_i32()?;
619
620 let indices = contiguous_pieces(&[1, 4, 9], &[3, 4, 6])?;
622 let result = arr.take(indices)?;
623
624 assert_arrays_eq!(
625 result,
626 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14]),
627 &mut ctx
628 );
629 Ok(())
630 }
631
632 #[test]
633 fn test_take_piecewise_interleaved() -> VortexResult<()> {
634 let mut ctx = array_session().create_execution_ctx();
635 let arr = chunked_i32()?;
636
637 let indices = contiguous_pieces(&[12, 2, 7, 0], &[3, 2, 3, 1])?;
639 let result = arr.take(indices)?;
640
641 assert_arrays_eq!(
642 result,
643 PrimitiveArray::from_iter([12i32, 13, 14, 2, 3, 7, 8, 9, 0]),
644 &mut ctx
645 );
646 Ok(())
647 }
648
649 #[test]
650 fn test_take_piecewise_whole_array() -> VortexResult<()> {
651 let mut ctx = array_session().create_execution_ctx();
652 let arr = chunked_i32()?;
653
654 let indices = contiguous_pieces(&[0], &[15])?;
655 let result = arr.take(indices)?;
656
657 assert_arrays_eq!(result, PrimitiveArray::from_iter(0i32..15), &mut ctx);
658 Ok(())
659 }
660
661 #[test]
662 fn test_take_piecewise_across_empty_chunk() -> VortexResult<()> {
663 let mut ctx = array_session().create_execution_ctx();
664 let arr = ChunkedArray::try_new(
665 vec![
666 buffer![0i32, 1, 2, 3, 4].into_array(),
667 PrimitiveArray::empty::<i32>(Nullability::NonNullable).into_array(),
668 buffer![5i32, 6, 7, 8, 9].into_array(),
669 ],
670 DType::Primitive(PType::I32, Nullability::NonNullable),
671 )?;
672
673 let indices = contiguous_pieces(&[3], &[4])?;
674 let result = arr.take(indices)?;
675
676 assert_arrays_eq!(result, PrimitiveArray::from_iter([3i32, 4, 5, 6]), &mut ctx);
677 Ok(())
678 }
679
680 #[test]
681 fn test_take_piecewise_adjacent_pieces_merge() -> VortexResult<()> {
682 let mut ctx = array_session().create_execution_ctx();
683 let arr = chunked_i32()?;
684
685 let indices = contiguous_pieces(&[0, 2, 7], &[2, 2, 2])?;
688 let result = arr.take(indices)?;
689
690 assert_arrays_eq!(
691 result,
692 PrimitiveArray::from_iter([0i32, 1, 2, 3, 7, 8]),
693 &mut ctx
694 );
695 Ok(())
696 }
697
698 #[test]
699 fn test_take_piecewise_same_chunk_out_of_order() -> VortexResult<()> {
700 let mut ctx = array_session().create_execution_ctx();
701 let arr = chunked_i32()?;
702
703 let indices = contiguous_pieces(&[2, 0], &[2, 2])?;
705 let result = arr.take(indices)?;
706
707 assert_arrays_eq!(result, PrimitiveArray::from_iter([2i32, 3, 0, 1]), &mut ctx);
708 Ok(())
709 }
710
711 #[test]
712 fn test_take_piecewise_zero_length_pieces() -> VortexResult<()> {
713 let mut ctx = array_session().create_execution_ctx();
714 let arr = chunked_i32()?;
715
716 let indices = contiguous_pieces(&[5, 0, 2], &[0, 4, 0])?;
717 let result = arr.take(indices)?;
718
719 assert_arrays_eq!(result, PrimitiveArray::from_iter([0i32, 1, 2, 3]), &mut ctx);
720 Ok(())
721 }
722
723 #[test]
724 fn test_take_piecewise_out_of_bounds() -> VortexResult<()> {
725 let mut ctx = array_session().create_execution_ctx();
726 let arr = chunked_i32()?;
727
728 let indices = contiguous_pieces(&[12], &[5])?;
729 let result = arr
730 .take(indices)
731 .and_then(|taken| taken.execute::<Canonical>(&mut ctx));
732
733 assert!(result.is_err());
734 Ok(())
735 }
736
737 #[test]
738 fn test_take_piecewise_non_unit_multiplier() -> VortexResult<()> {
739 let mut ctx = array_session().create_execution_ctx();
740 let arr = chunked_i32()?;
741
742 let indices = PiecewiseSequenceArray::try_new(
744 buffer![0u64, 1].into_array(),
745 buffer![5u64, 3].into_array(),
746 buffer![2u64, 4].into_array(),
747 8,
748 )?
749 .into_array();
750 let result = arr.take(indices)?;
751
752 assert_arrays_eq!(
753 result,
754 PrimitiveArray::from_iter([0i32, 2, 4, 6, 8, 1, 5, 9]),
755 &mut ctx
756 );
757 Ok(())
758 }
759
760 #[test]
761 fn test_take_piecewise_nullable_values() -> VortexResult<()> {
762 let mut ctx = array_session().create_execution_ctx();
763 let arr = ChunkedArray::try_new(
764 vec![
765 PrimitiveArray::from_option_iter([Some(0i32), None, Some(2)]).into_array(),
766 PrimitiveArray::from_option_iter([None, Some(4i32), Some(5)]).into_array(),
767 ],
768 DType::Primitive(PType::I32, Nullability::Nullable),
769 )?;
770
771 let indices = contiguous_pieces(&[4, 1], &[2, 3])?;
772 let result = arr.take(indices)?;
773
774 assert_arrays_eq!(
775 result,
776 PrimitiveArray::from_option_iter([Some(4i32), Some(5), None, Some(2), None]),
777 &mut ctx
778 );
779 Ok(())
780 }
781
782 #[test]
783 fn test_take_fsl_over_chunked_elements() -> VortexResult<()> {
784 let mut ctx = array_session().create_execution_ctx();
785 let elements = ChunkedArray::try_new(
787 vec![
788 PrimitiveArray::from_iter(0i32..8).into_array(),
789 PrimitiveArray::from_iter(8i32..13).into_array(),
790 PrimitiveArray::from_iter(13i32..18).into_array(),
791 ],
792 DType::Primitive(PType::I32, Nullability::NonNullable),
793 )?
794 .into_array();
795 let fsl = FixedSizeListArray::try_new(elements, 3, Validity::NonNullable, 6)?;
796
797 let indices = buffer![4u64, 0, 2, 5, 1, 4].into_array();
798 let result = fsl.take(indices.clone())?;
799 let expected = FixedSizeListArray::try_new(
800 PrimitiveArray::from_iter(0i32..18).into_array(),
801 3,
802 Validity::NonNullable,
803 6,
804 )?
805 .take(indices)?;
806
807 assert_arrays_eq!(result, expected, &mut ctx);
808 Ok(())
809 }
810
811 #[test]
812 fn test_take_fsl_over_chunked_elements_conformance() -> VortexResult<()> {
813 let elements = ChunkedArray::try_new(
814 vec![
815 PrimitiveArray::from_iter(0i32..8).into_array(),
816 PrimitiveArray::from_iter(8i32..13).into_array(),
817 PrimitiveArray::from_iter(13i32..18).into_array(),
818 ],
819 DType::Primitive(PType::I32, Nullability::NonNullable),
820 )?
821 .into_array();
822 let fsl = FixedSizeListArray::try_new(elements, 3, Validity::NonNullable, 6)?;
823 test_take_conformance(
824 &fsl.into_array(),
825 &mut array_session().create_execution_ctx(),
826 );
827 Ok(())
828 }
829
830 #[test]
831 fn test_take_chunked_fsl() -> VortexResult<()> {
832 let mut ctx = array_session().create_execution_ctx();
833 let c0 = FixedSizeListArray::try_new(
834 PrimitiveArray::from_iter(0i32..6).into_array(),
835 2,
836 Validity::NonNullable,
837 3,
838 )?;
839 let c1 = FixedSizeListArray::try_new(
840 PrimitiveArray::from_iter(6i32..10).into_array(),
841 2,
842 Validity::NonNullable,
843 2,
844 )?;
845 let dtype = c0.dtype().clone();
846 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
847
848 let indices = buffer![4u64, 0, 3, 3, 1].into_array();
849 let result = arr.take(indices.clone())?;
850 let expected = FixedSizeListArray::try_new(
851 PrimitiveArray::from_iter(0i32..10).into_array(),
852 2,
853 Validity::NonNullable,
854 5,
855 )?
856 .take(indices)?;
857
858 assert_arrays_eq!(result, expected, &mut ctx);
859 Ok(())
860 }
861
862 #[test]
863 fn test_take_chunked_fsl_nullable() -> VortexResult<()> {
864 let mut ctx = array_session().create_execution_ctx();
865 let c0 = FixedSizeListArray::try_new(
866 PrimitiveArray::from_iter(0i32..6).into_array(),
867 2,
868 Validity::Array(bitbuffer![1 0 1].into_array()),
869 3,
870 )?;
871 let c1 = FixedSizeListArray::try_new(
872 PrimitiveArray::from_iter(6i32..10).into_array(),
873 2,
874 Validity::AllValid,
875 2,
876 )?;
877 let dtype = c0.dtype().clone();
878 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
879
880 let indices =
881 PrimitiveArray::from_option_iter([Some(4u64), None, Some(0), Some(1)]).into_array();
882 let result = arr.take(indices.clone())?;
883 let expected = FixedSizeListArray::try_new(
884 PrimitiveArray::from_iter(0i32..10).into_array(),
885 2,
886 Validity::Array(bitbuffer![1 0 1 1 1].into_array()),
887 5,
888 )?
889 .take(indices)?;
890
891 assert_arrays_eq!(result, expected, &mut ctx);
892 Ok(())
893 }
894
895 #[test]
896 fn test_take_chunked_fsl_non_fsl_chunk() -> VortexResult<()> {
897 let mut ctx = array_session().create_execution_ctx();
898 let c0 = FixedSizeListArray::try_new(
899 PrimitiveArray::from_iter(0i32..6).into_array(),
900 2,
901 Validity::NonNullable,
902 3,
903 )?;
904 let c1 = FixedSizeListArray::try_new(
905 PrimitiveArray::from_iter(6i32..10).into_array(),
906 2,
907 Validity::NonNullable,
908 2,
909 )?;
910 let dtype = c0.dtype().clone();
911 let nested = ChunkedArray::try_new(vec![c1.into_array()], dtype.clone())?;
914 let arr = ChunkedArray::try_new(vec![c0.into_array(), nested.into_array()], dtype)?;
915
916 let indices = buffer![4u64, 0, 3, 1].into_array();
917 let result = arr.take(indices.clone())?;
918 let expected = FixedSizeListArray::try_new(
919 PrimitiveArray::from_iter(0i32..10).into_array(),
920 2,
921 Validity::NonNullable,
922 5,
923 )?
924 .take(indices)?;
925
926 assert_arrays_eq!(result, expected, &mut ctx);
927 Ok(())
928 }
929
930 #[test]
931 fn test_take_chunked_fsl_constant_chunk() -> VortexResult<()> {
932 let mut ctx = array_session().create_execution_ctx();
933 let c0 = FixedSizeListArray::try_new(
934 PrimitiveArray::from_iter(0i32..6).into_array(),
935 2,
936 Validity::AllValid,
937 3,
938 )?;
939 let dtype = c0.dtype().clone();
940 let c1 = ConstantArray::new(Scalar::null(dtype.clone()), 2).into_array();
942 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1], dtype)?;
943
944 let indices = buffer![4u64, 0, 3, 1].into_array();
945 let result = arr.take(indices.clone())?;
946 let expected = FixedSizeListArray::try_new(
947 PrimitiveArray::from_iter(0i32..10).into_array(),
948 2,
949 Validity::Array(bitbuffer![1 1 1 0 0].into_array()),
950 5,
951 )?
952 .take(indices)?;
953
954 assert_arrays_eq!(result, expected, &mut ctx);
955 Ok(())
956 }
957
958 #[test]
959 fn test_take_piecewise_chunked_fsl() -> VortexResult<()> {
960 let mut ctx = array_session().create_execution_ctx();
961 let c0 = FixedSizeListArray::try_new(
962 PrimitiveArray::from_iter(0i32..6).into_array(),
963 2,
964 Validity::NonNullable,
965 3,
966 )?;
967 let c1 = FixedSizeListArray::try_new(
968 PrimitiveArray::from_iter(6i32..10).into_array(),
969 2,
970 Validity::NonNullable,
971 2,
972 )?;
973 let dtype = c0.dtype().clone();
974 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
975 let reference = FixedSizeListArray::try_new(
976 PrimitiveArray::from_iter(0i32..10).into_array(),
977 2,
978 Validity::NonNullable,
979 5,
980 )?;
981
982 let indices = contiguous_pieces(&[1], &[3])?;
984 assert_arrays_eq!(
985 arr.take(indices.clone())?,
986 reference.take(indices)?,
987 &mut ctx
988 );
989
990 let indices = contiguous_pieces(&[3, 0], &[2, 2])?;
992 assert_arrays_eq!(
993 arr.take(indices.clone())?,
994 reference.take(indices)?,
995 &mut ctx
996 );
997 Ok(())
998 }
999
1000 #[test]
1001 fn test_take_chunked_struct_nested_flatten() -> VortexResult<()> {
1002 let mut ctx = array_session().create_execution_ctx();
1003 let s0 = StructArray::try_new(
1004 ["a"].into(),
1005 vec![buffer![0i32, 1, 2].into_array()],
1006 3,
1007 Validity::NonNullable,
1008 )?;
1009 let s1 = StructArray::try_new(
1010 ["a"].into(),
1011 vec![buffer![3i32, 4].into_array()],
1012 2,
1013 Validity::NonNullable,
1014 )?;
1015 let dtype = s0.dtype().clone();
1016 let arr = ChunkedArray::try_new(vec![s0.into_array(), s1.into_array()], dtype)?;
1017
1018 let result = arr.take(buffer![4u64, 0, 2, 4].into_array())?;
1019 let expected = StructArray::try_new(
1020 ["a"].into(),
1021 vec![buffer![4i32, 0, 2, 4].into_array()],
1022 4,
1023 Validity::NonNullable,
1024 )?;
1025
1026 assert_arrays_eq!(result, expected, &mut ctx);
1027 Ok(())
1028 }
1029
1030 #[test]
1031 fn test_take_chunked_fsl_conformance() -> VortexResult<()> {
1032 let c0 = FixedSizeListArray::try_new(
1033 PrimitiveArray::from_iter(0i32..6).into_array(),
1034 2,
1035 Validity::NonNullable,
1036 3,
1037 )?;
1038 let c1 = FixedSizeListArray::try_new(
1039 PrimitiveArray::from_iter(6i32..10).into_array(),
1040 2,
1041 Validity::NonNullable,
1042 2,
1043 )?;
1044 let dtype = c0.dtype().clone();
1045 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
1046 test_take_conformance(
1047 &arr.into_array(),
1048 &mut array_session().create_execution_ctx(),
1049 );
1050 Ok(())
1051 }
1052
1053 #[test]
1054 fn test_take() {
1055 let mut ctx = array_session().create_execution_ctx();
1056 let a = buffer![1i32, 2, 3].into_array();
1057 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1058 .unwrap();
1059 assert_eq!(arr.nchunks(), 3);
1060 assert_eq!(arr.len(), 9);
1061 let indices = buffer![0u64, 0, 6, 4].into_array();
1062
1063 let result = arr.take(indices).unwrap();
1064 assert_arrays_eq!(result, PrimitiveArray::from_iter([1i32, 1, 1, 2]), &mut ctx);
1065 }
1066
1067 #[test]
1068 fn test_take_nullable_values() {
1069 let mut ctx = array_session().create_execution_ctx();
1070 let a = PrimitiveArray::new(buffer![1i32, 2, 3], Validity::AllValid).into_array();
1071 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1072 .unwrap();
1073 assert_eq!(arr.nchunks(), 3);
1074 assert_eq!(arr.len(), 9);
1075 let indices = PrimitiveArray::new(buffer![0u64, 0, 6, 4], Validity::NonNullable);
1076
1077 let result = arr.take(indices.into_array()).unwrap();
1078 assert_arrays_eq!(
1079 result,
1080 PrimitiveArray::from_option_iter([1i32, 1, 1, 2].map(Some)),
1081 &mut ctx
1082 );
1083 }
1084
1085 #[test]
1086 fn test_take_nullable_indices() {
1087 let mut ctx = array_session().create_execution_ctx();
1088 let a = buffer![1i32, 2, 3].into_array();
1089 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1090 .unwrap();
1091 assert_eq!(arr.nchunks(), 3);
1092 assert_eq!(arr.len(), 9);
1093 let indices = PrimitiveArray::new(
1094 buffer![0u64, 0, 6, 4],
1095 Validity::Array(bitbuffer![1 0 0 1].into_array()),
1096 );
1097
1098 let result = arr.take(indices.into_array()).unwrap();
1099 assert_arrays_eq!(
1100 result,
1101 PrimitiveArray::from_option_iter([Some(1i32), None, None, Some(2)]),
1102 &mut ctx
1103 );
1104 }
1105
1106 #[test]
1107 fn test_take_nullable_struct() {
1108 let mut ctx = array_session().create_execution_ctx();
1109 let struct_array =
1110 StructArray::try_new(FieldNames::default(), vec![], 100, Validity::NonNullable)
1111 .unwrap();
1112
1113 let arr = ChunkedArray::from_iter(vec![
1114 struct_array.clone().into_array(),
1115 struct_array.into_array(),
1116 ]);
1117
1118 let result = arr
1119 .take(PrimitiveArray::from_option_iter(vec![Some(0), None, Some(101)]).into_array())
1120 .unwrap();
1121
1122 let expect = StructArray::try_new(
1123 FieldNames::default(),
1124 vec![],
1125 3,
1126 Validity::Array(BoolArray::from_iter(vec![true, false, true]).into_array()),
1127 )
1128 .unwrap();
1129 assert_arrays_eq!(result, expect, &mut ctx);
1130 }
1131
1132 #[test]
1133 fn test_empty_take() {
1134 let mut ctx = array_session().create_execution_ctx();
1135 let a = buffer![1i32, 2, 3].into_array();
1136 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1137 .unwrap();
1138 assert_eq!(arr.nchunks(), 3);
1139 assert_eq!(arr.len(), 9);
1140
1141 let indices = PrimitiveArray::empty::<u64>(Nullability::NonNullable);
1142 let result = arr.take(indices.into_array()).unwrap();
1143
1144 assert!(result.is_empty());
1145 assert_eq!(result.dtype(), arr.dtype());
1146 assert_arrays_eq!(
1147 result,
1148 PrimitiveArray::empty::<i32>(Nullability::NonNullable),
1149 &mut ctx
1150 );
1151 }
1152
1153 #[test]
1154 fn test_take_shuffled_indices() -> VortexResult<()> {
1155 let mut ctx = array_session().create_execution_ctx();
1156 let c0 = buffer![0i32, 1, 2].into_array();
1157 let c1 = buffer![3i32, 4, 5].into_array();
1158 let c2 = buffer![6i32, 7, 8].into_array();
1159 let arr = ChunkedArray::try_new(
1160 vec![c0, c1, c2],
1161 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1162 .dtype()
1163 .clone(),
1164 )?;
1165
1166 let indices = buffer![8u64, 0, 5, 3, 2, 7, 1, 6, 4].into_array();
1168 let result = arr.take(indices)?;
1169
1170 assert_arrays_eq!(
1171 result,
1172 PrimitiveArray::from_iter([8i32, 0, 5, 3, 2, 7, 1, 6, 4]),
1173 &mut ctx
1174 );
1175 Ok(())
1176 }
1177
1178 #[test]
1179 fn test_take_shuffled_duplicates_with_empty_chunks() -> VortexResult<()> {
1180 let mut ctx = array_session().create_execution_ctx();
1181 let empty = PrimitiveArray::empty::<i32>(Nullability::NonNullable).into_array();
1182 let arr = ChunkedArray::try_new(
1183 vec![
1184 empty.clone(),
1185 buffer![0i32, 1].into_array(),
1186 empty.clone(),
1187 buffer![2i32, 3].into_array(),
1188 empty,
1189 ],
1190 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1191 .dtype()
1192 .clone(),
1193 )?;
1194
1195 let result = arr.take(buffer![3u64, 0, 2, 0, 3, 1, 2].into_array())?;
1196
1197 assert_arrays_eq!(
1198 result,
1199 PrimitiveArray::from_iter([3i32, 0, 2, 0, 3, 1, 2]),
1200 &mut ctx
1201 );
1202 Ok(())
1203 }
1204
1205 #[test]
1206 fn test_take_small_shuffled_fixed_size_lists() -> VortexResult<()> {
1207 let mut ctx = array_session().create_execution_ctx();
1208 let first = FixedSizeListArray::new(
1209 buffer![0i32, 1, 2, 3].into_array(),
1210 2,
1211 Validity::NonNullable,
1212 2,
1213 )
1214 .into_array();
1215 let second = FixedSizeListArray::new(
1216 buffer![4i32, 5, 6, 7].into_array(),
1217 2,
1218 Validity::NonNullable,
1219 2,
1220 )
1221 .into_array();
1222 let dtype = first.dtype().clone();
1223 let array = ChunkedArray::try_new(vec![first, second], dtype)?;
1224
1225 let result = array.take(buffer![3u64, 0, 2, 1, 3].into_array())?;
1226 let expected = FixedSizeListArray::new(
1227 buffer![6i32, 7, 0, 1, 4, 5, 2, 3, 6, 7].into_array(),
1228 2,
1229 Validity::NonNullable,
1230 5,
1231 );
1232
1233 assert_arrays_eq!(result, expected, &mut ctx);
1234 Ok(())
1235 }
1236
1237 #[test]
1238 fn test_take_shuffled_large() -> VortexResult<()> {
1239 let mut ctx = array_session().create_execution_ctx();
1240 let nchunks: i32 = 100;
1241 let chunk_len: i32 = 1_000;
1242 let total = nchunks * chunk_len;
1243
1244 let chunks: Vec<_> = (0..nchunks)
1245 .map(|c| {
1246 let start = c * chunk_len;
1247 PrimitiveArray::from_iter(start..start + chunk_len).into_array()
1248 })
1249 .collect();
1250 let dtype = chunks[0].dtype().clone();
1251 let arr = ChunkedArray::try_new(chunks, dtype)?;
1252
1253 let mut indices: Vec<u64> = (0..u64::try_from(total)?).collect();
1255 let mut seed: u64 = 0xdeadbeef;
1256 for i in (1..indices.len()).rev() {
1257 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
1258 let j = (seed >> 33) as usize % (i + 1);
1259 indices.swap(i, j);
1260 }
1261
1262 let indices_arr = PrimitiveArray::new(Buffer::from(indices.clone()), Validity::NonNullable);
1263 let result = arr.take(indices_arr.into_array())?;
1264
1265 let result = result.execute::<PrimitiveArray>(&mut ctx)?;
1267 let result_vals = result.as_slice::<i32>();
1268 for (pos, &idx) in indices.iter().enumerate() {
1269 assert_eq!(
1270 result_vals[pos],
1271 i32::try_from(idx)?,
1272 "mismatch at position {pos}"
1273 );
1274 }
1275 Ok(())
1276 }
1277
1278 #[test]
1279 fn test_take_null_indices() -> VortexResult<()> {
1280 let mut ctx = array_session().create_execution_ctx();
1281 let c0 = buffer![10i32, 20, 30].into_array();
1282 let c1 = buffer![40i32, 50, 60].into_array();
1283 let arr = ChunkedArray::try_new(
1284 vec![c0, c1],
1285 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1286 .dtype()
1287 .clone(),
1288 )?;
1289
1290 let indices =
1292 PrimitiveArray::from_option_iter([Some(5u64), None, Some(0), Some(3), None, Some(2)]);
1293 let result = arr.take(indices.into_array())?;
1294
1295 assert_arrays_eq!(
1296 result,
1297 PrimitiveArray::from_option_iter([
1298 Some(60i32),
1299 None,
1300 Some(10),
1301 Some(40),
1302 None,
1303 Some(30)
1304 ]),
1305 &mut ctx
1306 );
1307 Ok(())
1308 }
1309
1310 #[test]
1311 fn test_take_sorted_indices() -> VortexResult<()> {
1312 let mut ctx = array_session().create_execution_ctx();
1313 let arr = chunked_i32()?;
1314
1315 let indices = buffer![1u64, 4, 5, 9, 10, 14].into_array();
1317 let result = arr.take(indices)?;
1318
1319 assert_arrays_eq!(
1320 result,
1321 PrimitiveArray::from_iter([1i32, 4, 5, 9, 10, 14]),
1322 &mut ctx
1323 );
1324 Ok(())
1325 }
1326
1327 #[test]
1328 fn test_take_out_of_bounds() -> VortexResult<()> {
1329 let mut ctx = array_session().create_execution_ctx();
1330 let arr = chunked_i32()?;
1331
1332 for indices in [buffer![0u64, 100], buffer![100u64, 0]] {
1334 let result = arr
1335 .take(indices.into_array())
1336 .and_then(|taken| taken.execute::<Canonical>(&mut ctx));
1337 assert!(result.is_err(), "expected out-of-bounds error");
1338 }
1339 Ok(())
1340 }
1341
1342 #[test]
1343 fn test_take_all_null_indices() -> VortexResult<()> {
1344 let mut ctx = array_session().create_execution_ctx();
1345 let arr = chunked_i32()?;
1346
1347 let indices = PrimitiveArray::from_option_iter([None::<u64>, None]).into_array();
1348 let result = arr.take(indices)?;
1349
1350 assert_arrays_eq!(
1351 result,
1352 PrimitiveArray::from_option_iter([None::<i32>, None]),
1353 &mut ctx
1354 );
1355 Ok(())
1356 }
1357
1358 #[test]
1359 fn test_take_chunked_conformance() {
1360 let a = buffer![1i32, 2, 3].into_array();
1361 let b = buffer![4i32, 5].into_array();
1362 let arr = ChunkedArray::try_new(
1363 vec![a, b],
1364 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1365 .dtype()
1366 .clone(),
1367 )
1368 .unwrap();
1369 test_take_conformance(
1370 &arr.into_array(),
1371 &mut array_session().create_execution_ctx(),
1372 );
1373
1374 let a = PrimitiveArray::from_option_iter([Some(1i32), None, Some(3)]);
1376 let b = PrimitiveArray::from_option_iter([Some(4i32), Some(5)]);
1377 let dtype = a.dtype().clone();
1378 let arr = ChunkedArray::try_new(vec![a.into_array(), b.into_array()], dtype).unwrap();
1379 test_take_conformance(
1380 &arr.into_array(),
1381 &mut array_session().create_execution_ctx(),
1382 );
1383
1384 let chunk = buffer![10i32, 20, 30, 40, 50].into_array();
1386 let arr = ChunkedArray::try_new(
1387 vec![chunk.clone(), chunk.clone(), chunk.clone()],
1388 chunk.dtype().clone(),
1389 )
1390 .unwrap();
1391 test_take_conformance(
1392 &arr.into_array(),
1393 &mut array_session().create_execution_ctx(),
1394 );
1395 }
1396}