Skip to content

Commit aa8f05f

Browse files
committed
implement append_to_builder for Patched
We call append_to_builder on the inner first, then just do a single pass and overwrite what it just wrote. Signed-off-by: Andrew Duffy <andrew@a10y.dev>
1 parent 8ebe6c6 commit aa8f05f

File tree

3 files changed

+147
-2
lines changed

3 files changed

+147
-2
lines changed

vortex-array/src/arrays/patched/compute/compare.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,7 @@ impl CompareKernel for Patched {
167167
}
168168
});
169169

170-
// SAFETY: thing
171-
let result = unsafe { BoolArray::new_unchecked(bits.freeze(), validity) };
170+
let result = BoolArray::new(bits.freeze(), validity);
172171
Ok(Some(result.into_array()))
173172
}
174173
}

vortex-array/src/arrays/patched/vtable/mod.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::hash::Hasher;
1010
use std::sync::Arc;
1111

1212
use vortex_buffer::Buffer;
13+
use vortex_error::VortexExpect;
1314
use vortex_error::VortexResult;
1415
use vortex_error::vortex_bail;
1516
use vortex_error::vortex_ensure;
@@ -34,6 +35,8 @@ use crate::arrays::patched::patch_lanes;
3435
use crate::arrays::patched::vtable::kernels::PARENT_KERNELS;
3536
use crate::arrays::primitive::PrimitiveArrayParts;
3637
use crate::buffer::BufferHandle;
38+
use crate::builders::ArrayBuilder;
39+
use crate::builders::PrimitiveBuilder;
3740
use crate::dtype::DType;
3841
use crate::dtype::NativePType;
3942
use crate::match_each_native_ptype;
@@ -169,6 +172,61 @@ impl VTable for Patched {
169172
Ok(ProstMetadata(inner))
170173
}
171174

175+
fn append_to_builder(
176+
array: &Self::Array,
177+
builder: &mut dyn ArrayBuilder,
178+
ctx: &mut ExecutionCtx,
179+
) -> VortexResult<()> {
180+
let dtype = array.dtype();
181+
182+
if !dtype.is_primitive() {
183+
// Default pathway: canonicalize and propagate.
184+
let canonical = array
185+
.clone()
186+
.into_array()
187+
.execute::<Canonical>(ctx)?
188+
.into_array();
189+
builder.extend_from_array(&canonical);
190+
return Ok(());
191+
}
192+
193+
let ptype = dtype.as_ptype();
194+
195+
let len = array.len();
196+
array.inner.append_to_builder(builder, ctx)?;
197+
198+
let offset = array.offset;
199+
let lane_offsets: Buffer<u32> =
200+
Buffer::from_byte_buffer(array.lane_offsets.clone().unwrap_host());
201+
let indices: Buffer<u16> = Buffer::from_byte_buffer(array.indices.clone().unwrap_host());
202+
let values = array.values.clone().execute::<PrimitiveArray>(ctx)?;
203+
204+
match_each_native_ptype!(ptype, |V| {
205+
let typed_builder = builder
206+
.as_any_mut()
207+
.downcast_mut::<PrimitiveBuilder<V>>()
208+
.vortex_expect("correctly typed builder");
209+
210+
// Overwrite the last `len` elements of the builder. These would have been
211+
// populated by the inner.append_to_builder() call above.
212+
let output = typed_builder.values_mut();
213+
let trailer = output.len() - len;
214+
215+
apply_patches_primitive::<V>(
216+
&mut output[trailer..],
217+
offset,
218+
len,
219+
array.n_chunks,
220+
array.n_lanes,
221+
&lane_offsets,
222+
&indices,
223+
values.as_slice::<V>(),
224+
);
225+
});
226+
227+
Ok(())
228+
}
229+
172230
fn build(
173231
dtype: &DType,
174232
len: usize,
@@ -320,9 +378,13 @@ mod tests {
320378
use crate::ExecutionCtx;
321379
use crate::IntoArray;
322380
use crate::arrays::PatchedArray;
381+
use crate::arrays::PrimitiveArray;
382+
use crate::assert_arrays_eq;
383+
use crate::builders::builder_with_capacity;
323384
use crate::dtype::Nullability;
324385
use crate::patches::Patches;
325386
use crate::scalar::Scalar;
387+
use crate::validity::Validity;
326388

327389
#[test]
328390
fn test_execute() {
@@ -393,4 +455,83 @@ mod tests {
393455
Scalar::primitive(1u16, Nullability::NonNullable)
394456
);
395457
}
458+
459+
#[test]
460+
fn test_append_to_builder_non_nullable() {
461+
let values = PrimitiveArray::new(buffer![0u16; 1024], Validity::NonNullable).into_array();
462+
let patches = Patches::new(
463+
1024,
464+
0,
465+
buffer![1u32, 2, 3].into_array(),
466+
buffer![10u16, 20, 30].into_array(),
467+
None,
468+
)
469+
.unwrap();
470+
471+
let session = VortexSession::empty();
472+
let mut ctx = ExecutionCtx::new(session);
473+
474+
let array = PatchedArray::from_array_and_patches(values, &patches, &mut ctx)
475+
.unwrap()
476+
.into_array();
477+
478+
let mut builder = builder_with_capacity(array.dtype(), array.len());
479+
array.append_to_builder(builder.as_mut(), &mut ctx).unwrap();
480+
481+
let result = builder.finish();
482+
483+
let mut expected = buffer_mut![0u16; 1024];
484+
expected[1] = 10;
485+
expected[2] = 20;
486+
expected[3] = 30;
487+
let expected = expected.into_array();
488+
489+
assert_arrays_eq!(expected, result);
490+
}
491+
492+
#[test]
493+
fn test_append_to_builder_with_validity() {
494+
// Create inner array with nulls at indices 0 and 5.
495+
let validity = Validity::from_iter((0..10).map(|i| i != 0 && i != 5));
496+
let values = PrimitiveArray::new(buffer![0u16; 10], validity).into_array();
497+
498+
// Apply patches at indices 1, 2, 3.
499+
let patches = Patches::new(
500+
10,
501+
0,
502+
buffer![1u32, 2, 3].into_array(),
503+
buffer![10u16, 20, 30].into_array(),
504+
None,
505+
)
506+
.unwrap();
507+
508+
let session = VortexSession::empty();
509+
let mut ctx = ExecutionCtx::new(session);
510+
511+
let array = PatchedArray::from_array_and_patches(values, &patches, &mut ctx)
512+
.unwrap()
513+
.into_array();
514+
515+
let mut builder = builder_with_capacity(array.dtype(), array.len());
516+
array.append_to_builder(builder.as_mut(), &mut ctx).unwrap();
517+
518+
let result = builder.finish();
519+
520+
// Expected: null at 0, patched 10/20/30 at 1/2/3, zero at 4, null at 5, zeros at 6-9.
521+
let expected = PrimitiveArray::from_option_iter([
522+
None,
523+
Some(10u16),
524+
Some(20),
525+
Some(30),
526+
Some(0),
527+
None,
528+
Some(0),
529+
Some(0),
530+
Some(0),
531+
Some(0),
532+
])
533+
.into_array();
534+
535+
assert_arrays_eq!(expected, result);
536+
}
396537
}

vortex-array/src/builders/primitive.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ impl<T: NativePType> PrimitiveBuilder<T> {
6262
self.values.as_ref()
6363
}
6464

65+
/// Returns the raw primitive values in this builder as a mutable slice.
66+
pub fn values_mut(&mut self) -> &mut [T] {
67+
self.values.as_mut()
68+
}
69+
6570
/// Create a new handle to the next `len` uninitialized values in the builder.
6671
///
6772
/// All reads/writes through the handle to the values buffer or the validity buffer will operate

0 commit comments

Comments
 (0)