Skip to main content

vortex_mask/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! A mask is a set of sorted unique positive integers.
5#![deny(missing_docs)]
6
7mod bitops;
8mod eq;
9mod intersect_by_rank;
10
11#[cfg(test)]
12mod tests;
13
14use std::cmp::Ordering;
15use std::fmt::Debug;
16use std::fmt::Formatter;
17use std::ops::Bound;
18use std::ops::RangeBounds;
19use std::sync::Arc;
20use std::sync::OnceLock;
21
22use itertools::Itertools;
23use vortex_buffer::BitBuffer;
24use vortex_buffer::BitBufferMut;
25use vortex_buffer::BitIterator;
26use vortex_error::VortexResult;
27use vortex_error::vortex_panic;
28
29/// Represents a set of values that are all included, all excluded, or some mixture of both.
30pub enum AllOr<T> {
31    /// All values are included.
32    All,
33    /// No values are included.
34    None,
35    /// Some values are included.
36    Some(T),
37}
38
39impl<T> AllOr<T> {
40    /// Returns the `Some` variant of the enum, or a default value.
41    #[inline]
42    pub fn unwrap_or_else<F, G>(self, all_true: F, all_false: G) -> T
43    where
44        F: FnOnce() -> T,
45        G: FnOnce() -> T,
46    {
47        match self {
48            Self::Some(v) => v,
49            AllOr::All => all_true(),
50            AllOr::None => all_false(),
51        }
52    }
53}
54
55impl<T> AllOr<&T> {
56    /// Clone the inner value.
57    #[inline]
58    pub fn cloned(self) -> AllOr<T>
59    where
60        T: Clone,
61    {
62        match self {
63            Self::All => AllOr::All,
64            Self::None => AllOr::None,
65            Self::Some(v) => AllOr::Some(v.clone()),
66        }
67    }
68}
69
70impl<T> Debug for AllOr<T>
71where
72    T: Debug,
73{
74    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
75        match self {
76            Self::All => f.write_str("All"),
77            Self::None => f.write_str("None"),
78            Self::Some(v) => f.debug_tuple("Some").field(v).finish(),
79        }
80    }
81}
82
83impl<T> PartialEq for AllOr<T>
84where
85    T: PartialEq,
86{
87    fn eq(&self, other: &Self) -> bool {
88        match (self, other) {
89            (Self::All, Self::All) => true,
90            (Self::None, Self::None) => true,
91            (Self::Some(lhs), Self::Some(rhs)) => lhs == rhs,
92            _ => false,
93        }
94    }
95}
96
97impl<T> Eq for AllOr<T> where T: Eq {}
98
99/// Represents a set of sorted unique positive integers.
100/// If a value is included in a Mask, it's valid.
101///
102/// A [`Mask`] can be constructed from various representations, and converted to various
103/// others. Internally, these are cached.
104#[derive(Clone)]
105#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
106pub enum Mask {
107    /// All values are included.
108    AllTrue(usize),
109    /// No values are included.
110    AllFalse(usize),
111    /// Some values are included, represented as a [`BitBuffer`].
112    Values(MaskValuesRef),
113}
114
115impl Debug for Mask {
116    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
117        match self {
118            Self::AllTrue(len) => write!(f, "All true({len})"),
119            Self::AllFalse(len) => write!(f, "All false({len})"),
120            Self::Values(mask) => write!(f, "{mask:?}"),
121        }
122    }
123}
124
125impl Default for Mask {
126    fn default() -> Self {
127        Self::new_true(0)
128    }
129}
130
131/// Represents the values of a [`Mask`] that contains some true and some false elements.
132#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
133pub struct MaskValues {
134    buffer: BitBuffer,
135
136    // We cached the indices and slices representations, since it can be faster than iterating
137    // the bit-mask over and over again.
138    #[cfg_attr(feature = "serde", serde(skip))]
139    indices: OnceLock<Vec<usize>>,
140    #[cfg_attr(feature = "serde", serde(skip))]
141    slices: OnceLock<Vec<(usize, usize)>>,
142
143    // Pre-computed values.
144    true_count: usize,
145    // i.e., the fraction of values that are true
146    density: f64,
147}
148
149/// A shared reference to [`MaskValues`].
150pub type MaskValuesRef = Arc<MaskValues>;
151
152impl Debug for MaskValues {
153    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
154        write!(f, "true_count={}, ", self.true_count)?;
155        write!(f, "density={}, ", self.density)?;
156        if let Some(v) = self.indices.get() {
157            write!(f, "indices={v:?}, ")?;
158        }
159        if let Some(v) = self.slices.get() {
160            write!(f, "slices={v:?}, ")?;
161        }
162        if f.alternate() {
163            f.write_str("\n")?;
164        }
165        write!(f, "{}", self.buffer)
166    }
167}
168
169impl Mask {
170    /// Create a new Mask with the given length.
171    pub fn new(length: usize, value: bool) -> Self {
172        if value {
173            Self::AllTrue(length)
174        } else {
175            Self::AllFalse(length)
176        }
177    }
178
179    /// Create a new Mask where all values are set.
180    #[inline]
181    pub fn new_true(length: usize) -> Self {
182        Self::AllTrue(length)
183    }
184
185    /// Create a new Mask where no values are set.
186    #[inline]
187    pub fn new_false(length: usize) -> Self {
188        Self::AllFalse(length)
189    }
190
191    /// Create a new [`Mask`] from a [`BitBuffer`].
192    pub fn from_buffer(buffer: BitBuffer) -> Self {
193        let len = buffer.len();
194        let true_count = buffer.true_count();
195
196        if true_count == 0 {
197            return Self::AllFalse(len);
198        }
199        if true_count == len {
200            return Self::AllTrue(len);
201        }
202
203        Self::Values(Arc::new(MaskValues {
204            buffer,
205            indices: Default::default(),
206            slices: Default::default(),
207            true_count,
208            density: true_count as f64 / len as f64,
209        }))
210    }
211
212    /// Create a new [`Mask`] from sorted, unique indices.
213    pub fn from_indices(len: usize, indices: impl IntoIterator<Item = usize>) -> Self {
214        let indices = indices.into_iter().collect::<Vec<_>>();
215        assert!(indices.is_sorted(), "Mask indices must be sorted");
216        assert!(
217            indices.windows(2).all(|w| w[0] != w[1]),
218            "Mask indices must be unique"
219        );
220        let buffer = BitBuffer::from_indices(len, indices.iter().copied());
221        debug_assert_eq!(buffer.len(), len);
222        let true_count = buffer.true_count();
223
224        if true_count == 0 {
225            return Self::AllFalse(len);
226        }
227        if true_count == len {
228            return Self::AllTrue(len);
229        }
230
231        Self::Values(Arc::new(MaskValues {
232            buffer,
233            indices: OnceLock::from(indices),
234            slices: Default::default(),
235            true_count,
236            density: true_count as f64 / len as f64,
237        }))
238    }
239
240    /// Create a new [`Mask`] from an [`IntoIterator<Item = usize>`] of indices to be excluded.
241    pub fn from_excluded_indices(len: usize, indices: impl IntoIterator<Item = usize>) -> Self {
242        let mut buf = BitBufferMut::new_set(len);
243
244        let mut false_count: usize = 0;
245        indices.into_iter().for_each(|idx| {
246            buf.unset(idx);
247            false_count += 1;
248        });
249        debug_assert_eq!(buf.len(), len);
250        let true_count = len - false_count;
251
252        // Return optimized variants when appropriate
253        if false_count == 0 {
254            return Self::AllTrue(len);
255        }
256        if false_count == len {
257            return Self::AllFalse(len);
258        }
259
260        Self::Values(Arc::new(MaskValues {
261            buffer: buf.freeze(),
262            indices: Default::default(),
263            slices: Default::default(),
264            true_count,
265            density: true_count as f64 / len as f64,
266        }))
267    }
268
269    /// Create a new [`Mask`] from a [`Vec<(usize, usize)>`] where each range
270    /// represents a contiguous range of true values.
271    pub fn from_slices(len: usize, vec: Vec<(usize, usize)>) -> Self {
272        Self::check_slices(len, &vec);
273        Self::from_slices_unchecked(len, vec)
274    }
275
276    fn from_slices_unchecked(len: usize, slices: Vec<(usize, usize)>) -> Self {
277        #[cfg(debug_assertions)]
278        Self::check_slices(len, &slices);
279
280        let true_count = slices.iter().map(|(b, e)| e - b).sum();
281        if true_count == 0 {
282            return Self::AllFalse(len);
283        }
284        if true_count == len {
285            return Self::AllTrue(len);
286        }
287
288        let mut buf = BitBufferMut::with_capacity(len);
289        let mut cursor = 0;
290        for (start, end) in slices.iter().copied() {
291            buf.append_n(false, start - cursor);
292            buf.append_n(true, end - start);
293            cursor = end;
294        }
295        buf.append_n(false, len - cursor);
296        debug_assert_eq!(buf.len(), len);
297
298        Self::Values(Arc::new(MaskValues {
299            buffer: buf.freeze(),
300            indices: Default::default(),
301            slices: OnceLock::from(slices),
302            true_count,
303            density: true_count as f64 / len as f64,
304        }))
305    }
306
307    #[allow(clippy::inline_always)]
308    #[inline(always)]
309    fn check_slices(len: usize, vec: &[(usize, usize)]) {
310        assert!(vec.iter().all(|&(b, e)| b < e && e <= len));
311        for (first, second) in vec.iter().tuple_windows() {
312            assert!(
313                first.0 < second.0,
314                "Slices must be sorted, got {first:?} and {second:?}"
315            );
316            assert!(
317                first.1 <= second.0,
318                "Slices must be non-overlapping, got {first:?} and {second:?}"
319            );
320        }
321    }
322
323    /// Create a new [`Mask`] from the intersection of two indices slices.
324    pub fn from_intersection_indices(
325        len: usize,
326        lhs: impl Iterator<Item = usize>,
327        rhs: impl Iterator<Item = usize>,
328    ) -> Self {
329        let mut intersection = Vec::with_capacity(len);
330        let mut lhs = lhs.peekable();
331        let mut rhs = rhs.peekable();
332        while let (Some(&l), Some(&r)) = (lhs.peek(), rhs.peek()) {
333            match l.cmp(&r) {
334                Ordering::Less => {
335                    lhs.next();
336                }
337                Ordering::Greater => {
338                    rhs.next();
339                }
340                Ordering::Equal => {
341                    intersection.push(l);
342                    lhs.next();
343                    rhs.next();
344                }
345            }
346        }
347        Self::from_indices(len, intersection)
348    }
349
350    /// Clears the mask of all data. Drops any allocated capacity.
351    pub fn clear(&mut self) {
352        *self = Self::new_false(0);
353    }
354
355    /// Returns the length of the mask (not the number of true values).
356    #[inline]
357    pub fn len(&self) -> usize {
358        match self {
359            Self::AllTrue(len) => *len,
360            Self::AllFalse(len) => *len,
361            Self::Values(values) => values.len(),
362        }
363    }
364
365    /// Returns true if the mask is empty i.e., it's length is 0.
366    #[inline]
367    pub fn is_empty(&self) -> bool {
368        match self {
369            Self::AllTrue(len) => *len == 0,
370            Self::AllFalse(len) => *len == 0,
371            Self::Values(values) => values.is_empty(),
372        }
373    }
374
375    /// Get the true count of the mask.
376    #[inline]
377    pub fn true_count(&self) -> usize {
378        match &self {
379            Self::AllTrue(len) => *len,
380            Self::AllFalse(_) => 0,
381            Self::Values(values) => values.true_count,
382        }
383    }
384
385    /// Get the false count of the mask.
386    #[inline]
387    pub fn false_count(&self) -> usize {
388        match &self {
389            Self::AllTrue(_) => 0,
390            Self::AllFalse(len) => *len,
391            Self::Values(values) => values.buffer.len() - values.true_count,
392        }
393    }
394
395    /// Returns true if all values in the mask are true.
396    #[inline]
397    pub fn all_true(&self) -> bool {
398        match &self {
399            Self::AllTrue(_) => true,
400            Self::AllFalse(0) => true,
401            Self::AllFalse(_) => false,
402            Self::Values(values) => values.buffer.len() == values.true_count,
403        }
404    }
405
406    /// Returns true if all values in the mask are false.
407    #[inline]
408    pub fn all_false(&self) -> bool {
409        self.true_count() == 0
410    }
411
412    /// Return the density of the full mask.
413    #[inline]
414    pub fn density(&self) -> f64 {
415        match &self {
416            Self::AllTrue(_) => 1.0,
417            Self::AllFalse(_) => 0.0,
418            Self::Values(values) => values.density,
419        }
420    }
421
422    /// Returns the boolean value at a given index.
423    ///
424    /// ## Panics
425    ///
426    /// Panics if the index is out of bounds.
427    #[inline]
428    pub fn value(&self, idx: usize) -> bool {
429        match self {
430            Mask::AllTrue(_) => true,
431            Mask::AllFalse(_) => false,
432            Mask::Values(values) => values.buffer.value(idx),
433        }
434    }
435
436    /// Iterate the mask as one `bool` per element, in order.
437    ///
438    /// Unlike repeatedly calling [`Mask::value`], this advances a single cursor rather than
439    /// recomputing the byte/bit offset for every element, and it does not allocate for the
440    /// all-true / all-false variants. Prefer this for sequential per-element scans.
441    #[inline]
442    pub fn iter(&self) -> MaskBoolIter<'_> {
443        match self {
444            Mask::AllTrue(len) => MaskBoolIter::Repeat {
445                value: true,
446                remaining: *len,
447            },
448            Mask::AllFalse(len) => MaskBoolIter::Repeat {
449                value: false,
450                remaining: *len,
451            },
452            Mask::Values(values) => MaskBoolIter::Bits(values.bit_buffer().iter()),
453        }
454    }
455
456    /// Returns the first true index in the mask.
457    pub fn first(&self) -> Option<usize> {
458        match &self {
459            Self::AllTrue(len) => (*len > 0).then_some(0),
460            Self::AllFalse(_) => None,
461            Self::Values(values) => {
462                if let Some(indices) = values.indices.get() {
463                    return indices.first().copied();
464                }
465                if let Some(slices) = values.slices.get() {
466                    return slices.first().map(|(start, _)| *start);
467                }
468                values.buffer.set_indices().next()
469            }
470        }
471    }
472
473    /// Returns the last true index in the mask.
474    pub fn last(&self) -> Option<usize> {
475        match &self {
476            Self::AllTrue(len) => (*len > 0).then_some(*len - 1),
477            Self::AllFalse(_) => None,
478            Self::Values(values) => {
479                if let Some(indices) = values.indices.get() {
480                    return indices.last().copied();
481                }
482                if let Some(slices) = values.slices.get() {
483                    return slices.last().map(|(_, end)| end - 1);
484                }
485
486                if values.true_count == 0 {
487                    return None;
488                }
489
490                Some(
491                    values
492                        .buffer
493                        .select(values.true_count - 1)
494                        .unwrap_or_else(|| {
495                            vortex_panic!(
496                                "Rank {} out of bounds for mask with true count {}",
497                                values.true_count - 1,
498                                values.true_count
499                            )
500                        }),
501                )
502            }
503        }
504    }
505
506    /// Returns the position in the mask of the nth true value.
507    pub fn rank(&self, n: usize) -> usize {
508        if n >= self.true_count() {
509            vortex_panic!(
510                "Rank {n} out of bounds for mask with true count {}",
511                self.true_count()
512            );
513        }
514        match &self {
515            Self::AllTrue(_) => n,
516            Self::AllFalse(_) => unreachable!("no true values in all-false mask"),
517            Self::Values(values) => {
518                if let Some(indices) = values.indices.get() {
519                    return indices[n];
520                }
521
522                values.buffer.select(n).unwrap_or_else(|| {
523                    vortex_panic!(
524                        "Rank {} out of bounds for mask with true count {}",
525                        values.true_count - 1,
526                        values.true_count
527                    )
528                })
529            }
530        }
531    }
532
533    /// Slice the mask.
534    pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
535        let start = match range.start_bound() {
536            Bound::Included(&s) => s,
537            Bound::Excluded(&s) => s + 1,
538            Bound::Unbounded => 0,
539        };
540        let end = match range.end_bound() {
541            Bound::Included(&e) => e + 1,
542            Bound::Excluded(&e) => e,
543            Bound::Unbounded => self.len(),
544        };
545
546        assert!(start <= end);
547        assert!(start <= self.len());
548        assert!(end <= self.len());
549        let len = end - start;
550
551        // Slicing the whole mask is the identity. `Self` is `Arc`-backed, so the clone is cheap
552        // and keeps the cached `indices`/`slices` representations that `from_buffer` would drop.
553        if len == self.len() {
554            return self.clone();
555        }
556
557        match &self {
558            Self::AllTrue(_) => Self::new_true(len),
559            Self::AllFalse(_) => Self::new_false(len),
560            Self::Values(values) => Self::from_buffer(values.buffer.slice(range)),
561        }
562    }
563
564    /// Return the boolean buffer representation of the mask.
565    #[inline]
566    pub fn bit_buffer(&self) -> AllOr<&BitBuffer> {
567        match &self {
568            Self::AllTrue(_) => AllOr::All,
569            Self::AllFalse(_) => AllOr::None,
570            Self::Values(values) => AllOr::Some(&values.buffer),
571        }
572    }
573
574    /// Return a boolean buffer representation of the mask, allocating new buffers for all-true
575    /// and all-false variants.
576    #[inline]
577    pub fn to_bit_buffer(&self) -> BitBuffer {
578        match self {
579            Self::AllTrue(l) => BitBuffer::new_set(*l),
580            Self::AllFalse(l) => BitBuffer::new_unset(*l),
581            Self::Values(values) => values.bit_buffer().clone(),
582        }
583    }
584
585    /// Return a boolean buffer representation of the mask, allocating new buffers for all-true
586    /// and all-false variants.
587    #[inline]
588    pub fn into_bit_buffer(self) -> BitBuffer {
589        match self {
590            Self::AllTrue(l) => BitBuffer::new_set(l),
591            Self::AllFalse(l) => BitBuffer::new_unset(l),
592            Self::Values(values) => Arc::try_unwrap(values)
593                .map(|v| v.into_bit_buffer())
594                .unwrap_or_else(|v| v.bit_buffer().clone()),
595        }
596    }
597
598    /// Return the indices representation of the mask.
599    #[inline]
600    pub fn indices(&self) -> AllOr<&[usize]> {
601        match &self {
602            Self::AllTrue(_) => AllOr::All,
603            Self::AllFalse(_) => AllOr::None,
604            Self::Values(values) => AllOr::Some(values.indices()),
605        }
606    }
607
608    /// Return the slices representation of the mask.
609    #[inline]
610    pub fn slices(&self) -> AllOr<&[(usize, usize)]> {
611        match &self {
612            Self::AllTrue(_) => AllOr::All,
613            Self::AllFalse(_) => AllOr::None,
614            Self::Values(values) => AllOr::Some(values.slices()),
615        }
616    }
617
618    /// Return an iterator over either indices or slices of the mask based on a density threshold.
619    #[inline]
620    pub fn threshold_iter(&self, threshold: f64) -> AllOr<MaskIter<'_>> {
621        match &self {
622            Self::AllTrue(_) => AllOr::All,
623            Self::AllFalse(_) => AllOr::None,
624            Self::Values(values) => AllOr::Some(values.threshold_iter(threshold)),
625        }
626    }
627
628    /// Return [`MaskValues`] if the mask is not all true or all false.
629    #[inline]
630    pub fn values(&self) -> Option<&MaskValues> {
631        if let Self::Values(values) = self {
632            Some(values)
633        } else {
634            None
635        }
636    }
637
638    /// Given monotonically increasing `indices` in [0, n_rows], returns the
639    /// count of valid elements up to each index.
640    ///
641    /// This is O(n_rows), but the per-gap counts are computed with a SIMD
642    /// popcount over the underlying bit buffer rather than walking bit-by-bit.
643    pub fn valid_counts_for_indices(&self, indices: &[usize]) -> Vec<usize> {
644        match self {
645            Self::AllTrue(_) => indices.to_vec(),
646            Self::AllFalse(_) => vec![0; indices.len()],
647            Self::Values(values) => {
648                let buffer = values.bit_buffer();
649                let mut valid_counts = Vec::with_capacity(indices.len());
650                let mut valid_count = 0;
651                let mut prev = 0;
652                for &next_idx in indices {
653                    assert!(next_idx <= buffer.len(), "Row indices exceed array length");
654                    // `indices` is monotonically increasing, so each gap is counted once;
655                    // the total work across all gaps scans the prefix `[0, last_idx)` once.
656                    if next_idx > prev {
657                        valid_count += buffer.count_range(prev, next_idx);
658                        prev = next_idx;
659                    }
660                    valid_counts.push(valid_count);
661                }
662
663                valid_counts
664            }
665        }
666    }
667
668    /// Limit the mask to the first `limit` true values
669    pub fn limit(self, limit: usize) -> Self {
670        // Early return optimization: if we're asking for more true values than the total
671        // length of the mask, then even if all values were true, we couldn't exceed the
672        // limit, so return the original mask unchanged.
673        if self.len() <= limit {
674            return self;
675        }
676
677        match &self {
678            Mask::AllTrue(len) => {
679                Self::from_iter([Self::new_true(limit), Self::new_false(len - limit)])
680            }
681            Mask::AllFalse(_) => self,
682            Mask::Values(mask_values) => {
683                if limit >= mask_values.true_count() {
684                    return self;
685                }
686
687                let existing_buffer = mask_values.bit_buffer();
688
689                let mut new_buffer_builder = BitBufferMut::new_unset(mask_values.len());
690                debug_assert!(limit < mask_values.len());
691
692                for index in existing_buffer.set_indices().take(limit) {
693                    // SAFETY: We checked that `limit` was less than the mask values length,
694                    // therefore `index` must be within the bounds of the bit buffer.
695                    unsafe { new_buffer_builder.set_unchecked(index) }
696                }
697
698                Self::from(new_buffer_builder.freeze())
699            }
700        }
701    }
702
703    /// Concatenate multiple masks together into a single mask.
704    pub fn concat<'a>(masks: impl Iterator<Item = &'a Self>) -> VortexResult<Self> {
705        let masks: Vec<_> = masks.collect();
706        let len = masks.iter().map(|t| t.len()).sum();
707
708        if masks.iter().all(|t| t.all_true()) {
709            return Ok(Mask::AllTrue(len));
710        }
711
712        if masks.iter().all(|t| t.all_false()) {
713            return Ok(Mask::AllFalse(len));
714        }
715
716        let mut builder = BitBufferMut::with_capacity(len);
717
718        for mask in masks {
719            match mask {
720                Mask::AllTrue(n) => builder.append_n(true, *n),
721                Mask::AllFalse(n) => builder.append_n(false, *n),
722                Mask::Values(v) => builder.append_buffer(v.bit_buffer()),
723            }
724        }
725
726        Ok(Mask::from_buffer(builder.freeze()))
727    }
728}
729
730impl MaskValues {
731    /// Returns the length of the mask.
732    #[inline]
733    pub fn len(&self) -> usize {
734        self.buffer.len()
735    }
736
737    /// Returns true if the mask is empty i.e., it's length is 0.
738    #[inline]
739    pub fn is_empty(&self) -> bool {
740        self.buffer.is_empty()
741    }
742
743    /// Returns the density of the mask.
744    #[inline]
745    pub fn density(&self) -> f64 {
746        self.density
747    }
748
749    /// Returns the true count of the mask.
750    #[inline]
751    pub fn true_count(&self) -> usize {
752        self.true_count
753    }
754
755    /// Returns the boolean buffer representation of the mask.
756    #[inline]
757    pub fn bit_buffer(&self) -> &BitBuffer {
758        &self.buffer
759    }
760
761    /// Returns the boolean buffer representation of the mask.
762    #[inline]
763    pub fn into_bit_buffer(self) -> BitBuffer {
764        self.buffer
765    }
766
767    /// Returns the boolean value at a given index.
768    #[inline]
769    pub fn value(&self, index: usize) -> bool {
770        self.buffer.value(index)
771    }
772
773    /// Constructs an indices vector from one of the other representations.
774    pub fn indices(&self) -> &[usize] {
775        self.indices.get_or_init(|| {
776            if self.true_count == 0 {
777                return vec![];
778            }
779
780            if self.true_count == self.len() {
781                return (0..self.len()).collect();
782            }
783
784            if let Some(slices) = self.slices.get() {
785                let mut indices = Vec::with_capacity(self.true_count);
786                indices.extend(slices.iter().flat_map(|(start, end)| *start..*end));
787                debug_assert!(indices.is_sorted());
788                assert_eq!(indices.len(), self.true_count);
789                return indices;
790            }
791
792            let mut indices = Vec::with_capacity(self.true_count);
793            // Word-at-a-time set-bit walk; faster than collecting `set_indices()`,
794            // whose per-`next` iterator state inlines less well (see
795            // `vortex-mask/benches/mask_iteration.rs`).
796            self.buffer.for_each_set_index(|i| indices.push(i));
797            debug_assert!(indices.is_sorted());
798            assert_eq!(indices.len(), self.true_count);
799            indices
800        })
801    }
802
803    /// Returns cached index positions when this mask already has them materialized.
804    ///
805    /// Unlike [`Self::indices`], this does not build the index vector from another
806    /// representation.
807    #[inline]
808    pub fn cached_indices(&self) -> Option<&[usize]> {
809        self.indices.get().map(Vec::as_slice)
810    }
811
812    /// Constructs a slices vector from one of the other representations.
813    #[inline]
814    pub fn slices(&self) -> &[(usize, usize)] {
815        self.slices.get_or_init(|| {
816            if self.true_count == self.len() {
817                return vec![(0, self.len())];
818            }
819
820            self.buffer.set_slices().collect()
821        })
822    }
823
824    /// Returns cached true-value ranges when this mask already has them materialized.
825    ///
826    /// Unlike [`Self::slices`], this does not build the slice vector from another
827    /// representation.
828    #[inline]
829    pub fn cached_slices(&self) -> Option<&[(usize, usize)]> {
830        self.slices.get().map(Vec::as_slice)
831    }
832
833    /// Return an iterator over either indices or slices of the mask based on a density threshold.
834    #[inline]
835    pub fn threshold_iter(&self, threshold: f64) -> MaskIter<'_> {
836        if self.density >= threshold {
837            MaskIter::Slices(self.slices())
838        } else {
839            MaskIter::Indices(self.indices())
840        }
841    }
842}
843
844/// Iterator over the indices or slices of a mask.
845pub enum MaskIter<'a> {
846    /// Slice of pre-cached indices of a mask.
847    Indices(&'a [usize]),
848    /// Slice of pre-cached slices of a mask.
849    Slices(&'a [(usize, usize)]),
850}
851
852/// Iterator yielding one `bool` per element of a [`Mask`], in order.
853///
854/// Created by [`Mask::iter`].
855pub enum MaskBoolIter<'a> {
856    /// An all-true or all-false run.
857    Repeat {
858        /// The constant value yielded by every element of the run.
859        value: bool,
860        /// The number of elements still to yield.
861        remaining: usize,
862    },
863    /// Per-element bits of a [`Mask::Values`] mask.
864    Bits(BitIterator<'a>),
865}
866
867impl Iterator for MaskBoolIter<'_> {
868    type Item = bool;
869
870    #[inline]
871    fn next(&mut self) -> Option<Self::Item> {
872        match self {
873            Self::Repeat { remaining: 0, .. } => None,
874            Self::Repeat { value, remaining } => {
875                *remaining -= 1;
876                Some(*value)
877            }
878            Self::Bits(bits) => bits.next(),
879        }
880    }
881
882    #[inline]
883    fn size_hint(&self) -> (usize, Option<usize>) {
884        let remaining = match self {
885            Self::Repeat { remaining, .. } => *remaining,
886            Self::Bits(bits) => bits.len(),
887        };
888        (remaining, Some(remaining))
889    }
890}
891
892impl ExactSizeIterator for MaskBoolIter<'_> {}
893
894impl From<BitBuffer> for Mask {
895    fn from(value: BitBuffer) -> Self {
896        Self::from_buffer(value)
897    }
898}
899
900impl FromIterator<bool> for Mask {
901    #[inline]
902    fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
903        Self::from_buffer(BitBuffer::from_iter(iter))
904    }
905}
906
907impl FromIterator<Mask> for Mask {
908    fn from_iter<T: IntoIterator<Item = Mask>>(iter: T) -> Self {
909        let masks = iter
910            .into_iter()
911            .filter(|m| !m.is_empty())
912            .collect::<Vec<_>>();
913        let total_length = masks.iter().map(|v| v.len()).sum();
914
915        // If they're all valid, then return a single validity.
916        if masks.iter().all(|v| v.all_true()) {
917            return Self::AllTrue(total_length);
918        }
919        // If they're all invalid, then return a single invalidity.
920        if masks.iter().all(|v| v.all_false()) {
921            return Self::AllFalse(total_length);
922        }
923
924        // Else, construct the boolean buffer
925        let mut buffer = BitBufferMut::with_capacity(total_length);
926        for mask in masks {
927            match mask {
928                Mask::AllTrue(count) => buffer.append_n(true, count),
929                Mask::AllFalse(count) => buffer.append_n(false, count),
930                Mask::Values(values) => {
931                    buffer.append_buffer(values.bit_buffer());
932                }
933            };
934        }
935        Self::from_buffer(buffer.freeze())
936    }
937}