vortex_array/arrays/varbin/compute/
take.rs1use num_traits::PrimInt;
2use vortex_dtype::{DType, NativePType, match_each_integer_ptype};
3use vortex_error::{VortexResult, vortex_err, vortex_panic};
4use vortex_mask::Mask;
5
6use crate::arrays::VarBinVTable;
7use crate::arrays::varbin::VarBinArray;
8use crate::arrays::varbin::builder::VarBinBuilder;
9use crate::compute::{TakeKernel, TakeKernelAdapter};
10use crate::{Array, ArrayRef, IntoArray, ToCanonical, register_kernel};
11
12impl TakeKernel for VarBinVTable {
13 fn take(&self, array: &VarBinArray, indices: &dyn Array) -> VortexResult<ArrayRef> {
14 let offsets = array.offsets().to_primitive()?;
15 let data = array.bytes();
16 let indices = indices.to_primitive()?;
17 match_each_integer_ptype!(offsets.ptype(), |O| {
18 match_each_integer_ptype!(indices.ptype(), |I| {
19 Ok(take(
20 array
21 .dtype()
22 .clone()
23 .union_nullability(indices.dtype().nullability()),
24 offsets.as_slice::<O>(),
25 data.as_slice(),
26 indices.as_slice::<I>(),
27 array.validity_mask()?,
28 indices.validity_mask()?,
29 )?
30 .into_array())
31 })
32 })
33 }
34}
35
36register_kernel!(TakeKernelAdapter(VarBinVTable).lift());
37
38fn take<I: NativePType, O: NativePType + PrimInt>(
39 dtype: DType,
40 offsets: &[O],
41 data: &[u8],
42 indices: &[I],
43 validity_mask: Mask,
44 indices_validity_mask: Mask,
45) -> VortexResult<VarBinArray> {
46 if !validity_mask.all_true() || !indices_validity_mask.all_true() {
47 return Ok(take_nullable(
48 dtype,
49 offsets,
50 data,
51 indices,
52 validity_mask,
53 indices_validity_mask,
54 ));
55 }
56
57 let mut builder = VarBinBuilder::<O>::with_capacity(indices.len());
58 for &idx in indices {
59 let idx = idx
60 .to_usize()
61 .ok_or_else(|| vortex_err!("Failed to convert index to usize: {}", idx))?;
62 let start = offsets[idx]
63 .to_usize()
64 .ok_or_else(|| vortex_err!("Failed to convert offset to usize: {}", offsets[idx]))?;
65 let stop = offsets[idx + 1].to_usize().ok_or_else(|| {
66 vortex_err!("Failed to convert offset to usize: {}", offsets[idx + 1])
67 })?;
68 builder.append_value(&data[start..stop]);
69 }
70 Ok(builder.finish(dtype))
71}
72
73fn take_nullable<I: NativePType, O: NativePType + PrimInt>(
74 dtype: DType,
75 offsets: &[O],
76 data: &[u8],
77 indices: &[I],
78 data_validity: Mask,
79 indices_validity: Mask,
80) -> VarBinArray {
81 let mut builder = VarBinBuilder::<O>::with_capacity(indices.len());
82 for (idx, data_idx) in indices.iter().enumerate() {
83 if !indices_validity.value(idx) {
84 builder.append_null();
85 continue;
86 }
87 let data_idx = data_idx
88 .to_usize()
89 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", data_idx));
90 if data_validity.value(data_idx) {
91 let start = offsets[data_idx].to_usize().unwrap_or_else(|| {
92 vortex_panic!("Failed to convert offset to usize: {}", offsets[data_idx])
93 });
94 let stop = offsets[data_idx + 1].to_usize().unwrap_or_else(|| {
95 vortex_panic!(
96 "Failed to convert offset to usize: {}",
97 offsets[data_idx + 1]
98 )
99 });
100 builder.append_value(&data[start..stop]);
101 } else {
102 builder.append_null();
103 }
104 }
105 builder.finish(dtype)
106}
107
108#[cfg(test)]
109mod tests {
110 use vortex_dtype::{DType, Nullability};
111
112 use crate::Array;
113 use crate::arrays::{PrimitiveArray, VarBinArray};
114 use crate::compute::take;
115
116 #[test]
117 fn test_null_take() {
118 let arr = VarBinArray::from_iter([Some("h")], DType::Utf8(Nullability::NonNullable));
119
120 let idx1: PrimitiveArray = (0..1).collect();
121
122 assert_eq!(
123 take(arr.as_ref(), idx1.as_ref()).unwrap().dtype(),
124 &DType::Utf8(Nullability::NonNullable)
125 );
126
127 let idx2: PrimitiveArray = PrimitiveArray::from_option_iter(vec![Some(0)]);
128
129 assert_eq!(
130 take(arr.as_ref(), idx2.as_ref()).unwrap().dtype(),
131 &DType::Utf8(Nullability::Nullable)
132 );
133 }
134}