Skip to content

Commit e3b7310

Browse files
feat: iterative execute alp/alp_rd/bitpacking (#7233)
Use iterative execute for alp/alp_rd and bitpacking Introduce a require_patches! and require_validity! to iteratively execute those children. --------- Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
1 parent 267d6ee commit e3b7310

5 files changed

Lines changed: 111 additions & 1 deletion

File tree

encodings/alp/src/alp/array.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ use vortex_array::IntoArray;
1616
use vortex_array::Precision;
1717
use vortex_array::ProstMetadata;
1818
use vortex_array::SerializeMetadata;
19+
use vortex_array::arrays::Primitive;
1920
use vortex_array::buffer::BufferHandle;
2021
use vortex_array::dtype::DType;
2122
use vortex_array::dtype::PType;
2223
use vortex_array::patches::Patches;
2324
use vortex_array::patches::PatchesMetadata;
25+
use vortex_array::require_child;
26+
use vortex_array::require_patches;
2427
use vortex_array::serde::ArrayChildren;
2528
use vortex_array::stats::ArrayStats;
2629
use vortex_array::stats::StatsSetRef;
@@ -191,6 +194,15 @@ impl VTable for ALP {
191194
}
192195

193196
fn execute(array: Arc<Array<Self>>, ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
197+
let array = require_child!(array, array.encoded(), ENCODED_SLOT => Primitive);
198+
require_patches!(
199+
array,
200+
array.patches(),
201+
PATCH_INDICES_SLOT,
202+
PATCH_VALUES_SLOT,
203+
PATCH_CHUNK_OFFSETS_SLOT
204+
);
205+
194206
Ok(ExecutionResult::done(
195207
execute_decompress(Arc::unwrap_or_clone(array).into_inner(), ctx)?.into_array(),
196208
))

encodings/alp/src/alp_rd/array.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use vortex_array::dtype::PType;
2626
use vortex_array::patches::Patches;
2727
use vortex_array::patches::PatchesMetadata;
2828
use vortex_array::require_child;
29+
use vortex_array::require_patches;
2930
use vortex_array::serde::ArrayChildren;
3031
use vortex_array::stats::ArrayStats;
3132
use vortex_array::stats::StatsSetRef;
@@ -271,6 +272,13 @@ impl VTable for ALPRD {
271272
fn execute(array: Arc<Array<Self>>, ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
272273
let array = require_child!(array, array.left_parts(), 0 => Primitive);
273274
let array = require_child!(array, array.right_parts(), 1 => Primitive);
275+
require_patches!(
276+
array,
277+
array.left_parts_patches(),
278+
LP_PATCH_INDICES_SLOT,
279+
LP_PATCH_VALUES_SLOT,
280+
LP_PATCH_CHUNK_OFFSETS_SLOT
281+
);
274282

275283
let right_bit_width = array.right_bit_width();
276284
let ALPRDArrayParts {
@@ -297,7 +305,6 @@ impl VTable for ALPRD {
297305
let validity = left_parts.validity_mask()?;
298306

299307
let decoded_array = if ptype == PType::F32 {
300-
// TODO(joe): use iterative execution for the patches.
301308
PrimitiveArray::new(
302309
alp_rd_decode::<f32>(
303310
left_parts.into_buffer::<u16>(),

encodings/fastlanes/src/bitpacking/vtable/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use std::hash::Hash;
55
use std::sync::Arc;
66

7+
use vortex_array::AnyCanonical;
78
use vortex_array::ArrayEq;
89
use vortex_array::ArrayHash;
910
use vortex_array::ArrayRef;
@@ -21,6 +22,8 @@ use vortex_array::dtype::PType;
2122
use vortex_array::match_each_integer_ptype;
2223
use vortex_array::patches::Patches;
2324
use vortex_array::patches::PatchesMetadata;
25+
use vortex_array::require_patches;
26+
use vortex_array::require_validity;
2427
use vortex_array::serde::ArrayChildren;
2528
use vortex_array::stats::StatsSetRef;
2629
use vortex_array::validity::Validity;
@@ -40,9 +43,11 @@ use crate::BitPackedArray;
4043
use crate::bitpack_decompress::unpack_array;
4144
use crate::bitpack_decompress::unpack_into_primitive_builder;
4245
use crate::bitpacking::array::NUM_SLOTS;
46+
use crate::bitpacking::array::PATCH_CHUNK_OFFSETS_SLOT;
4347
use crate::bitpacking::array::PATCH_INDICES_SLOT;
4448
use crate::bitpacking::array::PATCH_VALUES_SLOT;
4549
use crate::bitpacking::array::SLOT_NAMES;
50+
use crate::bitpacking::array::VALIDITY_SLOT;
4651
use crate::bitpacking::vtable::kernels::PARENT_KERNELS;
4752
use crate::bitpacking::vtable::rules::RULES;
4853
mod kernels;
@@ -286,6 +291,15 @@ impl VTable for BitPacked {
286291
}
287292

288293
fn execute(array: Arc<Array<Self>>, ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
294+
require_patches!(
295+
array,
296+
array.patches(),
297+
PATCH_INDICES_SLOT,
298+
PATCH_VALUES_SLOT,
299+
PATCH_CHUNK_OFFSETS_SLOT
300+
);
301+
require_validity!(array, &array.validity(), VALIDITY_SLOT => AnyCanonical);
302+
289303
Ok(ExecutionResult::done(
290304
unpack_array(&array, ctx)?.into_array(),
291305
))

vortex-array/public-api.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24082,6 +24082,12 @@ pub macro vortex_array::match_smallest_offset_type!
2408224082

2408324083
pub macro vortex_array::require_child!
2408424084

24085+
pub macro vortex_array::require_opt_child!
24086+
24087+
pub macro vortex_array::require_patches!
24088+
24089+
pub macro vortex_array::require_validity!
24090+
2408524091
pub macro vortex_array::vtable!
2408624092

2408724093
pub enum vortex_array::Canonical

vortex-array/src/executor.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,77 @@ macro_rules! require_child {
477477
}};
478478
}
479479

480+
/// Like [`require_child!`], but for optional children. If the child is `None`, this is a no-op.
481+
/// If the child is `Some` but does not match `$M`, early-returns an [`ExecutionResult`] requesting
482+
/// execution of child `$idx`.
483+
///
484+
/// Unlike `require_child!`, this is a statement macro (no value produced) and does not clone
485+
/// `$parent` — it is moved into the early-return path.
486+
///
487+
/// ```ignore
488+
/// require_opt_child!(array, array.patches().map(|p| p.indices()), 1 => Primitive);
489+
/// ```
490+
#[macro_export]
491+
macro_rules! require_opt_child {
492+
($parent:expr, $child_opt:expr, $idx:expr => $M:ty) => {
493+
if $child_opt.is_some_and(|child| !child.is::<$M>()) {
494+
return Ok($crate::ExecutionResult::execute_slot::<$M>($parent, $idx));
495+
}
496+
};
497+
}
498+
499+
/// Require that all children of a [`Patches`](crate::patches::Patches) (indices, values, and
500+
/// optionally chunk_offsets) are `Primitive`. If no patches are present, this is a no-op.
501+
///
502+
/// Like [`require_opt_child!`], `$parent` is moved (not cloned) into the early-return path.
503+
///
504+
/// ```ignore
505+
/// require_patches!(array, array.patches(), PATCH_INDICES_SLOT, PATCH_VALUES_SLOT, PATCH_CHUNK_OFFSETS_SLOT);
506+
/// ```
507+
#[macro_export]
508+
macro_rules! require_patches {
509+
($parent:expr, $patches:expr, $indices_slot:expr, $values_slot:expr, $chunk_offsets_slot:expr) => {
510+
let __patches = $patches;
511+
$crate::require_opt_child!(
512+
$parent,
513+
__patches.as_ref().map(|p| p.indices()),
514+
$indices_slot => $crate::arrays::Primitive
515+
);
516+
let __patches = $patches;
517+
$crate::require_opt_child!(
518+
$parent,
519+
__patches.as_ref().map(|p| p.values()),
520+
$values_slot => $crate::arrays::Primitive
521+
);
522+
let __patches = $patches;
523+
$crate::require_opt_child!(
524+
$parent,
525+
__patches.as_ref().and_then(|p| p.chunk_offsets().as_ref()),
526+
$chunk_offsets_slot => $crate::arrays::Primitive
527+
);
528+
};
529+
}
530+
531+
/// Require that a [`Validity::Array`](crate::validity::Validity::Array) child matches `$M`. If validity is not array-backed
532+
/// (e.g. `NonNullable` or `AllValid`), this is a no-op. If it is array-backed but does not
533+
/// match `$M`, early-returns an [`ExecutionResult`] requesting execution of the validity slot.
534+
///
535+
/// Like [`require_opt_child!`], `$parent` is moved (not cloned) into the early-return path.
536+
///
537+
/// ```ignore
538+
/// require_validity!(array, &array.validity, VALIDITY_SLOT => AnyCanonical);
539+
/// ```
540+
#[macro_export]
541+
macro_rules! require_validity {
542+
($parent:expr, $validity:expr, $idx:expr => $M:ty) => {
543+
if let $crate::validity::Validity::Array(v) = $validity {
544+
if !v.is::<$M>() {
545+
return Ok($crate::ExecutionResult::execute_slot::<$M>($parent, $idx));
546+
}
547+
}
548+
};
549+
}
550+
480551
/// Extension trait for creating an execution context from a session.
481552
pub trait VortexSessionExecute {
482553
/// Create a new execution context from this session.

0 commit comments

Comments
 (0)