vortex_array/arrays/primitive/array/
patch.rs1use vortex_dtype::IntegerPType;
5use vortex_dtype::NativePType;
6use vortex_dtype::UnsignedPType;
7use vortex_dtype::match_each_integer_ptype;
8use vortex_dtype::match_each_native_ptype;
9
10use crate::ToCanonical;
11use crate::arrays::PrimitiveArray;
12use crate::patches::Patches;
13use crate::validity::Validity;
14use crate::vtable::ValidityHelper;
15
16impl PrimitiveArray {
17 pub fn patch(self, patches: &Patches) -> Self {
18 let patch_indices = patches.indices().to_primitive();
19 let patch_values = patches.values().to_primitive();
20
21 let patched_validity = self.validity().clone().patch(
22 self.len(),
23 patches.offset(),
24 patch_indices.as_ref(),
25 patch_values.validity(),
26 );
27 match_each_integer_ptype!(patch_indices.ptype(), |I| {
28 match_each_native_ptype!(self.ptype(), |T| {
29 self.patch_typed::<T, I>(
30 patch_indices,
31 patches.offset(),
32 patch_values,
33 patched_validity,
34 )
35 })
36 })
37 }
38
39 fn patch_typed<T, I>(
40 self,
41 patch_indices: PrimitiveArray,
42 patch_indices_offset: usize,
43 patch_values: PrimitiveArray,
44 patched_validity: Validity,
45 ) -> Self
46 where
47 T: NativePType,
48 I: IntegerPType,
49 {
50 let mut own_values = self.into_buffer_mut::<T>();
51
52 let patch_indices = patch_indices.as_slice::<I>();
53 let patch_values = patch_values.as_slice::<T>();
54 for (idx, value) in itertools::zip_eq(patch_indices, patch_values) {
55 own_values[idx.as_() - patch_indices_offset] = *value;
56 }
57 Self::new(own_values, patched_validity)
58 }
59}
60
61#[inline]
74#[expect(
75 clippy::too_many_arguments,
76 reason = "all arguments are needed for the patching operation"
77)]
78pub fn patch_chunk<T, I, C>(
79 decoded_values: &mut [T],
80 patches_indices: &[I],
81 patches_values: &[T],
82 patches_offset: usize,
83 chunk_offsets_slice: &[C],
84 chunk_idx: usize,
85 base_offset: usize,
86 offset_within_chunk: usize,
87) where
88 T: NativePType,
89 I: UnsignedPType,
90 C: UnsignedPType,
91{
92 let patches_start_idx =
94 (chunk_offsets_slice[chunk_idx].as_() - base_offset).saturating_sub(offset_within_chunk);
95 let patches_end_idx = if chunk_idx + 1 < chunk_offsets_slice.len() {
96 chunk_offsets_slice[chunk_idx + 1].as_() - base_offset - offset_within_chunk
97 } else {
98 patches_indices.len()
99 };
100
101 let chunk_start = chunk_idx * 1024;
102 for patches_idx in patches_start_idx..patches_end_idx {
103 let patched_value = patches_values[patches_idx];
104 let absolute_index: usize = patches_indices[patches_idx].as_() - patches_offset;
105 let chunk_relative_index = absolute_index - chunk_start;
106 decoded_values[chunk_relative_index] = patched_value;
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use vortex_buffer::buffer;
113
114 use super::*;
115 use crate::ToCanonical;
116 use crate::validity::Validity;
117
118 #[test]
119 fn patch_sliced() {
120 let input = PrimitiveArray::new(buffer![2u32; 10], Validity::AllValid);
121 let sliced = input.slice(2..8);
122 assert_eq!(sliced.to_primitive().as_slice::<u32>(), &[2u32; 6]);
123 }
124}