From 4945d6a5870e325b4dd016fa84b0e716c6619a62 Mon Sep 17 00:00:00 2001 From: Daniel King Date: Mon, 31 Aug 2026 19:14:07 -0400 Subject: [PATCH] Push runend lists into listview slots Signed-off-by: Daniel King --- encodings/runend/src/array.rs | 102 +++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/encodings/runend/src/array.rs b/encodings/runend/src/array.rs index 030a46cb802..99451d9e413 100644 --- a/encodings/runend/src/array.rs +++ b/encodings/runend/src/array.rs @@ -22,11 +22,9 @@ use vortex_array::IntoArray; use vortex_array::TypedArrayRef; use vortex_array::VortexSessionExecute; use vortex_array::array_slots; -use vortex_array::arrays::BoolArray; use vortex_array::arrays::DecimalArray; use vortex_array::arrays::ListViewArray; use vortex_array::arrays::Primitive; -use vortex_array::arrays::PrimitiveArray; use vortex_array::arrays::VarBinViewArray; use vortex_array::arrays::listview::ListViewArraySlotsExt; use vortex_array::buffer::BufferHandle; @@ -511,53 +509,49 @@ pub(super) fn run_end_canonicalize( .values() .clone() .execute_as::("values", ctx)?; - runend_decode_listview(pends, values, array.offset(), array.len(), ctx)?.into_array() + let validity = match values.validity()? { + Validity::NonNullable => Validity::NonNullable, + Validity::AllValid => Validity::AllValid, + Validity::AllInvalid => Validity::AllInvalid, + Validity::Array(validity) => Validity::Array( + unsafe { + RunEnd::new_unchecked( + pends.clone().into_array(), + validity, + array.offset(), + array.len(), + ) + } + .into_array(), + ), + }; + + unsafe { + ListViewArray::new_unchecked( + values.elements().clone(), + RunEnd::new_unchecked( + pends.clone().into_array(), + values.offsets().clone(), + array.offset(), + array.len(), + ) + .into_array(), + RunEnd::new_unchecked( + pends.into_array(), + values.sizes().clone(), + array.offset(), + array.len(), + ) + .into_array(), + validity, + ) + } + .into_array() } _ => vortex_bail!("Unsupported RunEnd value type: {}", array.dtype()), }) } -fn runend_decode_listview( - ends: PrimitiveArray, - values: ListViewArray, - offset: usize, - length: usize, - ctx: &mut ExecutionCtx, -) -> VortexResult { - let offsets = values.offsets().clone().execute_as("offsets", ctx)?; - let decoded_offsets = - runend_decode_primitive(ends.clone(), offsets, offset, length, ctx)?.into_array(); - - let sizes = values.sizes().clone().execute_as("sizes", ctx)?; - let decoded_sizes = - runend_decode_primitive(ends.clone(), sizes, offset, length, ctx)?.into_array(); - - let validity = match values.validity()? { - Validity::NonNullable => Validity::NonNullable, - Validity::AllValid => Validity::AllValid, - Validity::AllInvalid => Validity::AllInvalid, - Validity::Array(validity) => Validity::Array(runend_decode_bools( - ends, - validity.execute_as::("validity", ctx)?, - offset, - length, - ctx, - )?), - }; - - // SAFETY: `decoded_offsets`, `decoded_sizes`, and `validity` are expanded from valid ListView - // metadata for each run. The original `elements` child is reused, so every expanded view still - // points at the same valid element ranges. - Ok(unsafe { - ListViewArray::new_unchecked( - values.elements().clone(), - decoded_offsets, - decoded_sizes, - validity, - ) - }) -} - #[cfg(test)] mod tests { use std::sync::Arc; @@ -568,7 +562,9 @@ mod tests { use vortex_array::arrays::DecimalArray; use vortex_array::arrays::DictArray; use vortex_array::arrays::ListArray; + use vortex_array::arrays::ListViewArray; use vortex_array::arrays::VarBinViewArray; + use vortex_array::arrays::listview::ListViewArraySlotsExt; use vortex_array::assert_arrays_eq; use vortex_array::builders::VarBinBuilder; use vortex_array::dtype::DType; @@ -726,6 +722,24 @@ mod tests { assert_arrays_eq!(arr.into_array(), expected, &mut ctx); } + #[test] + fn test_runend_list_pushes_into_listview_slots() -> VortexResult<()> { + let mut ctx = SESSION.create_execution_ctx(); + let values = ListArray::from_iter_slow::( + vec![vec![1i64, 2], vec![3], vec![4, 5, 6]], + Arc::new(DType::Primitive(PType::I64, Nullability::NonNullable)), + )? + .into_array(); + let arr = RunEnd::try_new(buffer![2u32, 5, 10].into_array(), values, &mut ctx)?; + + let listview = arr.into_array().execute::(&mut ctx)?; + assert!(listview.offsets().is::()); + assert!(listview.sizes().is::()); + assert_eq!(listview.elements().len(), 6); + + Ok(()) + } + #[test] fn test_runend_dict() { let mut ctx = SESSION.create_execution_ctx();