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)?;
799 let expected = FixedSizeListArray::try_new(
800 PrimitiveArray::from_iter([
801 12i32, 13, 14, 0, 1, 2, 6, 7, 8, 15, 16, 17, 3, 4, 5, 12, 13, 14,
802 ])
803 .into_array(),
804 3,
805 Validity::NonNullable,
806 6,
807 )?;
808
809 assert_arrays_eq!(result, expected, &mut ctx);
810 Ok(())
811 }
812
813 #[test]
814 fn test_take_fsl_over_chunked_elements_conformance() -> VortexResult<()> {
815 let elements = ChunkedArray::try_new(
816 vec![
817 PrimitiveArray::from_iter(0i32..8).into_array(),
818 PrimitiveArray::from_iter(8i32..13).into_array(),
819 PrimitiveArray::from_iter(13i32..18).into_array(),
820 ],
821 DType::Primitive(PType::I32, Nullability::NonNullable),
822 )?
823 .into_array();
824 let fsl = FixedSizeListArray::try_new(elements, 3, Validity::NonNullable, 6)?;
825 test_take_conformance(
826 &fsl.into_array(),
827 &mut array_session().create_execution_ctx(),
828 );
829 Ok(())
830 }
831
832 #[test]
833 fn test_take_chunked_fsl() -> VortexResult<()> {
834 let mut ctx = array_session().create_execution_ctx();
835 let c0 = FixedSizeListArray::try_new(
836 PrimitiveArray::from_iter(0i32..6).into_array(),
837 2,
838 Validity::NonNullable,
839 3,
840 )?;
841 let c1 = FixedSizeListArray::try_new(
842 PrimitiveArray::from_iter(6i32..10).into_array(),
843 2,
844 Validity::NonNullable,
845 2,
846 )?;
847 let dtype = c0.dtype().clone();
848 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
849
850 let indices = buffer![4u64, 0, 3, 3, 1].into_array();
851 let result = arr.take(indices)?;
852 let expected = FixedSizeListArray::try_new(
853 PrimitiveArray::from_iter([8i32, 9, 0, 1, 6, 7, 6, 7, 2, 3]).into_array(),
854 2,
855 Validity::NonNullable,
856 5,
857 )?;
858
859 assert_arrays_eq!(result, expected, &mut ctx);
860 Ok(())
861 }
862
863 #[test]
864 fn test_take_chunked_fsl_nullable() -> VortexResult<()> {
865 let mut ctx = array_session().create_execution_ctx();
866 let c0 = FixedSizeListArray::try_new(
867 PrimitiveArray::from_iter(0i32..6).into_array(),
868 2,
869 Validity::Array(bitbuffer![1 0 1].into_array()),
870 3,
871 )?;
872 let c1 = FixedSizeListArray::try_new(
873 PrimitiveArray::from_iter(6i32..10).into_array(),
874 2,
875 Validity::AllValid,
876 2,
877 )?;
878 let dtype = c0.dtype().clone();
879 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
880
881 let indices =
882 PrimitiveArray::from_option_iter([Some(4u64), None, Some(0), Some(1)]).into_array();
883 let result = arr.take(indices)?;
884 let expected = FixedSizeListArray::try_new(
885 PrimitiveArray::from_iter([8i32, 9, 0, 0, 0, 1, 0, 0]).into_array(),
886 2,
887 Validity::Array(bitbuffer![1 0 1 0].into_array()),
888 4,
889 )?;
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)?;
918 let expected = FixedSizeListArray::try_new(
919 PrimitiveArray::from_iter([8i32, 9, 0, 1, 6, 7, 2, 3]).into_array(),
920 2,
921 Validity::NonNullable,
922 4,
923 )?;
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)?;
945 let expected = FixedSizeListArray::try_new(
946 PrimitiveArray::from_iter([0i32, 0, 0, 1, 0, 0, 2, 3]).into_array(),
947 2,
948 Validity::Array(bitbuffer![0 1 0 1].into_array()),
949 4,
950 )?;
951
952 assert_arrays_eq!(result, expected, &mut ctx);
953 Ok(())
954 }
955
956 #[test]
957 fn test_take_piecewise_chunked_fsl() -> VortexResult<()> {
958 let mut ctx = array_session().create_execution_ctx();
959 let c0 = FixedSizeListArray::try_new(
960 PrimitiveArray::from_iter(0i32..6).into_array(),
961 2,
962 Validity::NonNullable,
963 3,
964 )?;
965 let c1 = FixedSizeListArray::try_new(
966 PrimitiveArray::from_iter(6i32..10).into_array(),
967 2,
968 Validity::NonNullable,
969 2,
970 )?;
971 let dtype = c0.dtype().clone();
972 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
973 let reference = FixedSizeListArray::try_new(
974 PrimitiveArray::from_iter(0i32..10).into_array(),
975 2,
976 Validity::NonNullable,
977 5,
978 )?;
979
980 let indices = contiguous_pieces(&[1], &[3])?;
982 let result = arr.take(indices.clone())?;
983 assert_arrays_eq!(&result, reference.take(indices)?, &mut ctx);
984 let expected = FixedSizeListArray::try_new(
985 PrimitiveArray::from_iter([2i32, 3, 4, 5, 6, 7]).into_array(),
986 2,
987 Validity::NonNullable,
988 3,
989 )?;
990 assert_arrays_eq!(result, expected, &mut ctx);
991
992 let indices = contiguous_pieces(&[3, 0], &[2, 2])?;
994 let result = arr.take(indices.clone())?;
995 assert_arrays_eq!(&result, reference.take(indices)?, &mut ctx);
996 let expected = FixedSizeListArray::try_new(
997 PrimitiveArray::from_iter([6i32, 7, 8, 9, 0, 1, 2, 3]).into_array(),
998 2,
999 Validity::NonNullable,
1000 4,
1001 )?;
1002 assert_arrays_eq!(result, expected, &mut ctx);
1003 Ok(())
1004 }
1005
1006 #[test]
1007 fn test_take_chunked_struct_nested_flatten() -> VortexResult<()> {
1008 let mut ctx = array_session().create_execution_ctx();
1009 let s0 = StructArray::try_new(
1010 ["a"].into(),
1011 vec![buffer![0i32, 1, 2].into_array()],
1012 3,
1013 Validity::NonNullable,
1014 )?;
1015 let s1 = StructArray::try_new(
1016 ["a"].into(),
1017 vec![buffer![3i32, 4].into_array()],
1018 2,
1019 Validity::NonNullable,
1020 )?;
1021 let dtype = s0.dtype().clone();
1022 let arr = ChunkedArray::try_new(vec![s0.into_array(), s1.into_array()], dtype)?;
1023
1024 let result = arr.take(buffer![4u64, 0, 2, 4].into_array())?;
1025 let expected = StructArray::try_new(
1026 ["a"].into(),
1027 vec![buffer![4i32, 0, 2, 4].into_array()],
1028 4,
1029 Validity::NonNullable,
1030 )?;
1031
1032 assert_arrays_eq!(result, expected, &mut ctx);
1033 Ok(())
1034 }
1035
1036 #[test]
1037 fn test_take_chunked_fsl_conformance() -> VortexResult<()> {
1038 let c0 = FixedSizeListArray::try_new(
1039 PrimitiveArray::from_iter(0i32..6).into_array(),
1040 2,
1041 Validity::NonNullable,
1042 3,
1043 )?;
1044 let c1 = FixedSizeListArray::try_new(
1045 PrimitiveArray::from_iter(6i32..10).into_array(),
1046 2,
1047 Validity::NonNullable,
1048 2,
1049 )?;
1050 let dtype = c0.dtype().clone();
1051 let arr = ChunkedArray::try_new(vec![c0.into_array(), c1.into_array()], dtype)?;
1052 test_take_conformance(
1053 &arr.into_array(),
1054 &mut array_session().create_execution_ctx(),
1055 );
1056 Ok(())
1057 }
1058
1059 #[test]
1060 fn test_take() {
1061 let mut ctx = array_session().create_execution_ctx();
1062 let a = buffer![1i32, 2, 3].into_array();
1063 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1064 .unwrap();
1065 assert_eq!(arr.nchunks(), 3);
1066 assert_eq!(arr.len(), 9);
1067 let indices = buffer![0u64, 0, 6, 4].into_array();
1068
1069 let result = arr.take(indices).unwrap();
1070 assert_arrays_eq!(result, PrimitiveArray::from_iter([1i32, 1, 1, 2]), &mut ctx);
1071 }
1072
1073 #[test]
1074 fn test_take_nullable_values() {
1075 let mut ctx = array_session().create_execution_ctx();
1076 let a = PrimitiveArray::new(buffer![1i32, 2, 3], Validity::AllValid).into_array();
1077 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1078 .unwrap();
1079 assert_eq!(arr.nchunks(), 3);
1080 assert_eq!(arr.len(), 9);
1081 let indices = PrimitiveArray::new(buffer![0u64, 0, 6, 4], Validity::NonNullable);
1082
1083 let result = arr.take(indices.into_array()).unwrap();
1084 assert_arrays_eq!(
1085 result,
1086 PrimitiveArray::from_option_iter([1i32, 1, 1, 2].map(Some)),
1087 &mut ctx
1088 );
1089 }
1090
1091 #[test]
1092 fn test_take_nullable_indices() {
1093 let mut ctx = array_session().create_execution_ctx();
1094 let a = buffer![1i32, 2, 3].into_array();
1095 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1096 .unwrap();
1097 assert_eq!(arr.nchunks(), 3);
1098 assert_eq!(arr.len(), 9);
1099 let indices = PrimitiveArray::new(
1100 buffer![0u64, 0, 6, 4],
1101 Validity::Array(bitbuffer![1 0 0 1].into_array()),
1102 );
1103
1104 let result = arr.take(indices.into_array()).unwrap();
1105 assert_arrays_eq!(
1106 result,
1107 PrimitiveArray::from_option_iter([Some(1i32), None, None, Some(2)]),
1108 &mut ctx
1109 );
1110 }
1111
1112 #[test]
1113 fn test_take_nullable_struct() {
1114 let mut ctx = array_session().create_execution_ctx();
1115 let struct_array =
1116 StructArray::try_new(FieldNames::default(), vec![], 100, Validity::NonNullable)
1117 .unwrap();
1118
1119 let arr = ChunkedArray::from_iter(vec![
1120 struct_array.clone().into_array(),
1121 struct_array.into_array(),
1122 ]);
1123
1124 let result = arr
1125 .take(PrimitiveArray::from_option_iter(vec![Some(0), None, Some(101)]).into_array())
1126 .unwrap();
1127
1128 let expect = StructArray::try_new(
1129 FieldNames::default(),
1130 vec![],
1131 3,
1132 Validity::Array(BoolArray::from_iter(vec![true, false, true]).into_array()),
1133 )
1134 .unwrap();
1135 assert_arrays_eq!(result, expect, &mut ctx);
1136 }
1137
1138 #[test]
1139 fn test_empty_take() {
1140 let mut ctx = array_session().create_execution_ctx();
1141 let a = buffer![1i32, 2, 3].into_array();
1142 let arr = ChunkedArray::try_new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone())
1143 .unwrap();
1144 assert_eq!(arr.nchunks(), 3);
1145 assert_eq!(arr.len(), 9);
1146
1147 let indices = PrimitiveArray::empty::<u64>(Nullability::NonNullable);
1148 let result = arr.take(indices.into_array()).unwrap();
1149
1150 assert!(result.is_empty());
1151 assert_eq!(result.dtype(), arr.dtype());
1152 assert_arrays_eq!(
1153 result,
1154 PrimitiveArray::empty::<i32>(Nullability::NonNullable),
1155 &mut ctx
1156 );
1157 }
1158
1159 #[test]
1160 fn test_take_shuffled_indices() -> VortexResult<()> {
1161 let mut ctx = array_session().create_execution_ctx();
1162 let c0 = buffer![0i32, 1, 2].into_array();
1163 let c1 = buffer![3i32, 4, 5].into_array();
1164 let c2 = buffer![6i32, 7, 8].into_array();
1165 let arr = ChunkedArray::try_new(
1166 vec![c0, c1, c2],
1167 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1168 .dtype()
1169 .clone(),
1170 )?;
1171
1172 let indices = buffer![8u64, 0, 5, 3, 2, 7, 1, 6, 4].into_array();
1174 let result = arr.take(indices)?;
1175
1176 assert_arrays_eq!(
1177 result,
1178 PrimitiveArray::from_iter([8i32, 0, 5, 3, 2, 7, 1, 6, 4]),
1179 &mut ctx
1180 );
1181 Ok(())
1182 }
1183
1184 #[test]
1185 fn test_take_shuffled_duplicates_with_empty_chunks() -> VortexResult<()> {
1186 let mut ctx = array_session().create_execution_ctx();
1187 let empty = PrimitiveArray::empty::<i32>(Nullability::NonNullable).into_array();
1188 let arr = ChunkedArray::try_new(
1189 vec![
1190 empty.clone(),
1191 buffer![0i32, 1].into_array(),
1192 empty.clone(),
1193 buffer![2i32, 3].into_array(),
1194 empty,
1195 ],
1196 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1197 .dtype()
1198 .clone(),
1199 )?;
1200
1201 let result = arr.take(buffer![3u64, 0, 2, 0, 3, 1, 2].into_array())?;
1202
1203 assert_arrays_eq!(
1204 result,
1205 PrimitiveArray::from_iter([3i32, 0, 2, 0, 3, 1, 2]),
1206 &mut ctx
1207 );
1208 Ok(())
1209 }
1210
1211 #[test]
1212 fn test_take_small_shuffled_fixed_size_lists() -> VortexResult<()> {
1213 let mut ctx = array_session().create_execution_ctx();
1214 let first = FixedSizeListArray::new(
1215 buffer![0i32, 1, 2, 3].into_array(),
1216 2,
1217 Validity::NonNullable,
1218 2,
1219 )
1220 .into_array();
1221 let second = FixedSizeListArray::new(
1222 buffer![4i32, 5, 6, 7].into_array(),
1223 2,
1224 Validity::NonNullable,
1225 2,
1226 )
1227 .into_array();
1228 let dtype = first.dtype().clone();
1229 let array = ChunkedArray::try_new(vec![first, second], dtype)?;
1230
1231 let result = array.take(buffer![3u64, 0, 2, 1, 3].into_array())?;
1232 let expected = FixedSizeListArray::new(
1233 buffer![6i32, 7, 0, 1, 4, 5, 2, 3, 6, 7].into_array(),
1234 2,
1235 Validity::NonNullable,
1236 5,
1237 );
1238
1239 assert_arrays_eq!(result, expected, &mut ctx);
1240 Ok(())
1241 }
1242
1243 #[test]
1244 fn test_take_shuffled_large() -> VortexResult<()> {
1245 let mut ctx = array_session().create_execution_ctx();
1246 let nchunks: i32 = 100;
1247 let chunk_len: i32 = 1_000;
1248 let total = nchunks * chunk_len;
1249
1250 let chunks: Vec<_> = (0..nchunks)
1251 .map(|c| {
1252 let start = c * chunk_len;
1253 PrimitiveArray::from_iter(start..start + chunk_len).into_array()
1254 })
1255 .collect();
1256 let dtype = chunks[0].dtype().clone();
1257 let arr = ChunkedArray::try_new(chunks, dtype)?;
1258
1259 let mut indices: Vec<u64> = (0..u64::try_from(total)?).collect();
1261 let mut seed: u64 = 0xdeadbeef;
1262 for i in (1..indices.len()).rev() {
1263 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
1264 let j = (seed >> 33) as usize % (i + 1);
1265 indices.swap(i, j);
1266 }
1267
1268 let indices_arr = PrimitiveArray::new(Buffer::from(indices.clone()), Validity::NonNullable);
1269 let result = arr.take(indices_arr.into_array())?;
1270
1271 let result = result.execute::<PrimitiveArray>(&mut ctx)?;
1273 assert_eq!(
1274 result.dtype(),
1275 &DType::Primitive(PType::I32, Nullability::NonNullable)
1276 );
1277 assert_eq!(result.len(), indices.len());
1278 let result_vals = result.as_slice::<i32>();
1279 for (pos, &idx) in indices.iter().enumerate() {
1280 assert_eq!(
1281 result_vals[pos],
1282 i32::try_from(idx)?,
1283 "mismatch at position {pos}"
1284 );
1285 }
1286 Ok(())
1287 }
1288
1289 #[test]
1290 fn test_take_null_indices() -> VortexResult<()> {
1291 let mut ctx = array_session().create_execution_ctx();
1292 let c0 = buffer![10i32, 20, 30].into_array();
1293 let c1 = buffer![40i32, 50, 60].into_array();
1294 let arr = ChunkedArray::try_new(
1295 vec![c0, c1],
1296 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1297 .dtype()
1298 .clone(),
1299 )?;
1300
1301 let indices =
1303 PrimitiveArray::from_option_iter([Some(5u64), None, Some(0), Some(3), None, Some(2)]);
1304 let result = arr.take(indices.into_array())?;
1305
1306 assert_arrays_eq!(
1307 result,
1308 PrimitiveArray::from_option_iter([
1309 Some(60i32),
1310 None,
1311 Some(10),
1312 Some(40),
1313 None,
1314 Some(30)
1315 ]),
1316 &mut ctx
1317 );
1318 Ok(())
1319 }
1320
1321 #[test]
1322 fn test_take_sorted_indices() -> VortexResult<()> {
1323 let mut ctx = array_session().create_execution_ctx();
1324 let arr = chunked_i32()?;
1325
1326 let indices = buffer![1u64, 4, 5, 9, 10, 14].into_array();
1328 let result = arr.take(indices)?;
1329
1330 assert_arrays_eq!(
1331 result,
1332 PrimitiveArray::from_iter([1i32, 4, 5, 9, 10, 14]),
1333 &mut ctx
1334 );
1335 Ok(())
1336 }
1337
1338 #[test]
1339 fn test_take_out_of_bounds() -> VortexResult<()> {
1340 let mut ctx = array_session().create_execution_ctx();
1341 let arr = chunked_i32()?;
1342
1343 for indices in [buffer![0u64, 100], buffer![100u64, 0]] {
1345 let result = arr
1346 .take(indices.into_array())
1347 .and_then(|taken| taken.execute::<Canonical>(&mut ctx));
1348 assert!(result.is_err(), "expected out-of-bounds error");
1349 }
1350 Ok(())
1351 }
1352
1353 #[test]
1354 fn test_take_all_null_indices() -> VortexResult<()> {
1355 let mut ctx = array_session().create_execution_ctx();
1356 let arr = chunked_i32()?;
1357
1358 let indices = PrimitiveArray::from_option_iter([None::<u64>, None]).into_array();
1359 let result = arr.take(indices)?;
1360
1361 assert_arrays_eq!(
1362 result,
1363 PrimitiveArray::from_option_iter([None::<i32>, None]),
1364 &mut ctx
1365 );
1366 Ok(())
1367 }
1368
1369 #[test]
1370 fn test_take_chunked_conformance() {
1371 let a = buffer![1i32, 2, 3].into_array();
1372 let b = buffer![4i32, 5].into_array();
1373 let arr = ChunkedArray::try_new(
1374 vec![a, b],
1375 PrimitiveArray::empty::<i32>(Nullability::NonNullable)
1376 .dtype()
1377 .clone(),
1378 )
1379 .unwrap();
1380 test_take_conformance(
1381 &arr.into_array(),
1382 &mut array_session().create_execution_ctx(),
1383 );
1384
1385 let a = PrimitiveArray::from_option_iter([Some(1i32), None, Some(3)]);
1387 let b = PrimitiveArray::from_option_iter([Some(4i32), Some(5)]);
1388 let dtype = a.dtype().clone();
1389 let arr = ChunkedArray::try_new(vec![a.into_array(), b.into_array()], dtype).unwrap();
1390 test_take_conformance(
1391 &arr.into_array(),
1392 &mut array_session().create_execution_ctx(),
1393 );
1394
1395 let chunk = buffer![10i32, 20, 30, 40, 50].into_array();
1397 let arr = ChunkedArray::try_new(
1398 vec![chunk.clone(), chunk.clone(), chunk.clone()],
1399 chunk.dtype().clone(),
1400 )
1401 .unwrap();
1402 test_take_conformance(
1403 &arr.into_array(),
1404 &mut array_session().create_execution_ctx(),
1405 );
1406 }
1407}