Skip to content

Commit e1c6ef5

Browse files
break: add Validity::definitely_all_null() method (#8447)
## Summary This PR introduces a new `Validity::definitely_all_null()` method that provides a fast path to check if a validity is definitively all-null (i.e., `Validity::AllInvalid`). This is the counterpart to the existing `definitely_no_nulls()` method. This is a rename, but not a change in semantics --------- Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9b5447a commit e1c6ef5

19 files changed

Lines changed: 31 additions & 30 deletions

File tree

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ use crate::executor::ExecutionResult;
4646
use crate::require_child;
4747
use crate::scalar::Scalar;
4848
use crate::serde::ArrayChildren;
49-
use crate::validity::Validity;
5049

5150
mod kernel;
5251
mod operations;
@@ -179,7 +178,7 @@ impl VTable for Dict {
179178

180179
let array = require_child!(array, array.codes(), DictSlots::CODES => Primitive);
181180

182-
if matches!(array.codes().validity()?, Validity::AllInvalid) {
181+
if array.codes().validity()?.definitely_all_null() {
183182
return Ok(ExecutionResult::done(ConstantArray::new(
184183
Scalar::null(array.dtype().as_nullable()),
185184
array.codes().len(),

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl VTable for Masked {
165165
let validity = array.masked_validity();
166166

167167
// Fast path: all masked means result is all nulls.
168-
if matches!(validity, Validity::AllInvalid) {
168+
if validity.definitely_all_null() {
169169
return Ok(ExecutionResult::done(
170170
ConstantArray::new(Scalar::null(array.dtype().as_nullable()), array.len())
171171
.into_array(),

vortex-array/src/arrays/primitive/array/top_value.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::arrays::primitive::NativeValue;
1717
use crate::dtype::NativePType;
1818
use crate::match_each_native_ptype;
1919
use crate::scalar::PValue;
20-
use crate::validity::Validity;
2120

2221
impl PrimitiveArray {
2322
/// Compute most common present value of this array
@@ -26,7 +25,7 @@ impl PrimitiveArray {
2625
return Ok(None);
2726
}
2827

29-
if matches!(self.validity()?, Validity::AllInvalid) {
28+
if self.validity()?.definitely_all_null() {
3029
return Ok(None);
3130
}
3231

vortex-array/src/arrays/varbin/array.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ impl VarBinData {
255255
}
256256
_ => None,
257257
};
258-
let all_invalid = matches!(validity, Validity::AllInvalid);
258+
let all_invalid = validity.definitely_all_null();
259259

260260
match_each_integer_ptype!(primitive_offsets.dtype().as_ptype(), |O| {
261261
let offsets_slice = primitive_offsets.as_slice::<O>();

vortex-array/src/scalar_fn/fns/fill_null/kernel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub(super) fn precondition(
7979
}
8080

8181
// If all values are null, replace the entire array with the fill value.
82-
if matches!(array.validity()?, Validity::AllInvalid) {
82+
if array.validity()?.definitely_all_null() {
8383
return Ok(Some(
8484
ConstantArray::new(fill_value.clone(), array.len()).into_array(),
8585
));

vortex-array/src/scalar_fn/fns/list_contains/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ fn list_is_not_empty(
415415
ctx: &mut ExecutionCtx,
416416
) -> VortexResult<ArrayRef> {
417417
// Short-circuit for all invalid.
418-
if matches!(list_array.validity()?, Validity::AllInvalid) {
418+
if list_array.validity()?.definitely_all_null() {
419419
return Ok(ConstantArray::new(
420420
Scalar::null(DType::Bool(Nullability::Nullable)),
421421
list_array.len(),

vortex-array/src/validity.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,19 @@ impl Validity {
123123
matches!(self, Self::NonNullable | Self::AllValid)
124124
}
125125

126+
/// Returns `true` if this validity is *definitely* all-null (every value is null), i.e. it
127+
/// is [`Validity::AllInvalid`].
128+
///
129+
/// Returning `false` does not prove that any value is valid: a [`Validity::Array`] may still
130+
/// resolve to all-null once executed. Callers must treat `false` as "unknown without
131+
/// compute". For a definitive answer, execute the validity with [`Self::execute_mask`] and
132+
/// check whether the resulting [`Mask`] is all-false (`Mask::all_false`). This is the
133+
/// all-null counterpart to [`Self::definitely_no_nulls`].
134+
#[inline]
135+
pub fn definitely_all_null(&self) -> bool {
136+
matches!(self, Self::AllInvalid)
137+
}
138+
126139
/// Returns whether this validity contains no null values, executing the validity array if
127140
/// necessary.
128141
///

vortex-cuda/src/dynamic_dispatch/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ use vortex::array::buffer::BufferHandle;
3232
use vortex::array::buffer::DeviceBufferExt;
3333
use vortex::array::match_each_unsigned_integer_ptype;
3434
use vortex::array::scalar::Scalar;
35-
use vortex::array::validity::Validity;
3635
use vortex::buffer::Alignment;
3736
use vortex::buffer::ByteBuffer;
3837
use vortex::buffer::ByteBufferMut;
@@ -434,7 +433,7 @@ impl MaterializedPlan {
434433
let output_ptype = self.dispatch_plan.output_ptype();
435434

436435
// All values are null — no need to touch the GPU.
437-
if matches!(self.validity, Validity::AllInvalid) {
436+
if self.validity.definitely_all_null() {
438437
let dtype = DType::Primitive(output_ptype, Nullability::Nullable);
439438
return ConstantArray::new(Scalar::null(dtype), len)
440439
.into_array()

vortex-cuda/src/kernel/encodings/date_time_parts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl CudaExecute for DateTimePartsExecutor {
7272
return Ok(Canonical::empty(array.dtype()));
7373
}
7474

75-
if matches!(validity, Validity::AllInvalid) {
75+
if validity.definitely_all_null() {
7676
let storage_ptype = ext.storage_dtype().as_ptype();
7777
return Ok(Canonical::Extension(
7878
TemporalArray::new_timestamp(

vortex-cuda/src/kernel/encodings/fsst.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use vortex::array::arrays::varbinview::build_views::build_views;
2323
use vortex::array::buffer::DeviceBuffer;
2424
use vortex::array::match_each_integer_ptype;
2525
use vortex::array::match_each_unsigned_integer_ptype;
26-
use vortex::array::validity::Validity;
2726
use vortex::buffer::Alignment;
2827
use vortex::buffer::Buffer;
2928
use vortex::dtype::NativePType;
@@ -62,7 +61,7 @@ impl CudaExecute for FSSTExecutor {
6261
let dtype = fsst.dtype().clone();
6362
let validity = fsst.codes().validity()?;
6463

65-
if fsst.is_empty() || matches!(validity, Validity::AllInvalid) {
64+
if fsst.is_empty() || validity.definitely_all_null() {
6665
let empty = unsafe {
6766
VarBinViewArray::new_unchecked(
6867
Buffer::<BinaryView>::zeroed(fsst.len()),

0 commit comments

Comments
 (0)