1use num_traits::AsPrimitive;
5use num_traits::NumCast;
6use vortex_array::ArrayRef;
7use vortex_array::ArrayView;
8use vortex_array::ExecutionCtx;
9use vortex_array::IntoArray;
10use vortex_array::arrays::ConstantArray;
11use vortex_array::arrays::PrimitiveArray;
12use vortex_array::arrays::dict::TakeExecute;
13use vortex_array::dtype::UnsignedPType;
14use vortex_array::match_each_integer_ptype;
15use vortex_array::match_each_unsigned_integer_ptype;
16use vortex_array::scalar::Scalar;
17use vortex_array::validity::Validity;
18use vortex_buffer::Buffer;
19use vortex_buffer::BufferMut;
20use vortex_error::VortexResult;
21use vortex_error::vortex_bail;
22use vortex_mask::AllOr;
23use vortex_mask::Mask;
24
25use crate::RunEnd;
26use crate::array::RunEndArrayExt;
27use crate::array::RunEndArraySlotsExt;
28use crate::iter::trimmed_ends_iter;
29
30const SORTED_LINEAR_RUNS_PER_INDEX_THRESHOLD: usize = 16;
31const UNSORTED_LINEAR_RUNS_PER_INDEX_THRESHOLD: usize = 4;
32const UNSORTED_LINEAR_MIN_RUNS: usize = 1 << 19;
35const TABLE_LEN_PER_INDEX_THRESHOLD: usize = 8;
39
40impl TakeExecute for RunEnd {
41 fn take(
42 array: ArrayView<'_, Self>,
43 indices: &ArrayRef,
44 ctx: &mut ExecutionCtx,
45 ) -> VortexResult<Option<ArrayRef>> {
46 let primitive_indices = indices.clone().execute::<PrimitiveArray>(ctx)?;
47 let indices_validity = primitive_indices.validity()?;
48 let indices_mask = indices_validity.execute_mask(primitive_indices.len(), ctx)?;
49
50 let taken = match_each_integer_ptype!(primitive_indices.ptype(), |P| {
51 take_indices(
52 array,
53 primitive_indices.as_slice::<P>(),
54 &indices_validity,
55 &indices_mask,
56 true,
57 ctx,
58 )?
59 });
60
61 Ok(Some(taken))
62 }
63}
64
65pub fn take_indices_unchecked<T: AsPrimitive<usize>>(
69 array: ArrayView<'_, RunEnd>,
70 indices: &[T],
71 validity: &Validity,
72 ctx: &mut ExecutionCtx,
73) -> VortexResult<ArrayRef> {
74 let validity_mask = validity.execute_mask(indices.len(), ctx)?;
75 take_indices(array, indices, validity, &validity_mask, false, ctx)
76}
77
78fn take_indices<T: AsPrimitive<usize>>(
79 array: ArrayView<'_, RunEnd>,
80 indices: &[T],
81 validity: &Validity,
82 validity_mask: &Mask,
83 check_bounds: bool,
84 ctx: &mut ExecutionCtx,
85) -> VortexResult<ArrayRef> {
86 if validity_mask.all_false() {
87 return Ok(
88 ConstantArray::new(Scalar::null(array.dtype().as_nullable()), indices.len())
89 .into_array(),
90 );
91 }
92
93 let stats = valid_indices_stats(indices, validity_mask, array.len(), check_bounds)?;
94 let ends = array.ends().clone().execute::<PrimitiveArray>(ctx)?;
95
96 let physical_indices = match_each_unsigned_integer_ptype!(ends.ptype(), |I| {
97 let ends = ends.as_slice::<I>();
98 if ends.len() <= u32::MAX as usize {
101 PrimitiveArray::new(
102 physical_indices_with_stats::<_, _, u32>(
103 ends,
104 array.offset(),
105 array.len(),
106 indices,
107 validity_mask,
108 stats,
109 ),
110 validity.clone(),
111 )
112 } else {
113 PrimitiveArray::new(
114 physical_indices_with_stats::<_, _, u64>(
115 ends,
116 array.offset(),
117 array.len(),
118 indices,
119 validity_mask,
120 stats,
121 ),
122 validity.clone(),
123 )
124 }
125 });
126
127 array.values().take(physical_indices.into_array())
128}
129
130#[derive(Clone, Copy)]
131struct ValidIndicesStats {
132 count: usize,
133 sorted: bool,
134}
135
136fn physical_indices_with_stats<I, T, O>(
137 ends: &[I],
138 offset: usize,
139 array_len: usize,
140 indices: &[T],
141 validity_mask: &Mask,
142 stats: ValidIndicesStats,
143) -> Buffer<O>
144where
145 I: UnsignedPType,
146 T: AsPrimitive<usize>,
147 O: UnsignedPType,
148 usize: AsPrimitive<O>,
149{
150 if stats.count == 0 {
151 return Buffer::zeroed(indices.len());
152 }
153
154 if stats.sorted
155 && prefer_linear_scan(
156 ends.len(),
157 stats.count,
158 SORTED_LINEAR_RUNS_PER_INDEX_THRESHOLD,
159 )
160 {
161 return physical_indices_linear_sorted(ends, offset, indices, validity_mask);
162 }
163
164 if array_len <= stats.count.saturating_mul(TABLE_LEN_PER_INDEX_THRESHOLD) {
168 return physical_indices_table(ends, offset, array_len, indices, validity_mask);
169 }
170
171 if ends.len() >= UNSORTED_LINEAR_MIN_RUNS
172 && prefer_linear_scan(
173 ends.len(),
174 stats.count,
175 UNSORTED_LINEAR_RUNS_PER_INDEX_THRESHOLD,
176 )
177 {
178 return physical_indices_linear_unsorted(ends, offset, indices, validity_mask, stats.count);
179 }
180
181 physical_indices_binary(ends, offset, indices, validity_mask)
182}
183
184fn valid_indices_stats<T: AsPrimitive<usize>>(
187 indices: &[T],
188 validity_mask: &Mask,
189 array_len: usize,
190 check_bounds: bool,
191) -> VortexResult<ValidIndicesStats> {
192 debug_assert_eq!(indices.len(), validity_mask.len());
193
194 let count = validity_mask.true_count();
195 if count == 0 {
196 return Ok(ValidIndicesStats {
197 count,
198 sorted: true,
199 });
200 }
201
202 let sorted = match validity_mask.bit_buffer() {
203 AllOr::All => valid_indices_sorted_all(indices, array_len, check_bounds)?,
204 AllOr::None => true,
205 AllOr::Some(validity) => {
206 valid_indices_sorted_masked(indices, validity.iter(), array_len, check_bounds)?
207 }
208 };
209
210 Ok(ValidIndicesStats { count, sorted })
211}
212
213fn valid_indices_sorted_all<T: AsPrimitive<usize>>(
214 indices: &[T],
215 array_len: usize,
216 check_bounds: bool,
217) -> VortexResult<bool> {
218 let Some((first, rest)) = indices.split_first() else {
221 return Ok(true);
222 };
223
224 let mut previous_idx = first.as_();
225 if check_bounds {
226 check_index(previous_idx, array_len)?;
227 }
228
229 let mut sorted = true;
230 for idx in rest {
231 let idx = idx.as_();
232 if check_bounds {
233 check_index(idx, array_len)?;
234 }
235 if previous_idx > idx {
236 sorted = false;
237 if !check_bounds {
238 break;
239 }
240 }
241 previous_idx = idx;
242 }
243
244 Ok(sorted)
245}
246
247fn valid_indices_sorted_masked<T: AsPrimitive<usize>>(
248 indices: &[T],
249 is_valid: impl Iterator<Item = bool>,
250 array_len: usize,
251 check_bounds: bool,
252) -> VortexResult<bool> {
253 let mut valid = is_valid
256 .zip(indices.iter())
257 .filter(|(is_valid, _)| *is_valid)
258 .map(|(_, idx)| idx.as_());
259
260 let Some(mut previous_idx) = valid.next() else {
263 return Ok(true);
264 };
265 if check_bounds {
266 check_index(previous_idx, array_len)?;
267 }
268
269 let mut sorted = true;
270 for idx in valid {
271 if check_bounds {
272 check_index(idx, array_len)?;
273 }
274 if previous_idx > idx {
275 sorted = false;
276 if !check_bounds {
277 break;
278 }
279 }
280 previous_idx = idx;
281 }
282
283 Ok(sorted)
284}
285
286fn prefer_linear_scan(
287 ends_len: usize,
288 valid_count: usize,
289 runs_per_index_threshold: usize,
290) -> bool {
291 ends_len <= valid_count.saturating_mul(runs_per_index_threshold)
292}
293
294fn check_index(index: usize, array_len: usize) -> VortexResult<()> {
295 if index >= array_len {
296 vortex_bail!(OutOfBounds: index, 0, array_len);
297 }
298 Ok(())
299}
300
301fn physical_indices_linear_sorted<I, T, O>(
302 ends: &[I],
303 offset: usize,
304 indices: &[T],
305 validity_mask: &Mask,
306) -> Buffer<O>
307where
308 I: UnsignedPType,
309 T: AsPrimitive<usize>,
310 O: UnsignedPType,
311 usize: AsPrimitive<O>,
312{
313 let mut run_idx = 0;
314
315 match validity_mask.bit_buffer() {
316 AllOr::All => Buffer::from_trusted_len_iter(indices.iter().map(|idx| {
317 advance_run(ends, &mut run_idx, idx.as_() + offset);
318 run_idx.as_()
319 })),
320 AllOr::None => unreachable!("AllInvalid indices have been handled earlier"),
321 AllOr::Some(validity) => {
322 let mut physical_indices = BufferMut::zeroed(indices.len());
325 for (idx_pos, (is_valid, idx)) in validity.iter().zip(indices.iter()).enumerate() {
326 if !is_valid {
327 continue;
328 }
329
330 advance_run(ends, &mut run_idx, idx.as_() + offset);
331 physical_indices[idx_pos] = run_idx.as_();
332 }
333 physical_indices.freeze()
334 }
335 }
336}
337
338fn physical_indices_table<I, T, O>(
345 ends: &[I],
346 offset: usize,
347 array_len: usize,
348 indices: &[T],
349 validity_mask: &Mask,
350) -> Buffer<O>
351where
352 I: UnsignedPType,
353 T: AsPrimitive<usize>,
354 O: UnsignedPType,
355 usize: AsPrimitive<O>,
356{
357 let table = run_index_table::<I, O>(ends, offset, array_len);
358 let table = table.as_slice();
359
360 match validity_mask.bit_buffer() {
361 AllOr::All => Buffer::from_trusted_len_iter(indices.iter().map(|idx| table[idx.as_()])),
362 AllOr::None => unreachable!("AllInvalid indices have been handled earlier"),
363 AllOr::Some(validity) => Buffer::from_trusted_len_iter(
364 validity
365 .iter()
366 .zip(indices.iter())
367 .map(|(is_valid, idx)| table[if is_valid { idx.as_() } else { 0 }]),
368 ),
369 }
370}
371
372fn run_index_table<I, O>(ends: &[I], offset: usize, len: usize) -> Buffer<O>
374where
375 I: UnsignedPType,
376 O: UnsignedPType,
377 usize: AsPrimitive<O>,
378{
379 let mut table = BufferMut::with_capacity(len);
380 let mut run_start = 0;
381 for (run_idx, run_end) in trimmed_ends_iter(ends, offset, len).enumerate() {
382 table.push_n(run_idx.as_(), run_end - run_start);
383 run_start = run_end;
384 }
385 table.freeze()
386}
387
388fn physical_indices_linear_unsorted<I, T, O>(
389 ends: &[I],
390 offset: usize,
391 indices: &[T],
392 validity_mask: &Mask,
393 valid_count: usize,
394) -> Buffer<O>
395where
396 I: UnsignedPType,
397 T: AsPrimitive<usize>,
398 O: UnsignedPType,
399 usize: AsPrimitive<O>,
400{
401 let mut pairs = Vec::with_capacity(valid_count);
402 match validity_mask.bit_buffer() {
403 AllOr::All => {
404 pairs.extend(
405 indices
406 .iter()
407 .enumerate()
408 .map(|(idx_pos, idx)| (idx.as_(), idx_pos)),
409 );
410 }
411 AllOr::None => unreachable!("AllInvalid indices have been handled earlier"),
412 AllOr::Some(validity) => {
413 for (idx_pos, (is_valid, idx)) in validity.iter().zip(indices.iter()).enumerate() {
414 if is_valid {
415 pairs.push((idx.as_(), idx_pos));
416 }
417 }
418 }
419 }
420 pairs.sort_unstable();
421
422 let mut physical_indices = BufferMut::zeroed(indices.len());
423 let mut run_idx = 0;
424
425 for (idx, idx_pos) in pairs {
426 advance_run(ends, &mut run_idx, idx + offset);
427 physical_indices[idx_pos] = run_idx.as_();
428 }
429
430 physical_indices.freeze()
431}
432
433fn physical_indices_binary<I, T, O>(
434 ends: &[I],
435 offset: usize,
436 indices: &[T],
437 validity_mask: &Mask,
438) -> Buffer<O>
439where
440 I: UnsignedPType,
441 T: AsPrimitive<usize>,
442 O: UnsignedPType,
443 usize: AsPrimitive<O>,
444{
445 match validity_mask.bit_buffer() {
446 AllOr::All => Buffer::from_trusted_len_iter(
447 indices
448 .iter()
449 .map(|idx| physical_index_binary(ends, idx.as_() + offset).as_()),
450 ),
451 AllOr::None => Buffer::zeroed(indices.len()),
452 AllOr::Some(validity) => {
453 let mut physical_indices = BufferMut::zeroed(indices.len());
454 for (idx_pos, (is_valid, idx)) in validity.iter().zip(indices.iter()).enumerate() {
455 if !is_valid {
456 continue;
457 }
458
459 physical_indices[idx_pos] = physical_index_binary(ends, idx.as_() + offset).as_();
460 }
461 physical_indices.freeze()
462 }
463 }
464}
465
466fn physical_index_binary<I: UnsignedPType>(ends: &[I], logical_idx: usize) -> usize {
467 let index = match <I as NumCast>::from(logical_idx) {
468 Some(logical_idx) => ends.partition_point(|end| *end <= logical_idx),
469 None => ends.len(),
470 };
471 index.min(ends.len() - 1)
472}
473
474fn advance_run<I: UnsignedPType>(ends: &[I], run_idx: &mut usize, logical_idx: usize) {
475 let Some(logical_idx) = I::from(logical_idx) else {
478 *run_idx = ends.len().saturating_sub(1);
479 return;
480 };
481 while *run_idx + 1 < ends.len() && ends[*run_idx] <= logical_idx {
482 *run_idx += 1;
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use std::sync::LazyLock;
489
490 use rstest::rstest;
491 use vortex_array::ArrayRef;
492 use vortex_array::Canonical;
493 use vortex_array::IntoArray;
494 use vortex_array::VortexSessionExecute;
495 use vortex_array::arrays::BoolArray;
496 use vortex_array::arrays::PrimitiveArray;
497 use vortex_array::assert_arrays_eq;
498 use vortex_array::compute::conformance::take::test_take_conformance;
499 use vortex_array::validity::Validity;
500 use vortex_buffer::buffer;
501 use vortex_mask::Mask;
502 use vortex_session::VortexSession;
503
504 use super::physical_indices_binary;
505 use super::physical_indices_linear_sorted;
506 use super::physical_indices_linear_unsorted;
507 use super::physical_indices_table;
508 use crate::RunEnd;
509 use crate::RunEndArray;
510
511 static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
512 let session = vortex_array::array_session();
513 crate::initialize(&session);
514 session
515 });
516
517 fn ree_array() -> RunEndArray {
518 RunEnd::encode(
519 buffer![1, 1, 1, 4, 4, 4, 2, 2, 5, 5, 5, 5].into_array(),
520 &mut SESSION.create_execution_ctx(),
521 )
522 .unwrap()
523 }
524
525 #[test]
526 fn ree_take() {
527 let taken = ree_array().take(buffer![9, 8, 1, 3].into_array()).unwrap();
528 let expected = PrimitiveArray::from_iter(vec![5i32, 5, 1, 4]).into_array();
529 assert_arrays_eq!(taken, expected, &mut SESSION.create_execution_ctx());
530 }
531
532 #[test]
533 fn ree_take_end() {
534 let taken = ree_array().take(buffer![11].into_array()).unwrap();
535 let expected = PrimitiveArray::from_iter(vec![5i32]).into_array();
536 assert_arrays_eq!(taken, expected, &mut SESSION.create_execution_ctx());
537 }
538
539 #[test]
540 fn ree_take_sorted_boundaries() {
541 let taken = ree_array()
542 .take(buffer![0, 2, 3, 6, 8, 11].into_array())
543 .unwrap();
544 let expected = PrimitiveArray::from_iter(vec![1i32, 1, 4, 2, 5, 5]).into_array();
545 assert_arrays_eq!(taken, expected, &mut SESSION.create_execution_ctx());
546 }
547
548 #[test]
549 #[should_panic]
550 fn ree_take_out_of_bounds() {
551 let _array = ree_array()
552 .take(buffer![12].into_array())
553 .unwrap()
554 .execute::<Canonical>(&mut SESSION.create_execution_ctx())
555 .unwrap();
556 }
557
558 #[test]
559 fn sliced_take() {
560 let sliced = ree_array().slice(4..9).unwrap();
561 let taken = sliced.take(buffer![1, 3, 4].into_array()).unwrap();
562
563 let expected = PrimitiveArray::from_iter(vec![4i32, 2, 5]).into_array();
564 assert_arrays_eq!(taken, expected, &mut SESSION.create_execution_ctx());
565 }
566
567 #[test]
568 fn sliced_take_unsorted_dense() {
569 let sliced = ree_array().slice(4..9).unwrap();
570 let taken = sliced.take(buffer![4, 0, 2, 1].into_array()).unwrap();
571
572 let expected = PrimitiveArray::from_iter(vec![5i32, 4, 2, 4]).into_array();
573 assert_arrays_eq!(taken, expected, &mut SESSION.create_execution_ctx());
574 }
575
576 #[test]
577 fn ree_take_nullable() {
578 let taken = ree_array()
579 .take(PrimitiveArray::from_option_iter([Some(1), None]).into_array())
580 .unwrap();
581
582 let expected = PrimitiveArray::from_option_iter([Some(1i32), None]);
583 assert_arrays_eq!(
584 taken,
585 expected.into_array(),
586 &mut SESSION.create_execution_ctx()
587 );
588 }
589
590 #[test]
591 fn ree_take_all_null_indices() {
592 let taken = ree_array()
593 .take(PrimitiveArray::from_option_iter([None::<u64>, None]).into_array())
594 .unwrap();
595
596 let expected = PrimitiveArray::from_option_iter([None::<i32>, None]);
597 assert_arrays_eq!(
598 taken,
599 expected.into_array(),
600 &mut SESSION.create_execution_ctx()
601 );
602 }
603
604 #[test]
605 fn ree_take_null_index_skips_out_of_bounds_value() {
606 let indices = PrimitiveArray::new(
607 buffer![1u64, 12],
608 Validity::Array(BoolArray::from_iter([true, false]).into_array()),
609 );
610 let taken = ree_array().take(indices.into_array()).unwrap();
611
612 let expected = PrimitiveArray::from_option_iter([Some(1i32), None]);
613 assert_arrays_eq!(
614 taken,
615 expected.into_array(),
616 &mut SESSION.create_execution_ctx()
617 );
618 }
619
620 #[test]
621 fn ree_take_unsorted_null_index_skips_out_of_bounds_value() {
622 let indices = PrimitiveArray::new(
623 buffer![3u64, 12, 1],
624 Validity::Array(BoolArray::from_iter([true, false, true]).into_array()),
625 );
626 let taken = ree_array().take(indices.into_array()).unwrap();
627
628 let expected = PrimitiveArray::from_option_iter([Some(4i32), None, Some(1)]);
629 assert_arrays_eq!(
630 taken,
631 expected.into_array(),
632 &mut SESSION.create_execution_ctx()
633 );
634 }
635
636 #[test]
637 fn ree_take_dense_null_index_skips_out_of_bounds_value() {
638 let indices = PrimitiveArray::new(
639 buffer![0u64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12],
640 Validity::Array(
641 BoolArray::from_iter([
642 true, true, true, true, true, true, true, true, true, true, true, false,
643 ])
644 .into_array(),
645 ),
646 );
647 let taken = ree_array().take(indices.into_array()).unwrap();
648
649 let expected = PrimitiveArray::from_option_iter([
650 Some(1i32),
651 Some(1),
652 Some(1),
653 Some(4),
654 Some(4),
655 Some(4),
656 Some(2),
657 Some(2),
658 Some(5),
659 Some(5),
660 Some(5),
661 None,
662 ]);
663 assert_arrays_eq!(
664 taken,
665 expected.into_array(),
666 &mut SESSION.create_execution_ctx()
667 );
668 }
669
670 #[rstest]
671 #[case(vec![3u32, 6, 8, 12], 0, 12, vec![0u64, 11, 3, 3, 7, 2, 9], Mask::new_true(7))]
672 #[case(vec![3u32, 6, 8, 12], 0, 12, vec![5u64, 100, 2, 11, 0], Mask::from_indices(5, [0, 2, 3, 4]))]
673 #[case(vec![6u32, 8, 12], 4, 5, vec![4u64, 0, 2, 1, 3], Mask::new_true(5))]
674 fn unsorted_strategies_agree(
675 #[case] ends: Vec<u32>,
676 #[case] offset: usize,
677 #[case] len: usize,
678 #[case] indices: Vec<u64>,
679 #[case] mask: Mask,
680 ) {
681 let binary = physical_indices_binary::<u32, u64, u64>(&ends, offset, &indices, &mask);
682 let table = physical_indices_table::<u32, u64, u64>(&ends, offset, len, &indices, &mask);
683 let sort_merge = physical_indices_linear_unsorted::<u32, u64, u64>(
684 &ends,
685 offset,
686 &indices,
687 &mask,
688 mask.true_count(),
689 );
690
691 assert_eq!(binary.as_slice(), table.as_slice());
692 assert_eq!(binary.as_slice(), sort_merge.as_slice());
693 }
694
695 #[rstest]
696 #[case(vec![3u32, 6, 8, 12], 0, 12, vec![0u64, 2, 3, 6, 8, 11], Mask::new_true(6))]
697 #[case(vec![3u32, 6, 8, 12], 0, 12, vec![1u64, 100, 5, 9], Mask::from_indices(4, [0, 2, 3]))]
698 #[case(vec![6u32, 8, 12], 4, 5, vec![0u64, 1, 3, 4], Mask::new_true(4))]
699 fn sorted_strategies_agree(
700 #[case] ends: Vec<u32>,
701 #[case] offset: usize,
702 #[case] len: usize,
703 #[case] indices: Vec<u64>,
704 #[case] mask: Mask,
705 ) {
706 let binary = physical_indices_binary::<u32, u64, u64>(&ends, offset, &indices, &mask);
707 let table = physical_indices_table::<u32, u64, u64>(&ends, offset, len, &indices, &mask);
708 let sorted =
709 physical_indices_linear_sorted::<u32, u64, u64>(&ends, offset, &indices, &mask);
710
711 assert_eq!(binary.as_slice(), table.as_slice());
712 assert_eq!(binary.as_slice(), sorted.as_slice());
713 }
714
715 #[rstest]
716 #[case(ree_array())]
717 #[case(RunEnd::encode(
718 buffer![1u8, 1, 2, 2, 2, 3, 3, 3, 3, 4].into_array(),
719 &mut SESSION.create_execution_ctx(),
720 ).unwrap())]
721 #[case(RunEnd::encode(
722 PrimitiveArray::from_option_iter([
723 Some(10),
724 Some(10),
725 None,
726 None,
727 Some(20),
728 Some(20),
729 Some(20),
730 ])
731 .into_array(),
732 &mut SESSION.create_execution_ctx(),
733 ).unwrap())]
734 #[case(RunEnd::encode(buffer![42i32, 42, 42, 42, 42].into_array(),
735 &mut SESSION.create_execution_ctx())
736 .unwrap())]
737 #[case(RunEnd::encode(
738 buffer![1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_array(),
739 &mut SESSION.create_execution_ctx(),
740 ).unwrap())]
741 #[case({
742 let mut values = Vec::new();
743 for i in 0..20 {
744 for _ in 0..=i {
745 values.push(i);
746 }
747 }
748 RunEnd::encode(
749 PrimitiveArray::from_iter(values).into_array(),
750 &mut SESSION.create_execution_ctx(),
751 )
752 .unwrap()
753 })]
754 fn test_take_runend_conformance(#[case] array: RunEndArray) {
755 test_take_conformance(&array.into_array(), &mut SESSION.create_execution_ctx());
756 }
757
758 #[rstest]
759 #[case(ree_array().slice(3..6).unwrap())]
760 #[case({
761 let array = RunEnd::encode(
762 buffer![1i32, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3].into_array(),
763 &mut SESSION.create_execution_ctx(),
764 )
765 .unwrap();
766 array.slice(2..8).unwrap()
767 })]
768 fn test_take_sliced_runend_conformance(#[case] sliced: ArrayRef) {
769 test_take_conformance(&sliced, &mut SESSION.create_execution_ctx());
770 }
771}