• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16979224669

14 Aug 2025 11:42PM UTC coverage: 23.728%. First build
16979224669

Pull #2456

github

web-flow
Merge 30049dfa7 into aaf3e36ad
Pull Request #2456: feat: basic BoolBuffer / BoolBufferMut

68 of 1065 new or added lines in 82 files covered. (6.38%)

8616 of 36312 relevant lines covered (23.73%)

146.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/vortex-array/src/arrays/bool/compute/filter.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use vortex_buffer::{BitBuffer, BitBufferMut};
5
use vortex_error::{VortexExpect, VortexResult};
6
use vortex_mask::{Mask, MaskIter};
7

8
use crate::arrays::{BoolArray, BoolVTable};
9
use crate::compute::{FilterKernel, FilterKernelAdapter};
10
use crate::vtable::ValidityHelper;
11
use crate::{ArrayRef, IntoArray, register_kernel};
12

13
/// If the filter density is above 80%, we use slices to filter the array instead of indices.
14
const FILTER_SLICES_DENSITY_THRESHOLD: f64 = 0.8;
15

16
impl FilterKernel for BoolVTable {
17
    fn filter(&self, array: &BoolArray, mask: &Mask) -> VortexResult<ArrayRef> {
×
18
        let validity = array.validity().filter(mask)?;
×
19

20
        let mask_values = mask
×
21
            .values()
×
22
            .vortex_expect("AllTrue and AllFalse are handled by filter fn");
×
23

24
        let buffer = match mask_values.threshold_iter(FILTER_SLICES_DENSITY_THRESHOLD) {
×
25
            MaskIter::Indices(indices) => filter_indices(
×
NEW
26
                array.bit_buffer(),
×
27
                mask.true_count(),
×
28
                indices.iter().copied(),
×
29
            ),
30
            MaskIter::Slices(slices) => filter_slices(
×
NEW
31
                array.bit_buffer(),
×
32
                mask.true_count(),
×
33
                slices.iter().copied(),
×
34
            ),
35
        };
36

37
        Ok(BoolArray::new(buffer, validity).into_array())
×
38
    }
×
39
}
40

41
register_kernel!(FilterKernelAdapter(BoolVTable).lift());
42

43
/// Select indices from a boolean buffer.
44
/// NOTE: it was benchmarked to be faster using collect_bool to index into a slice than to
45
///  pass the indices as an iterator of usize. So we keep this alternate implementation.
46
pub fn filter_indices(
×
NEW
47
    buffer: &BitBuffer,
×
48
    indices_len: usize,
×
49
    mut indices: impl Iterator<Item = usize>,
×
NEW
50
) -> BitBuffer {
×
NEW
51
    BitBuffer::collect_bool(indices_len, |_idx| {
×
52
        let idx = indices
×
53
            .next()
×
54
            .vortex_expect("iterator is guaranteed to be within the length of the array.");
×
NEW
55
        buffer.value(idx)
×
56
    })
×
57
}
×
58

59
pub fn filter_slices(
×
NEW
60
    buffer: &BitBuffer,
×
61
    indices_len: usize,
×
62
    slices: impl Iterator<Item = (usize, usize)>,
×
NEW
63
) -> BitBuffer {
×
64
    let offset = buffer.offset();
×
NEW
65
    let src = buffer.inner();
×
66

NEW
67
    let mut builder = BitBufferMut::new(indices_len);
×
68
    for (start, end) in slices {
×
69
        builder.append_packed_range(start + offset..end + offset, src)
×
70
    }
NEW
71
    builder.freeze()
×
72
}
×
73

74
#[cfg(test)]
75
mod test {
76
    use itertools::Itertools;
77
    use vortex_mask::Mask;
78

79
    use crate::arrays::BoolArray;
80
    use crate::arrays::bool::compute::filter::{filter_indices, filter_slices};
81
    use crate::canonical::ToCanonical;
82
    use crate::compute::conformance::filter::test_filter_conformance;
83
    use crate::compute::filter;
84

85
    #[test]
86
    fn filter_bool_test() {
87
        let arr = BoolArray::from_iter([true, true, false]);
88
        let mask = Mask::from_iter([true, false, true]);
89

90
        let filtered = filter(arr.as_ref(), &mask).unwrap().to_bool().unwrap();
91
        assert_eq!(2, filtered.len());
92

93
        assert_eq!(
94
            vec![true, false],
95
            filtered.bit_buffer().iter().collect_vec()
96
        )
97
    }
98

99
    #[test]
100
    fn filter_bool_by_slice_test() {
101
        let arr = BoolArray::from_iter([true, true, false]);
102

103
        let filtered = filter_slices(arr.bit_buffer(), 2, [(0, 1), (2, 3)].into_iter());
104
        assert_eq!(2, filtered.len());
105

106
        assert_eq!(vec![true, false], filtered.iter().collect_vec())
107
    }
108

109
    #[test]
110
    fn filter_bool_by_index_test() {
111
        let arr = BoolArray::from_iter([true, true, false]);
112

113
        let filtered = filter_indices(arr.bit_buffer(), 2, [0, 2].into_iter());
114
        assert_eq!(2, filtered.len());
115

116
        assert_eq!(vec![true, false], filtered.iter().collect_vec())
117
    }
118

119
    use rstest::rstest;
120

121
    #[rstest]
122
    #[case(BoolArray::from_iter([true, false, true, true, false]))]
123
    #[case(BoolArray::from_iter([Some(true), None, Some(false), Some(true), None]))]
124
    #[case(BoolArray::from_iter([true]))]
125
    #[case(BoolArray::from_iter([false, false]))]
126
    #[case(BoolArray::from_iter((0..100).map(|i| i % 2 == 0)))]
127
    #[case(BoolArray::from_iter((0..1024).map(|i| i % 3 != 0)))]
128
    fn test_filter_bool_conformance(#[case] array: BoolArray) {
129
        test_filter_conformance(array.as_ref());
130
    }
131
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc