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