Skip to content

Commit 98b31fb

Browse files
authored
Feature: add impl owned filter impls (#5493)
Since the operator API passes around owned vectors, we probably want to use these filter impls. It is a good amount of boilerplate, but honestly I think it is fine since we are not likely not adding many more vector types. Signed-off-by: Connor Tsui <[email protected]>
1 parent 4a0051e commit 98b31fb

File tree

10 files changed

+200
-11
lines changed

10 files changed

+200
-11
lines changed

vortex-compute/src/filter/vector/binaryview.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
use vortex_buffer::{Buffer, BufferMut};
55
use vortex_mask::{Mask, MaskMut};
6-
use vortex_vector::VectorOps;
76
use vortex_vector::binaryview::{
87
BinaryView, BinaryViewType, BinaryViewVector, BinaryViewVectorMut,
98
};
9+
use vortex_vector::{VectorMutOps, VectorOps};
1010

1111
use crate::filter::Filter;
1212

@@ -42,3 +42,24 @@ where
4242
}
4343
}
4444
}
45+
46+
impl<M, T: BinaryViewType> Filter<M> for BinaryViewVector<T>
47+
where
48+
for<'a> &'a BinaryViewVector<T>: Filter<M, Output = BinaryViewVector<T>>,
49+
for<'a> &'a mut BinaryViewVectorMut<T>: Filter<M, Output = ()>,
50+
{
51+
type Output = Self;
52+
53+
fn filter(self, selection: &M) -> Self {
54+
match self.try_into_mut() {
55+
// If we have exclusive access, we can perform the filter in place.
56+
Ok(mut vector_mut) => {
57+
(&mut vector_mut).filter(selection);
58+
vector_mut.freeze()
59+
}
60+
// Otherwise, allocate a new buffer and fill it in (delegate to the `&BinaryViewVector`
61+
// impl).
62+
Err(vector) => (&vector).filter(selection),
63+
}
64+
}
65+
}

vortex-compute/src/filter/vector/bool.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
use vortex_buffer::{BitBuffer, BitBufferMut};
55
use vortex_mask::{Mask, MaskMut};
6-
use vortex_vector::VectorOps;
76
use vortex_vector::bool::{BoolVector, BoolVectorMut};
7+
use vortex_vector::{VectorMutOps, VectorOps};
88

99
use crate::filter::Filter;
1010

@@ -38,3 +38,23 @@ where
3838
unsafe { self.validity_mut().filter(selection) };
3939
}
4040
}
41+
42+
impl<M> Filter<M> for BoolVector
43+
where
44+
for<'a> &'a BoolVector: Filter<M, Output = BoolVector>,
45+
for<'a> &'a mut BoolVectorMut: Filter<M, Output = ()>,
46+
{
47+
type Output = Self;
48+
49+
fn filter(self, selection: &M) -> Self {
50+
match self.try_into_mut() {
51+
// If we have exclusive access, we can perform the filter in place.
52+
Ok(mut vector_mut) => {
53+
(&mut vector_mut).filter(selection);
54+
vector_mut.freeze()
55+
}
56+
// Otherwise, allocate a new buffer and fill it in (delegate to the `&BoolVector` impl).
57+
Err(vector) => (&vector).filter(selection),
58+
}
59+
}
60+
}

vortex-compute/src/filter/vector/decimal.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use vortex_dtype::i256;
55
use vortex_vector::decimal::{DVector, DVectorMut, DecimalVector, DecimalVectorMut};
6-
use vortex_vector::{match_each_dvector, match_each_dvector_mut};
6+
use vortex_vector::{VectorMutOps, VectorOps, match_each_dvector, match_each_dvector_mut};
77

88
use crate::filter::Filter;
99

@@ -38,3 +38,24 @@ where
3838
match_each_dvector_mut!(self, |d| { d.filter(selection) });
3939
}
4040
}
41+
42+
impl<M> Filter<M> for DecimalVector
43+
where
44+
for<'a> &'a DecimalVector: Filter<M, Output = DecimalVector>,
45+
for<'a> &'a mut DecimalVectorMut: Filter<M, Output = ()>,
46+
{
47+
type Output = Self;
48+
49+
fn filter(self, selection: &M) -> Self {
50+
match self.try_into_mut() {
51+
// If we have exclusive access, we can perform the filter in place.
52+
Ok(mut vector_mut) => {
53+
(&mut vector_mut).filter(selection);
54+
vector_mut.freeze()
55+
}
56+
// Otherwise, allocate a new buffer and fill it in (delegate to the `&DecimalVector`
57+
// impl).
58+
Err(vector) => (&vector).filter(selection),
59+
}
60+
}
61+
}

vortex-compute/src/filter/vector/dvector.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
use vortex_buffer::{Buffer, BufferMut};
55
use vortex_dtype::NativeDecimalType;
66
use vortex_mask::{Mask, MaskMut};
7-
use vortex_vector::VectorOps;
87
use vortex_vector::decimal::{DVector, DVectorMut};
8+
use vortex_vector::{VectorMutOps, VectorOps};
99

1010
use crate::filter::Filter;
1111

@@ -39,3 +39,23 @@ where
3939
}
4040
}
4141
}
42+
43+
impl<M, D: NativeDecimalType> Filter<M> for DVector<D>
44+
where
45+
for<'a> &'a DVector<D>: Filter<M, Output = DVector<D>>,
46+
for<'a> &'a mut DVectorMut<D>: Filter<M, Output = ()>,
47+
{
48+
type Output = Self;
49+
50+
fn filter(self, selection: &M) -> Self {
51+
match self.try_into_mut() {
52+
// If we have exclusive access, we can perform the filter in place.
53+
Ok(mut vector_mut) => {
54+
(&mut vector_mut).filter(selection);
55+
vector_mut.freeze()
56+
}
57+
// Otherwise, allocate a new buffer and fill it in (delegate to the `&DVector` impl).
58+
Err(vector) => (&vector).filter(selection),
59+
}
60+
}
61+
}

vortex-compute/src/filter/vector/list.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
use std::sync::Arc;
55

66
use vortex_mask::{Mask, MaskMut};
7-
use vortex_vector::VectorOps;
87
use vortex_vector::listview::{ListViewVector, ListViewVectorMut};
98
use vortex_vector::primitive::{PrimitiveVector, PrimitiveVectorMut};
9+
use vortex_vector::{VectorMutOps, VectorOps};
1010

1111
use crate::filter::Filter;
1212

@@ -45,3 +45,24 @@ where
4545
}
4646
}
4747
}
48+
49+
impl<M> Filter<M> for ListViewVector
50+
where
51+
for<'a> &'a ListViewVector: Filter<M, Output = ListViewVector>,
52+
for<'a> &'a mut ListViewVectorMut: Filter<M, Output = ()>,
53+
{
54+
type Output = Self;
55+
56+
fn filter(self, selection: &M) -> Self {
57+
match self.try_into_mut() {
58+
// If we have exclusive access, we can perform the filter in place.
59+
Ok(mut vector_mut) => {
60+
(&mut vector_mut).filter(selection);
61+
vector_mut.freeze()
62+
}
63+
// Otherwise, allocate a new buffer and fill it in (delegate to the `&ListViewVector`
64+
// impl).
65+
Err(vector) => (&vector).filter(selection),
66+
}
67+
}
68+
}

vortex-compute/src/filter/vector/mod.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
//! Filter implementations for vector types.
5+
//!
6+
//! This module provides [`Filter`] trait implementations for all vector types with three distinct
7+
//! patterns optimized for different ownership scenarios:
8+
//!
9+
//! ### 1. Reference Implementation (`&Vector`)
10+
//!
11+
//! Filters by allocating new memory and copying selected elements. Returns a new owned vector.
12+
//! This is the base implementation that all other patterns can fall back to.
13+
//!
14+
//! ### 2. Mutable Reference Implementation (`&mut VectorMut`)
15+
//!
16+
//! Filters in-place when exclusive mutable access is available, avoiding allocation. Returns `()`
17+
//! as the vector is modified directly. This is the most efficient when you already have a mutable
18+
//! vector (it is only less efficient if the vector is very small and the output vector is already
19+
//! in the L1 cache).
20+
//!
21+
//! ### 3. Owned Implementation (`Vector`)
22+
//!
23+
//! Uses [`VectorOps::try_into_mut`] to check for exclusive ownership. If successful, performs
24+
//! in-place filtering via the mutable implementation and calls [`VectorMutOps::freeze`] to convert
25+
//! back. Otherwise, delegates to the reference implementation and makes an allocation.
26+
//!
27+
//! ## Breaking Recursive Trait Bounds
28+
//!
29+
//! To allow all vector types to implement filter generically over a "mask" type `M`, we must break
30+
//! the recursive trait bounds (e.g. from [`StructVector`] requiring `Vector: Filter<M>` for its
31+
//! fields) by manually implementing [`Filter`] for [`Vector`] and [`VectorMut`] for each concrete
32+
//! mask type in this file.
33+
434
use vortex_buffer::BitView;
535
use vortex_mask::Mask;
636
use vortex_vector::{Vector, VectorMut, match_each_vector, match_each_vector_mut};
@@ -18,9 +48,8 @@ mod primitive;
1848
mod pvector;
1949
mod struct_;
2050

21-
// To allow all vector types to implement filter generically over `M`, we must break the recursive
22-
// trait bounds (e.g. from StructVector requiring Vector: Filter<M> for its fields) by manually
23-
// implementing Filter for Vector and VectorMut for each concrete mask type here.
51+
// We manually implement Filter for Vector and VectorMut for each concrete mask type here to break
52+
// the recursive trait bounds.
2453

2554
impl Filter<Mask> for &Vector {
2655
type Output = Vector;

vortex-compute/src/filter/vector/null.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ impl<const NB: usize> Filter<BitView<'_, NB>> for &mut NullVectorMut {
3939
}
4040
}
4141

42+
impl Filter<Mask> for NullVector {
43+
type Output = Self;
44+
45+
fn filter(self, selection: &Mask) -> Self {
46+
(&self).filter(selection)
47+
}
48+
}
49+
50+
impl<const NB: usize> Filter<BitView<'_, NB>> for NullVector {
51+
type Output = Self;
52+
53+
fn filter(self, selection: &BitView<'_, NB>) -> Self {
54+
(&self).filter(selection)
55+
}
56+
}
57+
4258
#[cfg(test)]
4359
mod tests {
4460
use vortex_mask::Mask;

vortex-compute/src/filter/vector/primitive.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use vortex_dtype::half::f16;
55
use vortex_vector::primitive::{PVector, PVectorMut, PrimitiveVector, PrimitiveVectorMut};
6-
use vortex_vector::{match_each_pvector, match_each_pvector_mut};
6+
use vortex_vector::{VectorMutOps, VectorOps, match_each_pvector, match_each_pvector_mut};
77

88
use crate::filter::Filter;
99

@@ -48,3 +48,24 @@ where
4848
match_each_pvector_mut!(self, |v| { v.filter(selection) })
4949
}
5050
}
51+
52+
impl<M> Filter<M> for PrimitiveVector
53+
where
54+
for<'a> &'a PrimitiveVector: Filter<M, Output = PrimitiveVector>,
55+
for<'a> &'a mut PrimitiveVectorMut: Filter<M, Output = ()>,
56+
{
57+
type Output = Self;
58+
59+
fn filter(self, selection: &M) -> Self {
60+
match self.try_into_mut() {
61+
// If we have exclusive access, we can perform the filter in place.
62+
Ok(mut vector_mut) => {
63+
(&mut vector_mut).filter(selection);
64+
vector_mut.freeze()
65+
}
66+
// Otherwise, allocate a new buffer and fill it in (delegate to the `&PrimitiveVector`
67+
// impl).
68+
Err(vector) => (&vector).filter(selection),
69+
}
70+
}
71+
}

vortex-compute/src/filter/vector/pvector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ where
5151
type Output = Self;
5252

5353
fn filter(self, selection_mask: &M) -> Self {
54-
// If we have exclusive access, we can perform the filter in place.
5554
match self.try_into_mut() {
55+
// If we have exclusive access, we can perform the filter in place.
5656
Ok(mut vector_mut) => {
5757
(&mut vector_mut).filter(selection_mask);
5858
vector_mut.freeze()

vortex-compute/src/filter/vector/struct_.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::sync::Arc;
55

66
use vortex_mask::{Mask, MaskMut};
77
use vortex_vector::struct_::{StructVector, StructVectorMut};
8-
use vortex_vector::{Vector, VectorMut, VectorOps};
8+
use vortex_vector::{Vector, VectorMut, VectorMutOps, VectorOps};
99

1010
use crate::filter::Filter;
1111

@@ -49,3 +49,23 @@ where
4949
}
5050
}
5151
}
52+
53+
impl<M> Filter<M> for StructVector
54+
where
55+
for<'a> &'a StructVector: Filter<M, Output = StructVector>,
56+
for<'a> &'a mut StructVectorMut: Filter<M, Output = ()>,
57+
{
58+
type Output = Self;
59+
60+
fn filter(self, selection: &M) -> Self {
61+
match self.try_into_mut() {
62+
// If we have exclusive access, we can perform the filter in place.
63+
Ok(mut vector_mut) => {
64+
(&mut vector_mut).filter(selection);
65+
vector_mut.freeze()
66+
}
67+
// Otherwise, allocate a new buffer and fill it in (delegate to the `&StructVector` impl).
68+
Err(vector) => (&vector).filter(selection),
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)