diff --git a/vortex-array/public-api.lock b/vortex-array/public-api.lock index c193f10da92..9918692205c 100644 --- a/vortex-array/public-api.lock +++ b/vortex-array/public-api.lock @@ -3364,7 +3364,7 @@ pub fn vortex_array::arrays::patched::Patched::deserialize(bytes: &[u8], _dtype: pub fn vortex_array::arrays::patched::Patched::dtype(array: &Self::Array) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::patched::Patched::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -3416,6 +3416,10 @@ pub fn vortex_array::arrays::patched::PatchedArray::from_array_and_patches(inner impl vortex_array::arrays::patched::PatchedArray +pub fn vortex_array::arrays::patched::PatchedArray::into_parts(self) -> vortex_array::arrays::patched::PatchedArrayParts + +impl vortex_array::arrays::patched::PatchedArray + pub fn vortex_array::arrays::patched::PatchedArray::to_array(&self) -> vortex_array::ArrayRef impl core::clone::Clone for vortex_array::arrays::patched::PatchedArray @@ -3444,6 +3448,22 @@ impl vortex_array::IntoArray for vortex_array::arrays::patched::PatchedArray pub fn vortex_array::arrays::patched::PatchedArray::into_array(self) -> vortex_array::ArrayRef +pub struct vortex_array::arrays::patched::PatchedArrayParts + +pub vortex_array::arrays::patched::PatchedArrayParts::indices: vortex_array::ArrayRef + +pub vortex_array::arrays::patched::PatchedArrayParts::inner: vortex_array::ArrayRef + +pub vortex_array::arrays::patched::PatchedArrayParts::lane_offsets: vortex_array::ArrayRef + +pub vortex_array::arrays::patched::PatchedArrayParts::len: usize + +pub vortex_array::arrays::patched::PatchedArrayParts::n_lanes: usize + +pub vortex_array::arrays::patched::PatchedArrayParts::offset: usize + +pub vortex_array::arrays::patched::PatchedArrayParts::values: vortex_array::ArrayRef + pub struct vortex_array::arrays::patched::PatchedMetadata impl core::clone::Clone for vortex_array::arrays::patched::PatchedMetadata @@ -4148,7 +4168,7 @@ pub fn vortex_array::arrays::slice::Slice::deserialize(_bytes: &[u8], _dtype: &v pub fn vortex_array::arrays::slice::Slice::dtype(array: &vortex_array::arrays::slice::SliceArray) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::slice::Slice::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -7332,7 +7352,7 @@ pub fn vortex_array::arrays::patched::Patched::deserialize(bytes: &[u8], _dtype: pub fn vortex_array::arrays::patched::Patched::dtype(array: &Self::Array) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::patched::Patched::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -7384,6 +7404,10 @@ pub fn vortex_array::arrays::patched::PatchedArray::from_array_and_patches(inner impl vortex_array::arrays::patched::PatchedArray +pub fn vortex_array::arrays::patched::PatchedArray::into_parts(self) -> vortex_array::arrays::patched::PatchedArrayParts + +impl vortex_array::arrays::patched::PatchedArray + pub fn vortex_array::arrays::patched::PatchedArray::to_array(&self) -> vortex_array::ArrayRef impl core::clone::Clone for vortex_array::arrays::patched::PatchedArray @@ -7942,7 +7966,7 @@ pub fn vortex_array::arrays::slice::Slice::deserialize(_bytes: &[u8], _dtype: &v pub fn vortex_array::arrays::slice::Slice::dtype(array: &vortex_array::arrays::slice::SliceArray) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::slice::Slice::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -22324,7 +22348,7 @@ pub fn vortex_array::arrays::patched::Patched::deserialize(bytes: &[u8], _dtype: pub fn vortex_array::arrays::patched::Patched::dtype(array: &Self::Array) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::patched::Patched::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -22444,7 +22468,7 @@ pub fn vortex_array::arrays::slice::Slice::deserialize(_bytes: &[u8], _dtype: &v pub fn vortex_array::arrays::slice::Slice::dtype(array: &vortex_array::arrays::slice::SliceArray) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::slice::Slice::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -23768,7 +23792,7 @@ pub fn vortex_array::arrays::patched::Patched::deserialize(bytes: &[u8], _dtype: pub fn vortex_array::arrays::patched::Patched::dtype(array: &Self::Array) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::patched::Patched::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::patched::Patched::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -23888,7 +23912,7 @@ pub fn vortex_array::arrays::slice::Slice::deserialize(_bytes: &[u8], _dtype: &v pub fn vortex_array::arrays::slice::Slice::dtype(array: &vortex_array::arrays::slice::SliceArray) -> &vortex_array::dtype::DType -pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::slice::Slice::execute(array: alloc::sync::Arc>, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::arrays::slice::Slice::execute_parent(array: &vortex_array::vtable::Array, parent: &vortex_array::ArrayRef, child_idx: usize, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> diff --git a/vortex-array/src/arrays/chunked/vtable/canonical.rs b/vortex-array/src/arrays/chunked/vtable/canonical.rs index 05b8bdfd42b..4a34fd9f922 100644 --- a/vortex-array/src/arrays/chunked/vtable/canonical.rs +++ b/vortex-array/src/arrays/chunked/vtable/canonical.rs @@ -10,8 +10,10 @@ use crate::Canonical; use crate::DynArray; use crate::ExecutionCtx; use crate::IntoArray; +use crate::arrays::ListView; use crate::arrays::ListViewArray; use crate::arrays::PrimitiveArray; +use crate::arrays::Struct; use crate::arrays::StructArray; use crate::arrays::chunked::vtable::ChunkedArray; use crate::arrays::listview::ListViewRebuildMode; @@ -41,7 +43,6 @@ pub(super) fn _canonicalize( &owned_chunks, Validity::copy_from_array(&array.clone().into_array())?, struct_dtype, - ctx, )?; Canonical::Struct(struct_array) } @@ -62,24 +63,22 @@ pub(super) fn _canonicalize( /// Packs many [`StructArray`]s to instead be a single [`StructArray`], where the [`DynArray`] for each /// field is a [`ChunkedArray`]. /// -/// The caller guarantees there are at least 2 chunks. +/// The caller guarantees there are at least 2 chunks, and that all chunks are already +/// canonicalized to [`StructArray`] by iterative execution. fn pack_struct_chunks( chunks: &[ArrayRef], validity: Validity, struct_dtype: &StructFields, - ctx: &mut ExecutionCtx, ) -> VortexResult { let len = chunks.iter().map(|chunk| chunk.len()).sum(); let mut field_arrays = Vec::new(); - let executed_chunks: Vec = chunks - .iter() - .map(|c| c.clone().execute::(ctx)) - .collect::>()?; - for (field_idx, field_dtype) in struct_dtype.fields().enumerate() { let mut field_chunks = Vec::with_capacity(chunks.len()); - for struct_array in &executed_chunks { + for chunk in chunks { + let struct_array = chunk + .as_opt::() + .vortex_expect("struct chunk pre-canonicalized by iterative execution"); let field = struct_array.unmasked_field(field_idx).to_array(); field_chunks.push(field); } @@ -99,7 +98,8 @@ fn pack_struct_chunks( /// /// We use the existing arrays (chunks) to form a chunked array of `elements` (the child array). /// -/// The caller guarantees there are at least 2 chunks. +/// The caller guarantees there are at least 2 chunks, and that all chunks are already +/// canonicalized to [`ListViewArray`] by iterative execution. fn swizzle_list_chunks( chunks: &[ArrayRef], validity: Validity, @@ -131,7 +131,9 @@ fn swizzle_list_chunks( let mut sizes = BufferMut::::with_capacity(len); for chunk in chunks { - let chunk_array = chunk.clone().execute::(ctx)?; + let chunk_array = chunk + .as_opt::() + .vortex_expect("list chunk pre-canonicalized by iterative execution"); // By rebuilding as zero-copy to `List` and trimming all elements (to prevent gaps), we make // the final output `ListView` also zero-copyable to `List`. let chunk_array = chunk_array.rebuild(ListViewRebuildMode::MakeExact)?; diff --git a/vortex-array/src/arrays/chunked/vtable/mod.rs b/vortex-array/src/arrays/chunked/vtable/mod.rs index e110d2542cf..e28a1d2cc12 100644 --- a/vortex-array/src/arrays/chunked/vtable/mod.rs +++ b/vortex-array/src/arrays/chunked/vtable/mod.rs @@ -12,6 +12,7 @@ use vortex_error::vortex_err; use vortex_error::vortex_panic; use vortex_session::VortexSession; +use crate::AnyCanonical; use crate::ArrayRef; use crate::Canonical; use crate::EmptyMetadata; @@ -202,6 +203,16 @@ impl VTable for Chunked { } fn execute(array: Arc>, ctx: &mut ExecutionCtx) -> VortexResult { + // Iteratively request execution of each chunk until it reaches canonical form. + // This gives the scheduler visibility into child execution and enables + // cross-step optimizations between chunk decoding steps. + for i in 0..array.nchunks() { + if !array.chunk(i).is::() { + return Ok(ExecutionResult::execute_slot::(array, i + 1)); + } + } + + // All chunks are now canonical — combine them. Ok(ExecutionResult::done( _canonicalize(&array, ctx)?.into_array(), )) diff --git a/vortex-array/src/arrays/filter/vtable.rs b/vortex-array/src/arrays/filter/vtable.rs index 618908b7301..3d11b59f95d 100644 --- a/vortex-array/src/arrays/filter/vtable.rs +++ b/vortex-array/src/arrays/filter/vtable.rs @@ -13,12 +13,14 @@ use vortex_error::vortex_panic; use vortex_mask::Mask; use vortex_session::VortexSession; +use crate::AnyCanonical; use crate::ArrayEq; use crate::ArrayHash; use crate::ArrayRef; use crate::DynArray; use crate::IntoArray; use crate::Precision; +use crate::arrays::filter::array::CHILD_SLOT; use crate::arrays::filter::array::FilterArray; use crate::arrays::filter::array::NUM_SLOTS; use crate::arrays::filter::array::SLOT_NAMES; @@ -30,6 +32,7 @@ use crate::buffer::BufferHandle; use crate::dtype::DType; use crate::executor::ExecutionCtx; use crate::executor::ExecutionResult; +use crate::require_child; use crate::scalar::Scalar; use crate::serde::ArrayChildren; use crate::stats::StatsSetRef; @@ -151,14 +154,18 @@ impl VTable for Filter { if let Some(canonical) = execute_filter_fast_paths(&array, ctx)? { return Ok(ExecutionResult::done(canonical)); } + + let array = require_child!(array, array.child(), CHILD_SLOT => AnyCanonical); + let Mask::Values(mask_values) = &array.mask else { unreachable!("`execute_filter_fast_paths` handles AllTrue and AllFalse") }; - // We rely on the optimization pass that runs prior to this execution for filter pushdown, - // so now we can just execute the filter without worrying. + // Child is pre-canonicalized — apply the filter directly. + debug_assert!(array.child().is_canonical()); + let child = array.child().to_canonical()?; Ok(ExecutionResult::done( - execute_filter(array.child().clone().execute(ctx)?, mask_values).into_array(), + execute_filter(child, mask_values).into_array(), )) } diff --git a/vortex-array/src/arrays/list/vtable/mod.rs b/vortex-array/src/arrays/list/vtable/mod.rs index 114579a4bab..17cc080dae9 100644 --- a/vortex-array/src/arrays/list/vtable/mod.rs +++ b/vortex-array/src/arrays/list/vtable/mod.rs @@ -18,7 +18,9 @@ use crate::IntoArray; use crate::Precision; use crate::ProstMetadata; use crate::arrays::ListArray; +use crate::arrays::Primitive; use crate::arrays::list::array::NUM_SLOTS; +use crate::arrays::list::array::OFFSETS_SLOT; use crate::arrays::list::array::SLOT_NAMES; use crate::arrays::list::array::VALIDITY_SLOT; use crate::arrays::list::compute::PARENT_KERNELS; @@ -32,6 +34,7 @@ use crate::hash::ArrayEq; use crate::hash::ArrayHash; use crate::metadata::DeserializeMetadata; use crate::metadata::SerializeMetadata; +use crate::require_child; use crate::serde::ArrayChildren; use crate::stats::StatsSetRef; use crate::validity::Validity; @@ -193,6 +196,7 @@ impl VTable for List { } fn execute(array: Arc>, ctx: &mut ExecutionCtx) -> VortexResult { + let array = require_child!(array, array.offsets(), OFFSETS_SLOT => Primitive); Ok(ExecutionResult::done( list_view_from_list(ListArray::clone(&array), ctx)?.into_array(), )) diff --git a/vortex-array/src/arrays/masked/vtable/mod.rs b/vortex-array/src/arrays/masked/vtable/mod.rs index 3b8b3b792f8..c929fbcb3a0 100644 --- a/vortex-array/src/arrays/masked/vtable/mod.rs +++ b/vortex-array/src/arrays/masked/vtable/mod.rs @@ -13,13 +13,14 @@ use vortex_error::vortex_ensure; use vortex_error::vortex_panic; use vortex_session::VortexSession; +use crate::AnyCanonical; use crate::ArrayRef; -use crate::Canonical; use crate::EmptyMetadata; use crate::IntoArray; use crate::Precision; use crate::arrays::ConstantArray; use crate::arrays::MaskedArray; +use crate::arrays::masked::array::CHILD_SLOT; use crate::arrays::masked::array::NUM_SLOTS; use crate::arrays::masked::array::SLOT_NAMES; use crate::arrays::masked::compute::rules::PARENT_RULES; @@ -30,6 +31,7 @@ use crate::executor::ExecutionCtx; use crate::executor::ExecutionResult; use crate::hash::ArrayEq; use crate::hash::ArrayHash; +use crate::require_child; use crate::scalar::Scalar; use crate::serde::ArrayChildren; use crate::stats::StatsSetRef; @@ -162,7 +164,10 @@ impl VTable for Masked { // While we could manually convert the dtype, `mask_validity_canonical` is already O(1) for // `AllTrue` masks (no data copying), so there's no benefit. - let child = array.child().clone().execute::(ctx)?; + let array = require_child!(array, array.child(), CHILD_SLOT => AnyCanonical); + + debug_assert!(array.child().is_canonical()); + let child = array.child().to_canonical()?; Ok(ExecutionResult::done( mask_validity_canonical(child, &validity_mask, ctx)?.into_array(), )) diff --git a/vortex-array/src/arrays/patched/array.rs b/vortex-array/src/arrays/patched/array.rs index 6a7b9a28e21..ff19af319d7 100644 --- a/vortex-array/src/arrays/patched/array.rs +++ b/vortex-array/src/arrays/patched/array.rs @@ -205,6 +205,47 @@ impl PatchedArray { } } +/// The owned parts of a [`PatchedArray`], produced by [`PatchedArray::into_parts`]. +pub struct PatchedArrayParts { + /// The inner array being patched. + pub inner: ArrayRef, + /// The lane offsets array (u32). + pub lane_offsets: ArrayRef, + /// The patch indices array (u16). + pub indices: ArrayRef, + /// The patch values array. + pub values: ArrayRef, + /// Number of lanes. + pub n_lanes: usize, + /// Offset into the first chunk. + pub offset: usize, + /// Logical length. + pub len: usize, +} + +impl PatchedArray { + /// Consume this array into its owned parts. + pub fn into_parts(mut self) -> PatchedArrayParts { + PatchedArrayParts { + inner: self.slots[INNER_SLOT] + .take() + .vortex_expect("PatchedArray inner slot"), + lane_offsets: self.slots[LANE_OFFSETS_SLOT] + .take() + .vortex_expect("PatchedArray lane_offsets slot"), + indices: self.slots[INDICES_SLOT] + .take() + .vortex_expect("PatchedArray indices slot"), + values: self.slots[VALUES_SLOT] + .take() + .vortex_expect("PatchedArray values slot"), + n_lanes: self.n_lanes, + offset: self.offset, + len: self.len, + } + } +} + impl PatchedArray { /// Returns a reference to the base array being patched. #[inline] diff --git a/vortex-array/src/arrays/patched/vtable/mod.rs b/vortex-array/src/arrays/patched/vtable/mod.rs index e015af1b352..c406f922b84 100644 --- a/vortex-array/src/arrays/patched/vtable/mod.rs +++ b/vortex-array/src/arrays/patched/vtable/mod.rs @@ -28,10 +28,16 @@ use crate::IntoArray; use crate::Precision; use crate::ProstMetadata; use crate::SerializeMetadata; +use crate::arrays::Primitive; use crate::arrays::PrimitiveArray; use crate::arrays::patched::PatchedArray; +use crate::arrays::patched::PatchedArrayParts; +use crate::arrays::patched::array::INDICES_SLOT; +use crate::arrays::patched::array::INNER_SLOT; +use crate::arrays::patched::array::LANE_OFFSETS_SLOT; use crate::arrays::patched::array::NUM_SLOTS; use crate::arrays::patched::array::SLOT_NAMES; +use crate::arrays::patched::array::VALUES_SLOT; use crate::arrays::patched::compute::rules::PARENT_RULES; use crate::arrays::patched::vtable::kernels::PARENT_KERNELS; use crate::arrays::primitive::PrimitiveArrayParts; @@ -42,6 +48,7 @@ use crate::dtype::DType; use crate::dtype::NativePType; use crate::dtype::PType; use crate::match_each_native_ptype; +use crate::require_child; use crate::serde::ArrayChildren; use crate::stats::ArrayStats; use crate::stats::StatsSetRef; @@ -288,12 +295,38 @@ impl VTable for Patched { Ok(()) } - fn execute(array: Arc>, ctx: &mut ExecutionCtx) -> VortexResult { - let inner = array - .base_array() - .clone() - .execute::(ctx)? - .into_primitive(); + fn execute(array: Arc>, _ctx: &mut ExecutionCtx) -> VortexResult { + let array = require_child!(array, array.base_array(), INNER_SLOT => Primitive); + let array = require_child!(array, array.lane_offsets(), LANE_OFFSETS_SLOT => Primitive); + let array = require_child!(array, array.patch_indices(), INDICES_SLOT => Primitive); + let array = require_child!(array, array.patch_values(), VALUES_SLOT => Primitive); + + let PatchedArrayParts { + inner, + lane_offsets, + indices, + values, + n_lanes, + offset, + len, + } = Arc::unwrap_or_clone(array).into_inner().into_parts(); + + let inner = inner + .try_into::() + .ok() + .vortex_expect("base_array pre-canonicalized to Primitive"); + let lane_offsets = lane_offsets + .try_into::() + .ok() + .vortex_expect("lane_offsets pre-canonicalized to Primitive"); + let indices = indices + .try_into::() + .ok() + .vortex_expect("patch_indices pre-canonicalized to Primitive"); + let values = values + .try_into::() + .ok() + .vortex_expect("patch_values pre-canonicalized to Primitive"); let PrimitiveArrayParts { buffer, @@ -301,32 +334,14 @@ impl VTable for Patched { validity, } = inner.into_parts(); - let lane_offsets = array - .lane_offsets() - .clone() - .execute::(ctx)?; - let indices = array - .patch_indices() - .clone() - .execute::(ctx)?; - - // TODO(aduffy): add support for non-primitive PatchedArray patches application (?) - let values = array - .patch_values() - .clone() - .execute::(ctx)?; - let patched_values = match_each_native_ptype!(values.ptype(), |V| { - let offset = array.offset; - let len = array.len; - let mut output = Buffer::::from_byte_buffer(buffer.unwrap_host()).into_mut(); apply_patches_primitive::( &mut output, offset, len, - array.n_lanes, + n_lanes, lane_offsets.as_slice::(), indices.as_slice::(), values.as_slice::(), diff --git a/vortex-array/src/arrays/slice/vtable.rs b/vortex-array/src/arrays/slice/vtable.rs index 01aba68bd46..9dcdc802cbf 100644 --- a/vortex-array/src/arrays/slice/vtable.rs +++ b/vortex-array/src/arrays/slice/vtable.rs @@ -18,9 +18,9 @@ use crate::AnyCanonical; use crate::ArrayEq; use crate::ArrayHash; use crate::ArrayRef; -use crate::Canonical; use crate::DynArray; use crate::Precision; +use crate::arrays::slice::array::CHILD_SLOT; use crate::arrays::slice::array::NUM_SLOTS; use crate::arrays::slice::array::SLOT_NAMES; use crate::arrays::slice::array::SliceArray; @@ -29,6 +29,7 @@ use crate::buffer::BufferHandle; use crate::dtype::DType; use crate::executor::ExecutionCtx; use crate::executor::ExecutionResult; +use crate::require_child; use crate::scalar::Scalar; use crate::serde::ArrayChildren; use crate::stats::StatsSetRef; @@ -146,20 +147,15 @@ impl VTable for Slice { Ok(()) } - fn execute(array: Arc>, ctx: &mut ExecutionCtx) -> VortexResult { - // Execute the child to get canonical form, then slice it - let Some(canonical) = array.child().as_opt::() else { - // If the child is not canonical, recurse. - return array - .child() - .clone() - .execute::(ctx)? - .slice(array.slice_range().clone()) - .map(ExecutionResult::done); - }; + fn execute(array: Arc>, _ctx: &mut ExecutionCtx) -> VortexResult { + let array = require_child!(array, array.child(), CHILD_SLOT => AnyCanonical); + // Child is now canonical — slice it. // TODO(ngates): we should inline canonical slice logic here. - Canonical::from(canonical) + debug_assert!(array.child().is_canonical()); + array + .child() + .to_canonical()? .as_ref() .slice(array.range.clone()) .map(ExecutionResult::done) diff --git a/vortex-array/src/arrays/varbin/vtable/mod.rs b/vortex-array/src/arrays/varbin/vtable/mod.rs index 0ed565a2587..3d84f6374f9 100644 --- a/vortex-array/src/arrays/varbin/vtable/mod.rs +++ b/vortex-array/src/arrays/varbin/vtable/mod.rs @@ -16,13 +16,16 @@ use crate::ExecutionResult; use crate::IntoArray; use crate::ProstMetadata; use crate::SerializeMetadata; +use crate::arrays::Primitive; use crate::arrays::VarBinArray; use crate::arrays::varbin::array::NUM_SLOTS; +use crate::arrays::varbin::array::OFFSETS_SLOT; use crate::arrays::varbin::array::SLOT_NAMES; use crate::buffer::BufferHandle; use crate::dtype::DType; use crate::dtype::Nullability; use crate::dtype::PType; +use crate::require_child; use crate::serde::ArrayChildren; use crate::validity::Validity; use crate::vtable; @@ -201,6 +204,7 @@ impl VTable for VarBin { } fn execute(array: Arc>, ctx: &mut ExecutionCtx) -> VortexResult { + let array = require_child!(array, array.offsets(), OFFSETS_SLOT => Primitive); Ok(ExecutionResult::done( varbin_to_canonical(&array, ctx)?.into_array(), )) diff --git a/vortex-array/src/vtable/dyn_.rs b/vortex-array/src/vtable/dyn_.rs index 67fd8d529cf..9df01693efb 100644 --- a/vortex-array/src/vtable/dyn_.rs +++ b/vortex-array/src/vtable/dyn_.rs @@ -35,6 +35,8 @@ pub type DynVTableRef = Arc; /// [`DynArray`] trait API to a minimum. pub trait DynVTable: 'static + Send + Sync + Debug { /// Clone this vtable into a `Box`. + /// + /// Note: This only allocates if the underlying VTable is not a zero-size type (zst). fn clone_boxed(&self) -> Box; #[allow(clippy::too_many_arguments)]