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;
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!(
482 total_len == output_len,
483 "PiecewiseSequenceArray expanded length {total_len} does not match declared length {output_len}"
484 );
485
486 if monotonic {
488 let mut gathered = Vec::new();
489 for (chunk_idx, plan) in plans.into_iter().enumerate() {
490 if plan.starts.is_empty() {
491 continue;
492 }
493 gathered.push(gather_chunk(array.chunk(chunk_idx), plan)?);
494 }
495 let result = if gathered.len() == 1 {
496 gathered.swap_remove(0)
497 } else {
498 unsafe { ChunkedArray::new_unchecked(gathered, array.dtype().clone()) }.into_array()
501 };
502 return Ok(Some(result));
503 }
504
505 let mut bases = vec![0usize; nchunks];
508 let mut running = 0usize;
509 let mut flattener = ChunkFlattener::new(array.dtype(), output_len, ctx.allocator());
510 for (chunk_idx, plan) in plans.into_iter().enumerate() {
511 if plan.starts.is_empty() {
512 continue;
513 }
514 bases[chunk_idx] = running;
515 running += plan.total;
516 flattener.push(gather_chunk(array.chunk(chunk_idx), plan)?, ctx)?;
517 }
518 let flat = flattener.finish(array.dtype(), ctx)?;
519
520 let mut reorder_starts = Vec::with_capacity(sub_pieces.len());
521 let mut reorder_lengths = Vec::with_capacity(sub_pieces.len());
522 for &(chunk_idx, offset, run) in &sub_pieces {
523 reorder_starts.push((bases[chunk_idx] + offset) as u64);
524 reorder_lengths.push(run as u64);
525 }
526 flat.take(contiguous_runs(reorder_starts, reorder_lengths, output_len))
527 .map(Some)
528}
529
530fn gather_chunk(chunk: &ArrayRef, plan: ChunkGather) -> VortexResult<ArrayRef> {
533 if let [start] = plan.starts.as_slice() {
534 let start = usize::try_from(*start)?;
535 return chunk.slice(start..start + plan.total);
536 }
537 chunk.take(contiguous_runs(plan.starts, plan.lengths, plan.total))
538}
539
540fn contiguous_runs(starts: Vec<u64>, lengths: Vec<u64>, total: usize) -> ArrayRef {
543 let count = starts.len();
544 debug_assert_eq!(count, lengths.len());
545 let starts = PrimitiveArray::new(Buffer::from(starts), Validity::NonNullable).into_array();
546 let lengths = match lengths.first() {
547 Some(&first) if lengths.iter().all(|&length| length == first) => {
548 ConstantArray::new(first, count).into_array()
549 }
550 _ => PrimitiveArray::new(Buffer::from(lengths), Validity::NonNullable).into_array(),
551 };
552 let multipliers = ConstantArray::new(1u64, count).into_array();
553 unsafe { PiecewiseSequenceArray::new_unchecked(starts, lengths, multipliers, total) }
556 .into_array()
557}
558
559#[cfg(test)]
560mod tests {
561 use vortex_buffer::Buffer;
562 use vortex_buffer::bitbuffer;
563 use vortex_buffer::buffer;
564 use vortex_error::VortexResult;
565
566 use crate::ArrayRef;
567 use crate::Canonical;
568 use crate::IntoArray;
569 use crate::VortexSessionExecute;
570 use crate::array_session;
571 use crate::arrays::BoolArray;
572 use crate::arrays::ChunkedArray;
573 use crate::arrays::ConstantArray;
574 use crate::arrays::FixedSizeListArray;
575 use crate::arrays::PiecewiseSequenceArray;
576 use crate::arrays::PrimitiveArray;
577 use crate::arrays::StructArray;
578 use crate::arrays::chunked::ChunkedArrayExt;
579 use crate::assert_arrays_eq;
580 use crate::compute::conformance::take::test_take_conformance;
581 use crate::dtype::DType;
582 use crate::dtype::FieldNames;
583 use crate::dtype::Nullability;
584 use crate::dtype::PType;
585 use crate::scalar::Scalar;
586 use crate::validity::Validity;
587
588 fn chunked_i32() -> VortexResult<ChunkedArray> {
589 ChunkedArray::try_new(
590 vec![
591 buffer![0i32, 1, 2, 3, 4].into_array(),
592 buffer![5i32, 6, 7, 8, 9].into_array(),
593 buffer![10i32, 11, 12, 13, 14].into_array(),
594 ],
595 DType::Primitive(PType::I32, Nullability::NonNullable),
596 )
597 }
598
599 fn contiguous_pieces(starts: &[u64], lengths: &[u64]) -> VortexResult<ArrayRef> {
600 let len = usize::try_from(lengths.iter().sum::<u64>())?;
601 Ok(PiecewiseSequenceArray::try_new(
602 starts.iter().copied().collect::<Buffer<u64>>().into_array(),
603 lengths
604 .iter()
605 .copied()
606 .collect::<Buffer<u64>>()
607 .into_array(),
608 ConstantArray::new(1u64, starts.len()).into_array(),
609 len,
610 )?
611 .into_array())
612 }
613
614 #[test]
615 fn test_take_piecewise_monotonic_spanning_chunks() -> VortexResult<()> {
616 let mut ctx = array_session().create_execution_ctx();
617 let arr = chunked_i32()?;
618
619 let indices = contiguous_pieces(&[1, 4, 9], &[3, 4, 6])?;
621 let result = arr.take(indices)?;
622
623 assert_arrays_eq!(
624 result,
625 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14]),
626 &mut ctx
627 );
628 Ok(())
629 }
630
631 #[test]
632 fn test_take_piecewise_interleaved() -> VortexResult<()> {
633 let mut ctx = array_session().create_execution_ctx();
634 let arr = chunked_i32()?;
635
636 let indices = contiguous_pieces(&[12, 2, 7, 0], &[3, 2, 3, 1])?;
638 let result = arr.take(indices)?;
639
640 assert_arrays_eq!(
641 result,
642 PrimitiveArray::from_iter([12i32, 13, 14, 2, 3, 7, 8, 9, 0]),
643 &mut ctx
644 );
645 Ok(())
646 }
647
648 #[test]
649 fn test_take_piecewise_whole_array() -> VortexResult<()> {
650 let mut ctx = array_session().create_execution_ctx();
651 let arr = chunked_i32()?;
652
653 let indices = contiguous_pieces(&[0], &[15])?;
654 let result = arr.take(indices)?;
655
656 assert_arrays_eq!(result, PrimitiveArray::from_iter(0i32..15), &mut ctx);
657 Ok(())
658 }
659
660 #[test]
661 fn test_take_piecewise_across_empty_chunk() -> VortexResult<()> {
662 let mut ctx = array_session().create_execution_ctx();
663 let arr = ChunkedArray::try_new(
664 vec![
665 buffer![0i32, 1, 2, 3, 4].into_array(),
666 PrimitiveArray::empty::<i32>(Nullability::NonNullable).into_array(),
667 buffer![5i32, 6, 7, 8, 9].into_array(),
668 ],
669 DType::Primitive(PType::I32, Nullability::NonNullable),
670 )?;
671
672 let indices = contiguous_pieces(&[3], &[4])?;
673 let result = arr.take(indices)?;
674
675 assert_arrays_eq!(result, PrimitiveArray::from_iter([3i32, 4, 5, 6]), &mut ctx);
676 Ok(())
677 }
678
679 #[test]
680 fn test_take_piecewise_adjacent_pieces_merge() -> VortexResult<()> {
681 let mut ctx = array_session().create_execution_ctx();
682 let arr = chunked_i32()?;
683
684 let indices = contiguous_pieces(&[0, 2, 7], &[2, 2, 2])?;
687 let result = arr.take(indices)?;
688
689 assert_arrays_eq!(
690 result,
691 PrimitiveArray::from_iter([0i32, 1, 2, 3, 7, 8]),
692 &mut ctx
693 );
694 Ok(())
695 }
696
697 #[test]
698 fn test_take_piecewise_same_chunk_out_of_order() -> VortexResult<()> {
699 let mut ctx = array_session().create_execution_ctx();
700 let arr = chunked_i32()?;
701
702 let indices = contiguous_pieces(&[2, 0], &[2, 2])?;
704 let result = arr.take(indices)?;
705
706 assert_arrays_eq!(result, PrimitiveArray::from_iter([2i32, 3, 0, 1]), &mut ctx);
707 Ok(())
708 }
709
710 #[test]
711 fn test_take_piecewise_zero_length_pieces() -> VortexResult<()> {
712 let mut ctx = array_session().create_execution_ctx();
713 let arr = chunked_i32()?;
714
715 let indices = contiguous_pieces(&[5, 0, 2], &[0, 4, 0])?;
716 let result = arr.take(indices)?;
717
718 assert_arrays_eq!(result, PrimitiveArray::from_iter([0i32, 1, 2, 3]), &mut ctx);
719 Ok(())
720 }
721
722 #[test]
723 fn test_take_piecewise_out_of_bounds() -> VortexResult<()> {
724 let mut ctx = array_session().create_execution_ctx();
725 let arr = chunked_i32()?;
726
727 let indices = contiguous_pieces(&[12], &[5])?;
728 let result = arr
729 .take(indices)
730 .and_then(|taken| taken.execute::<Canonical>(&mut ctx));
731
732 assert!(result.is_err());
733 Ok(())
734 }
735
736 #[test]
737 fn test_take_piecewise_non_unit_multiplier() -> VortexResult<()> {
738 let mut ctx = array_session().create_execution_ctx();
739 let arr = chunked_i32()?;
740
741 let indices = PiecewiseSequenceArray::try_new(
743 buffer![0u64, 1].into_array(),
744 buffer![5u64, 3].into_array(),
745 buffer![2u64, 4].into_array(),
746 8,
747 )?
748 .into_array();
749 let result = arr.take(indices)?;
750
751 assert_arrays_eq!(
752 result,
753 PrimitiveArray::from_iter([0i32, 2, 4, 6, 8, 1, 5, 9]),
754 &mut ctx
755 );
756 Ok(())
757 }
758
759 #[test]
760 fn test_take_piecewise_nullable_values() -> VortexResult<()> {
761 let mut ctx = array_session().create_execution_ctx();
762 let arr = ChunkedArray::try_new(
763 vec![
764 PrimitiveArray::from_option_iter([Some(0i32), None, Some(2)]).into_array(),
765 PrimitiveArray::from_option_iter([None, Some(4i32), Some(5)]).into_array(),
766 ],
767 DType::Primitive(PType::I32, Nullability::Nullable),
768 )?;
769
770 let indices = contiguous_pieces(&[4, 1], &[2, 3])?;
771 let result = arr.take(indices)?;
772
773 assert_arrays_eq!(
774 result,
775 PrimitiveArray::from_option_iter([Some(4i32), Some(5), None, Some(2), None]),
776 &mut ctx
777 );
778 Ok(())
779 }
780
781 #[test]
782 fn test_take_fsl_over_chunked_elements() -> VortexResult<()> {
783 let mut ctx = array_session().create_execution_ctx();
784 let elements = ChunkedArray::try_new(
786 vec![
787 PrimitiveArray::from_iter(0i32..8).into_array(),
788 PrimitiveArray::from_iter(8i32..13).into_array(),
789 PrimitiveArray::from_iter(13i32..18).into_array(),
790 ],
791 DType::Primitive(PType::I32, Nullability::NonNullable),
792 )?
793 .into_array();
794 let fsl = FixedSizeListArray::try_new(elements, 3, Validity::NonNullable, 6)?;
795
796 let indices = buffer![4u64, 0, 2, 5, 1, 4].into_array();
797 let result = fsl.take(indices.clone())?;
798 let expected = FixedSizeListArray::try_new(
799 PrimitiveArray::from_iter(0i32..18).into_array(),
800 3,
801 Validity::NonNullable,
802 6,
803 )?
804 .take(indices)?;
805
806 assert_arrays_eq!(result, expected, &mut ctx);
807 Ok(())
808 }
809
810 #[test]
811 fn test_take_fsl_over_chunked_elements_conformance() -> VortexResult<()> {
812 let elements = ChunkedArray::try_new(
813 vec![
814 PrimitiveArray::from_iter(0i32..8).into_array(),
815 PrimitiveArray::from_iter(8i32..13).into_array(),
816 PrimitiveArray::from_iter(13i32..18).into_array(),
817 ],
818 DType::Primitive(PType::I32, Nullability::NonNullable),
819 )?
820 .into_array();
821 let fsl = FixedSizeListArray::try_new(elements, 3, Validity::NonNullable, 6)?;
822 test_take_conformance(
823 &fsl.into_array(),
824 &mut array_session().create_execution_ctx(),
825 );
826 Ok(())
827 }
828
829 #[test]
830 fn test_take_chunked_fsl() -> VortexResult<()> {
831 let mut ctx = array_session().create_execution_ctx();
832 let c0 = FixedSizeListArray::try_new(
833 PrimitiveArray::from_iter(0i32..6).into_array(),
834 2,
835 Validity::NonNullable,
836 3,
837 )?;
838 let c1 = FixedSizeListArray::try_new(
839 PrimitiveArray::from_iter(6i32..10).into_array(),
840 2,
841 Validity::NonNullable,
842 2,
843 )?;
844 let dtype = c0.dtype().clone();
845 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
846
847 let indices = buffer![4u64, 0, 3, 3, 1].into_array();
848 let result = arr.take(indices.clone())?;
849 let expected = FixedSizeListArray::try_new(
850 PrimitiveArray::from_iter(0i32..10).into_array(),
851 2,
852 Validity::NonNullable,
853 5,
854 )?
855 .take(indices)?;
856
857 assert_arrays_eq!(result, expected, &mut ctx);
858 Ok(())
859 }
860
861 #[test]
862 fn test_take_chunked_fsl_nullable() -> VortexResult<()> {
863 let mut ctx = array_session().create_execution_ctx();
864 let c0 = FixedSizeListArray::try_new(
865 PrimitiveArray::from_iter(0i32..6).into_array(),
866 2,
867 Validity::Array(bitbuffer![1 0 1].into_array()),
868 3,
869 )?;
870 let c1 = FixedSizeListArray::try_new(
871 PrimitiveArray::from_iter(6i32..10).into_array(),
872 2,
873 Validity::AllValid,
874 2,
875 )?;
876 let dtype = c0.dtype().clone();
877 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
878
879 let indices =
880 PrimitiveArray::from_option_iter([Some(4u64), None, Some(0), Some(1)]).into_array();
881 let result = arr.take(indices.clone())?;
882 let expected = FixedSizeListArray::try_new(
883 PrimitiveArray::from_iter(0i32..10).into_array(),
884 2,
885 Validity::Array(bitbuffer![1 0 1 1 1].into_array()),
886 5,
887 )?
888 .take(indices)?;
889
890 assert_arrays_eq!(result, expected, &mut ctx);
891 Ok(())
892 }
893
894 #[test]
895 fn test_take_chunked_fsl_non_fsl_chunk() -> VortexResult<()> {
896 let mut ctx = array_session().create_execution_ctx();
897 let c0 = FixedSizeListArray::try_new(
898 PrimitiveArray::from_iter(0i32..6).into_array(),
899 2,
900 Validity::NonNullable,
901 3,
902 )?;
903 let c1 = FixedSizeListArray::try_new(
904 PrimitiveArray::from_iter(6i32..10).into_array(),
905 2,
906 Validity::NonNullable,
907 2,
908 )?;
909 let dtype = c0.dtype().clone();
910 let nested = ChunkedArray::try_new(vec![c1.into_array()], dtype.clone())?;
913 let arr = ChunkedArray::try_new(vec![c0.into_array(), nested.into_array()], dtype)?;
914
915 let indices = buffer![4u64, 0, 3, 1].into_array();
916 let result = arr.take(indices.clone())?;
917 let expected = FixedSizeListArray::try_new(
918 PrimitiveArray::from_iter(0i32..10).into_array(),
919 2,
920 Validity::NonNullable,
921 5,
922 )?
923 .take(indices)?;
924
925 assert_arrays_eq!(result, expected, &mut ctx);
926 Ok(())
927 }
928
929 #[test]
930 fn test_take_chunked_fsl_constant_chunk() -> VortexResult<()> {
931 let mut ctx = array_session().create_execution_ctx();
932 let c0 = FixedSizeListArray::try_new(
933 PrimitiveArray::from_iter(0i32..6).into_array(),
934 2,
935 Validity::AllValid,
936 3,
937 )?;
938 let dtype = c0.dtype().clone();
939 let c1 = ConstantArray::new(Scalar::null(dtype.clone()), 2).into_array();
941 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1], dtype)?;
942
943 let indices = buffer![4u64, 0, 3, 1].into_array();
944 let result = arr.take(indices.clone())?;
945 let expected = FixedSizeListArray::try_new(
946 PrimitiveArray::from_iter(0i32..10).into_array(),
947 2,
948 Validity::Array(bitbuffer![1 1 1 0 0].into_array()),
949 5,
950 )?
951 .take(indices)?;
952
953 assert_arrays_eq!(result, expected, &mut ctx);
954 Ok(())
955 }
956
957 #[test]
958 fn test_take_piecewise_chunked_fsl() -> VortexResult<()> {
959 let mut ctx = array_session().create_execution_ctx();
960 let c0 = FixedSizeListArray::try_new(
961 PrimitiveArray::from_iter(0i32..6).into_array(),
962 2,
963 Validity::NonNullable,
964 3,
965 )?;
966 let c1 = FixedSizeListArray::try_new(
967 PrimitiveArray::from_iter(6i32..10).into_array(),
968 2,
969 Validity::NonNullable,
970 2,
971 )?;
972 let dtype = c0.dtype().clone();
973 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
974 let reference = FixedSizeListArray::try_new(
975 PrimitiveArray::from_iter(0i32..10).into_array(),
976 2,
977 Validity::NonNullable,
978 5,
979 )?;
980
981 let indices = contiguous_pieces(&[1], &[3])?;
983 assert_arrays_eq!(
984 arr.take(indices.clone())?,
985 reference.take(indices)?,
986 &mut ctx
987 );
988
989 let indices = contiguous_pieces(&[3, 0], &[2, 2])?;
991 assert_arrays_eq!(
992 arr.take(indices.clone())?,
993 reference.take(indices)?,
994 &mut ctx
995 );
996 Ok(())
997 }
998
999 #[test]
1000 fn test_take_chunked_struct_nested_flatten() -> VortexResult<()> {
1001 let mut ctx = array_session().create_execution_ctx();
1002 let s0 = StructArray::try_new(
1003 ["a"].into(),
1004 vec![buffer![0i32, 1, 2].into_array()],
1005 3,
1006 Validity::NonNullable,
1007 )?;
1008 let s1 = StructArray::try_new(
1009 ["a"].into(),
1010 vec![buffer![3i32, 4].into_array()],
1011 2,
1012 Validity::NonNullable,
1013 )?;
1014 let dtype = s0.dtype().clone();
1015 let arr = ChunkedArray::try_new(vec![s0.into_array(), s1.into_array()], dtype)?;
1016
1017 let result = arr.take(buffer![4u64, 0, 2, 4].into_array())?;
1018 let expected = StructArray::try_new(
1019 ["a"].into(),
1020 vec![buffer![4i32, 0, 2, 4].into_array()],
1021 4,
1022 Validity::NonNullable,
1023 )?;
1024
1025 assert_arrays_eq!(result, expected, &mut ctx);
1026 Ok(())
1027 }
1028
1029 #[test]
1030 fn test_take_chunked_fsl_conformance() -> VortexResult<()> {
1031 let c0 = FixedSizeListArray::try_new(
1032 PrimitiveArray::from_iter(0i32..6).into_array(),
1033 2,
1034 Validity::NonNullable,
1035 3,
1036 )?;
1037 let c1 = FixedSizeListArray::try_new(
1038 PrimitiveArray::from_iter(6i32..10).into_array(),
1039 2,
1040 Validity::NonNullable,
1041 2,
1042 )?;
1043 let dtype = c0.dtype().clone();
1044 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
1045 test_take_conformance(
1046 &arr.into_array(),
1047 &mut array_session().create_execution_ctx(),
1048 );
1049 Ok(())
1050 }
1051
1052 #[test]
1053 fn test_take() {
1054 let mut ctx = array_session().create_execution_ctx();
1055 let a = buffer![1i32, 2, 3].into_array();
1056 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1057 .unwrap();
1058 assert_eq!(arr.nchunks(), 3);
1059 assert_eq!(arr.len(), 9);
1060 let indices = buffer![0u64, 0, 6, 4].into_array();
1061
1062 let result = arr.take(indices).unwrap();
1063 assert_arrays_eq!(result, PrimitiveArray::from_iter([1i32, 1, 1, 2]), &mut ctx);
1064 }
1065
1066 #[test]
1067 fn test_take_nullable_values() {
1068 let mut ctx = array_session().create_execution_ctx();
1069 let a = PrimitiveArray::new(buffer![1i32, 2, 3], Validity::AllValid).into_array();
1070 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1071 .unwrap();
1072 assert_eq!(arr.nchunks(), 3);
1073 assert_eq!(arr.len(), 9);
1074 let indices = PrimitiveArray::new(buffer![0u64, 0, 6, 4], Validity::NonNullable);
1075
1076 let result = arr.take(indices.into_array()).unwrap();
1077 assert_arrays_eq!(
1078 result,
1079 PrimitiveArray::from_option_iter([1i32, 1, 1, 2].map(Some)),
1080 &mut ctx
1081 );
1082 }
1083
1084 #[test]
1085 fn test_take_nullable_indices() {
1086 let mut ctx = array_session().create_execution_ctx();
1087 let a = buffer![1i32, 2, 3].into_array();
1088 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1089 .unwrap();
1090 assert_eq!(arr.nchunks(), 3);
1091 assert_eq!(arr.len(), 9);
1092 let indices = PrimitiveArray::new(
1093 buffer![0u64, 0, 6, 4],
1094 Validity::Array(bitbuffer![1 0 0 1].into_array()),
1095 );
1096
1097 let result = arr.take(indices.into_array()).unwrap();
1098 assert_arrays_eq!(
1099 result,
1100 PrimitiveArray::from_option_iter([Some(1i32), None, None, Some(2)]),
1101 &mut ctx
1102 );
1103 }
1104
1105 #[test]
1106 fn test_take_nullable_struct() {
1107 let mut ctx = array_session().create_execution_ctx();
1108 let struct_array =
1109 StructArray::try_new(FieldNames::default(), vec![], 100, Validity::NonNullable)
1110 .unwrap();
1111
1112 let arr = ChunkedArray::from_iter(vec![
1113 struct_array.clone().into_array(),
1114 struct_array.into_array(),
1115 ]);
1116
1117 let result = arr
1118 .take(PrimitiveArray::from_option_iter(vec![Some(0), None, Some(101)]).into_array())
1119 .unwrap();
1120
1121 let expect = StructArray::try_new(
1122 FieldNames::default(),
1123 vec![],
1124 3,
1125 Validity::Array(BoolArray::from_iter(vec![true, false, true]).into_array()),
1126 )
1127 .unwrap();
1128 assert_arrays_eq!(result, expect, &mut ctx);
1129 }
1130
1131 #[test]
1132 fn test_empty_take() {
1133 let mut ctx = array_session().create_execution_ctx();
1134 let a = buffer![1i32, 2, 3].into_array();
1135 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1136 .unwrap();
1137 assert_eq!(arr.nchunks(), 3);
1138 assert_eq!(arr.len(), 9);
1139
1140 let indices = PrimitiveArray::empty::<u64>(Nullability::NonNullable);
1141 let result = arr.take(indices.into_array()).unwrap();
1142
1143 assert!(result.is_empty());
1144 assert_eq!(result.dtype(), arr.dtype());
1145 assert_arrays_eq!(
1146 result,
1147 PrimitiveArray::empty::<i32>(Nullability::NonNullable),
1148 &mut ctx
1149 );
1150 }
1151
1152 #[test]
1153 fn test_take_shuffled_indices() -> VortexResult<()> {
1154 let mut ctx = array_session().create_execution_ctx();
1155 let c0 = buffer![0i32, 1, 2].into_array();
1156 let c1 = buffer![3i32, 4, 5].into_array();
1157 let c2 = buffer![6i32, 7, 8].into_array();
1158 let arr = ChunkedArray::try_new(
1159 vec![c0, c1, c2],
1160 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1161 .dtype()
1162 .clone(),
1163 )?;
1164
1165 let indices = buffer![8u64, 0, 5, 3, 2, 7, 1, 6, 4].into_array();
1167 let result = arr.take(indices)?;
1168
1169 assert_arrays_eq!(
1170 result,
1171 PrimitiveArray::from_iter([8i32, 0, 5, 3, 2, 7, 1, 6, 4]),
1172 &mut ctx
1173 );
1174 Ok(())
1175 }
1176
1177 #[test]
1178 fn test_take_shuffled_duplicates_with_empty_chunks() -> VortexResult<()> {
1179 let mut ctx = array_session().create_execution_ctx();
1180 let empty = PrimitiveArray::empty::<i32>(Nullability::NonNullable).into_array();
1181 let arr = ChunkedArray::try_new(
1182 vec![
1183 empty.clone(),
1184 buffer![0i32, 1].into_array(),
1185 empty.clone(),
1186 buffer![2i32, 3].into_array(),
1187 empty,
1188 ],
1189 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1190 .dtype()
1191 .clone(),
1192 )?;
1193
1194 let result = arr.take(buffer![3u64, 0, 2, 0, 3, 1, 2].into_array())?;
1195
1196 assert_arrays_eq!(
1197 result,
1198 PrimitiveArray::from_iter([3i32, 0, 2, 0, 3, 1, 2]),
1199 &mut ctx
1200 );
1201 Ok(())
1202 }
1203
1204 #[test]
1205 fn test_take_small_shuffled_fixed_size_lists() -> VortexResult<()> {
1206 let mut ctx = array_session().create_execution_ctx();
1207 let first = FixedSizeListArray::new(
1208 buffer![0i32, 1, 2, 3].into_array(),
1209 2,
1210 Validity::NonNullable,
1211 2,
1212 )
1213 .into_array();
1214 let second = FixedSizeListArray::new(
1215 buffer![4i32, 5, 6, 7].into_array(),
1216 2,
1217 Validity::NonNullable,
1218 2,
1219 )
1220 .into_array();
1221 let dtype = first.dtype().clone();
1222 let array = ChunkedArray::try_new(vec![first, second], dtype)?;
1223
1224 let result = array.take(buffer![3u64, 0, 2, 1, 3].into_array())?;
1225 let expected = FixedSizeListArray::new(
1226 buffer![6i32, 7, 0, 1, 4, 5, 2, 3, 6, 7].into_array(),
1227 2,
1228 Validity::NonNullable,
1229 5,
1230 );
1231
1232 assert_arrays_eq!(result, expected, &mut ctx);
1233 Ok(())
1234 }
1235
1236 #[test]
1237 fn test_take_shuffled_large() -> VortexResult<()> {
1238 let mut ctx = array_session().create_execution_ctx();
1239 let nchunks: i32 = 100;
1240 let chunk_len: i32 = 1_000;
1241 let total = nchunks * chunk_len;
1242
1243 let chunks: Vec<_> = (0..nchunks)
1244 .map(|c| {
1245 let start = c * chunk_len;
1246 PrimitiveArray::from_iter(start..start + chunk_len).into_array()
1247 })
1248 .collect();
1249 let dtype = chunks[0].dtype().clone();
1250 let arr = ChunkedArray::try_new(chunks, dtype)?;
1251
1252 let mut indices: Vec<u64> = (0..u64::try_from(total)?).collect();
1254 let mut seed: u64 = 0xdeadbeef;
1255 for i in (1..indices.len()).rev() {
1256 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
1257 let j = (seed >> 33) as usize % (i + 1);
1258 indices.swap(i, j);
1259 }
1260
1261 let indices_arr = PrimitiveArray::new(Buffer::from(indices.clone()), Validity::NonNullable);
1262 let result = arr.take(indices_arr.into_array())?;
1263
1264 let result = result.execute::<PrimitiveArray>(&mut ctx)?;
1266 let result_vals = result.as_slice::<i32>();
1267 for (pos, &idx) in indices.iter().enumerate() {
1268 assert_eq!(
1269 result_vals[pos],
1270 i32::try_from(idx)?,
1271 "mismatch at position {pos}"
1272 );
1273 }
1274 Ok(())
1275 }
1276
1277 #[test]
1278 fn test_take_null_indices() -> VortexResult<()> {
1279 let mut ctx = array_session().create_execution_ctx();
1280 let c0 = buffer![10i32, 20, 30].into_array();
1281 let c1 = buffer![40i32, 50, 60].into_array();
1282 let arr = ChunkedArray::try_new(
1283 vec![c0, c1],
1284 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1285 .dtype()
1286 .clone(),
1287 )?;
1288
1289 let indices =
1291 PrimitiveArray::from_option_iter([Some(5u64), None, Some(0), Some(3), None, Some(2)]);
1292 let result = arr.take(indices.into_array())?;
1293
1294 assert_arrays_eq!(
1295 result,
1296 PrimitiveArray::from_option_iter([
1297 Some(60i32),
1298 None,
1299 Some(10),
1300 Some(40),
1301 None,
1302 Some(30)
1303 ]),
1304 &mut ctx
1305 );
1306 Ok(())
1307 }
1308
1309 #[test]
1310 fn test_take_sorted_indices() -> VortexResult<()> {
1311 let mut ctx = array_session().create_execution_ctx();
1312 let arr = chunked_i32()?;
1313
1314 let indices = buffer![1u64, 4, 5, 9, 10, 14].into_array();
1316 let result = arr.take(indices)?;
1317
1318 assert_arrays_eq!(
1319 result,
1320 PrimitiveArray::from_iter([1i32, 4, 5, 9, 10, 14]),
1321 &mut ctx
1322 );
1323 Ok(())
1324 }
1325
1326 #[test]
1327 fn test_take_out_of_bounds() -> VortexResult<()> {
1328 let mut ctx = array_session().create_execution_ctx();
1329 let arr = chunked_i32()?;
1330
1331 for indices in [buffer![0u64, 100], buffer![100u64, 0]] {
1333 let result = arr
1334 .take(indices.into_array())
1335 .and_then(|taken| taken.execute::<Canonical>(&mut ctx));
1336 assert!(result.is_err(), "expected out-of-bounds error");
1337 }
1338 Ok(())
1339 }
1340
1341 #[test]
1342 fn test_take_all_null_indices() -> VortexResult<()> {
1343 let mut ctx = array_session().create_execution_ctx();
1344 let arr = chunked_i32()?;
1345
1346 let indices = PrimitiveArray::from_option_iter([None::<u64>, None]).into_array();
1347 let result = arr.take(indices)?;
1348
1349 assert_arrays_eq!(
1350 result,
1351 PrimitiveArray::from_option_iter([None::<i32>, None]),
1352 &mut ctx
1353 );
1354 Ok(())
1355 }
1356
1357 #[test]
1358 fn test_take_chunked_conformance() {
1359 let a = buffer![1i32, 2, 3].into_array();
1360 let b = buffer![4i32, 5].into_array();
1361 let arr = ChunkedArray::try_new(
1362 vec![a, b],
1363 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1364 .dtype()
1365 .clone(),
1366 )
1367 .unwrap();
1368 test_take_conformance(
1369 &arr.into_array(),
1370 &mut array_session().create_execution_ctx(),
1371 );
1372
1373 let a = PrimitiveArray::from_option_iter([Some(1i32), None, Some(3)]);
1375 let b = PrimitiveArray::from_option_iter([Some(4i32), Some(5)]);
1376 let dtype = a.dtype().clone();
1377 let arr = ChunkedArray::try_new(vec![a.into_array(), b.into_array()], dtype).unwrap();
1378 test_take_conformance(
1379 &arr.into_array(),
1380 &mut array_session().create_execution_ctx(),
1381 );
1382
1383 let chunk = buffer![10i32, 20, 30, 40, 50].into_array();
1385 let arr = ChunkedArray::try_new(
1386 vec![chunk.clone(), chunk.clone(), chunk.clone()],
1387 chunk.dtype().clone(),
1388 )
1389 .unwrap();
1390 test_take_conformance(
1391 &arr.into_array(),
1392 &mut array_session().create_execution_ctx(),
1393 );
1394 }
1395}