From f3c7593f2f5d1f19eaf1dc44a0d15f63cd5c5271 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 17 May 2026 22:24:16 +0000 Subject: [PATCH] RowSizeKernel and RowEncodeKernel dispatch helpers Wire per-encoding fast-path traits into `dispatch_size` and `dispatch_encode`. Both helpers now try the in-crate downcast arms (Constant, Dict, Patched) before falling back to canonicalization. This commit adds stub impls returning `Ok(None)` so the existing behavior is preserved bit-for-bit; subsequent commits replace each stub with its real impl. Keeping the wiring change separate from the algorithm work makes the kernel impl commits trivially reviewable in isolation (they only touch one file each). The kernel module is `mod kernels` (crate-private) so the impls satisfy the orphan rule (trait defined in `vortex-row`, types from `vortex-array`) without leaking the impls into the crate's public surface. Signed-off-by: Claude --- vortex-row/public-api.lock | 48 ++++++++++++++++++++++++++++++ vortex-row/src/encode.rs | 23 ++++++++++++-- vortex-row/src/kernels/constant.rs | 40 +++++++++++++++++++++++++ vortex-row/src/kernels/dict.rs | 40 +++++++++++++++++++++++++ vortex-row/src/kernels/mod.rs | 17 +++++++++++ vortex-row/src/kernels/patched.rs | 40 +++++++++++++++++++++++++ vortex-row/src/lib.rs | 1 + vortex-row/src/size.rs | 24 +++++++++++++-- 8 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 vortex-row/src/kernels/constant.rs create mode 100644 vortex-row/src/kernels/dict.rs create mode 100644 vortex-row/src/kernels/mod.rs create mode 100644 vortex-row/src/kernels/patched.rs diff --git a/vortex-row/public-api.lock b/vortex-row/public-api.lock index ed231a1e556..a7221cd91ee 100644 --- a/vortex-row/public-api.lock +++ b/vortex-row/public-api.lock @@ -146,6 +146,18 @@ pub trait vortex_row::encode::RowEncodeKernel: vortex_array::array::vtable::VTab pub fn vortex_row::encode::RowEncodeKernel::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> +impl vortex_row::encode::RowEncodeKernel for vortex_array::arrays::constant::vtable::Constant + +pub fn vortex_array::arrays::constant::vtable::Constant::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::encode::RowEncodeKernel for vortex_array::arrays::dict::vtable::Dict + +pub fn vortex_array::arrays::dict::vtable::Dict::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::encode::RowEncodeKernel for vortex_array::arrays::patched::vtable::Patched + +pub fn vortex_array::arrays::patched::vtable::Patched::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + pub fn vortex_row::encode::dispatch_encode(&vortex_array::array::erased::ArrayRef, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult<()> pub mod vortex_row::options @@ -266,6 +278,18 @@ pub trait vortex_row::size::RowSizeKernel: vortex_array::array::vtable::VTable pub fn vortex_row::size::RowSizeKernel::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> +impl vortex_row::size::RowSizeKernel for vortex_array::arrays::constant::vtable::Constant + +pub fn vortex_array::arrays::constant::vtable::Constant::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::size::RowSizeKernel for vortex_array::arrays::dict::vtable::Dict + +pub fn vortex_array::arrays::dict::vtable::Dict::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::size::RowSizeKernel for vortex_array::arrays::patched::vtable::Patched + +pub fn vortex_array::arrays::patched::vtable::Patched::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + pub fn vortex_row::size::dispatch_size(&vortex_array::array::erased::ArrayRef, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult<()> pub struct vortex_row::RowEncode @@ -412,10 +436,34 @@ pub trait vortex_row::RowEncodeKernel: vortex_array::array::vtable::VTable pub fn vortex_row::RowEncodeKernel::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> +impl vortex_row::encode::RowEncodeKernel for vortex_array::arrays::constant::vtable::Constant + +pub fn vortex_array::arrays::constant::vtable::Constant::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::encode::RowEncodeKernel for vortex_array::arrays::dict::vtable::Dict + +pub fn vortex_array::arrays::dict::vtable::Dict::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::encode::RowEncodeKernel for vortex_array::arrays::patched::vtable::Patched + +pub fn vortex_array::arrays::patched::vtable::Patched::row_encode_into(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &[u32], &mut [u32], &mut [u8], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + pub trait vortex_row::RowSizeKernel: vortex_array::array::vtable::VTable pub fn vortex_row::RowSizeKernel::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> +impl vortex_row::size::RowSizeKernel for vortex_array::arrays::constant::vtable::Constant + +pub fn vortex_array::arrays::constant::vtable::Constant::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::size::RowSizeKernel for vortex_array::arrays::dict::vtable::Dict + +pub fn vortex_array::arrays::dict::vtable::Dict::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + +impl vortex_row::size::RowSizeKernel for vortex_array::arrays::patched::vtable::Patched + +pub fn vortex_array::arrays::patched::vtable::Patched::row_size_contribution(vortex_array::array::view::ArrayView<'_, Self>, vortex_row::options::SortField, &mut [u32], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> + pub fn vortex_row::compute_row_sizes(&[vortex_array::array::erased::ArrayRef], &[vortex_row::options::SortField], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_row::convert_columns(&[vortex_array::array::erased::ArrayRef], &[vortex_row::options::SortField], &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult diff --git a/vortex-row/src/encode.rs b/vortex-row/src/encode.rs index 1ca24ec378c..7510b78bc9f 100644 --- a/vortex-row/src/encode.rs +++ b/vortex-row/src/encode.rs @@ -25,6 +25,8 @@ use vortex_array::arrays::Constant; use vortex_array::arrays::ListViewArray; use vortex_array::arrays::Primitive; use vortex_array::arrays::PrimitiveArray; +use vortex_array::arrays::dict::Dict; +use vortex_array::arrays::patched::Patched; use vortex_array::dtype::DType; use vortex_array::dtype::Nullability; use vortex_array::dtype::PType; @@ -462,9 +464,9 @@ fn encode_constant_arith( /// Dispatch a single column's encoding into the shared `out` buffer. /// -/// For PR 1 this is just the canonicalize-then-`codec::field_encode` fallback path. -/// In-crate fast paths for `Constant`/`Dict`/`Patched` and the inventory-based registry -/// for downstream encodings are added in PR 3. +/// Tries the in-crate per-encoding fast paths first, then falls back to canonicalization. +/// Per-encoding kernels currently return `Ok(None)` (stubs added alongside the trait); the +/// real impls land in follow-up commits. The downstream-encoding registry is added next. pub fn dispatch_encode( col: &ArrayRef, field: SortField, @@ -473,6 +475,21 @@ pub fn dispatch_encode( out: &mut [u8], ctx: &mut ExecutionCtx, ) -> VortexResult<()> { + if let Some(view) = col.as_opt::() + && Constant::row_encode_into(view, field, offsets, cursors, out, ctx)?.is_some() + { + return Ok(()); + } + if let Some(view) = col.as_opt::() + && Dict::row_encode_into(view, field, offsets, cursors, out, ctx)?.is_some() + { + return Ok(()); + } + if let Some(view) = col.as_opt::() + && Patched::row_encode_into(view, field, offsets, cursors, out, ctx)?.is_some() + { + return Ok(()); + } let canonical = col.clone().execute::(ctx)?; codec::field_encode(&canonical, field, offsets, cursors, out, ctx) } diff --git a/vortex-row/src/kernels/constant.rs b/vortex-row/src/kernels/constant.rs new file mode 100644 index 00000000000..51d54fbf123 --- /dev/null +++ b/vortex-row/src/kernels/constant.rs @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Row-encode kernels for `ConstantArray`. +//! +//! Stubs in this commit return `Ok(None)` so the dispatch loop falls back to +//! canonicalization. The real impls land in a follow-up commit. + +use vortex_array::ArrayView; +use vortex_array::ExecutionCtx; +use vortex_array::arrays::Constant; +use vortex_error::VortexResult; + +use crate::encode::RowEncodeKernel; +use crate::options::SortField; +use crate::size::RowSizeKernel; + +impl RowSizeKernel for Constant { + fn row_size_contribution( + _column: ArrayView<'_, Self>, + _field: SortField, + _sizes: &mut [u32], + _ctx: &mut ExecutionCtx, + ) -> VortexResult> { + Ok(None) + } +} + +impl RowEncodeKernel for Constant { + fn row_encode_into( + _column: ArrayView<'_, Self>, + _field: SortField, + _offsets: &[u32], + _cursors: &mut [u32], + _out: &mut [u8], + _ctx: &mut ExecutionCtx, + ) -> VortexResult> { + Ok(None) + } +} diff --git a/vortex-row/src/kernels/dict.rs b/vortex-row/src/kernels/dict.rs new file mode 100644 index 00000000000..0f576f3372a --- /dev/null +++ b/vortex-row/src/kernels/dict.rs @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Row-encode kernels for `DictArray`. +//! +//! Stubs in this commit return `Ok(None)` so the dispatch loop falls back to +//! canonicalization. The real impls land in a follow-up commit. + +use vortex_array::ArrayView; +use vortex_array::ExecutionCtx; +use vortex_array::arrays::dict::Dict; +use vortex_error::VortexResult; + +use crate::encode::RowEncodeKernel; +use crate::options::SortField; +use crate::size::RowSizeKernel; + +impl RowSizeKernel for Dict { + fn row_size_contribution( + _column: ArrayView<'_, Self>, + _field: SortField, + _sizes: &mut [u32], + _ctx: &mut ExecutionCtx, + ) -> VortexResult> { + Ok(None) + } +} + +impl RowEncodeKernel for Dict { + fn row_encode_into( + _column: ArrayView<'_, Self>, + _field: SortField, + _offsets: &[u32], + _cursors: &mut [u32], + _out: &mut [u8], + _ctx: &mut ExecutionCtx, + ) -> VortexResult> { + Ok(None) + } +} diff --git a/vortex-row/src/kernels/mod.rs b/vortex-row/src/kernels/mod.rs new file mode 100644 index 00000000000..492f619ef0d --- /dev/null +++ b/vortex-row/src/kernels/mod.rs @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Per-encoding fast-path implementations of [`RowSizeKernel`] and [`RowEncodeKernel`] for +//! encodings defined in `vortex-array`. +//! +//! Each impl in this module lives here (rather than under the corresponding encoding's +//! `compute` module in `vortex-array`) so the orphan rule is satisfied: the trait is +//! defined in `vortex-row` and the impl is also in `vortex-row`, while the array type +//! (`Constant`, `Dict`, `Patched`) remains in `vortex-array`. +//! +//! [`RowSizeKernel`]: crate::size::RowSizeKernel +//! [`RowEncodeKernel`]: crate::encode::RowEncodeKernel + +mod constant; +mod dict; +mod patched; diff --git a/vortex-row/src/kernels/patched.rs b/vortex-row/src/kernels/patched.rs new file mode 100644 index 00000000000..2637116afb4 --- /dev/null +++ b/vortex-row/src/kernels/patched.rs @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Row-encode kernels for `Patched`. +//! +//! Stubs in this commit return `Ok(None)` so the dispatch loop falls back to +//! canonicalization. The real impls land in a follow-up commit. + +use vortex_array::ArrayView; +use vortex_array::ExecutionCtx; +use vortex_array::arrays::patched::Patched; +use vortex_error::VortexResult; + +use crate::encode::RowEncodeKernel; +use crate::options::SortField; +use crate::size::RowSizeKernel; + +impl RowSizeKernel for Patched { + fn row_size_contribution( + _column: ArrayView<'_, Self>, + _field: SortField, + _sizes: &mut [u32], + _ctx: &mut ExecutionCtx, + ) -> VortexResult> { + Ok(None) + } +} + +impl RowEncodeKernel for Patched { + fn row_encode_into( + _column: ArrayView<'_, Self>, + _field: SortField, + _offsets: &[u32], + _cursors: &mut [u32], + _out: &mut [u8], + _ctx: &mut ExecutionCtx, + ) -> VortexResult> { + Ok(None) + } +} diff --git a/vortex-row/src/lib.rs b/vortex-row/src/lib.rs index fddcca665c1..2896ae05acf 100644 --- a/vortex-row/src/lib.rs +++ b/vortex-row/src/lib.rs @@ -28,6 +28,7 @@ pub mod codec; pub mod convert; pub mod encode; +mod kernels; pub mod options; pub mod size; diff --git a/vortex-row/src/size.rs b/vortex-row/src/size.rs index bfe5f647dc5..8fb1bdbcf08 100644 --- a/vortex-row/src/size.rs +++ b/vortex-row/src/size.rs @@ -11,9 +11,12 @@ use vortex_array::Canonical; use vortex_array::ExecutionCtx; use vortex_array::IntoArray; use vortex_array::VTable; +use vortex_array::arrays::Constant; use vortex_array::arrays::ConstantArray; use vortex_array::arrays::PrimitiveArray; use vortex_array::arrays::StructArray; +use vortex_array::arrays::dict::Dict; +use vortex_array::arrays::patched::Patched; use vortex_array::dtype::DType; use vortex_array::dtype::FieldName; use vortex_array::dtype::FieldNames; @@ -256,15 +259,30 @@ impl ScalarFnVTable for RowSize { /// Dispatch a single column's per-row size contribution. /// -/// For PR 1 this is just the canonicalize-then-`codec::field_size` fallback path. In-crate -/// fast paths for `Constant`/`Dict`/`Patched` and the inventory-based registry for -/// downstream encodings are added in PR 3. +/// Tries the in-crate per-encoding fast paths first, then falls back to canonicalization. +/// Per-encoding kernels currently return `Ok(None)` (stubs added alongside the trait); the +/// real impls land in follow-up commits. The downstream-encoding registry is added next. pub fn dispatch_size( col: &ArrayRef, field: SortField, sizes: &mut [u32], ctx: &mut ExecutionCtx, ) -> VortexResult<()> { + if let Some(view) = col.as_opt::() + && Constant::row_size_contribution(view, field, sizes, ctx)?.is_some() + { + return Ok(()); + } + if let Some(view) = col.as_opt::() + && Dict::row_size_contribution(view, field, sizes, ctx)?.is_some() + { + return Ok(()); + } + if let Some(view) = col.as_opt::() + && Patched::row_size_contribution(view, field, sizes, ctx)?.is_some() + { + return Ok(()); + } let canonical = col.clone().execute::(ctx)?; codec::field_size(&canonical, field, sizes, ctx) }