Skip to main content

lance_select/
mask.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4use std::collections::HashSet;
5use std::io::Write;
6use std::ops::{Range, RangeBounds, RangeInclusive};
7use std::{collections::BTreeMap, io::Read};
8
9use arrow_array::{Array, BinaryArray, GenericBinaryArray};
10use arrow_buffer::{Buffer, NullBuffer, OffsetBuffer};
11use byteorder::{ReadBytesExt, WriteBytesExt};
12use deepsize::DeepSizeOf;
13use itertools::Itertools;
14use roaring::{MultiOps, RoaringBitmap, RoaringTreemap};
15
16use lance_core::cache::CacheCodecImpl;
17use lance_core::utils::address::RowAddress;
18use lance_core::{Error, Result};
19
20mod nullable;
21
22pub use nullable::{NullableRowAddrMask, NullableRowAddrSet};
23
24/// A mask that selects or deselects rows based on an allow-list or block-list.
25#[derive(Clone, Debug, DeepSizeOf, PartialEq)]
26pub enum RowAddrMask {
27    AllowList(RowAddrTreeMap),
28    BlockList(RowAddrTreeMap),
29}
30
31impl Default for RowAddrMask {
32    fn default() -> Self {
33        // Empty block list means all rows are allowed
34        Self::BlockList(RowAddrTreeMap::new())
35    }
36}
37
38impl RowAddrMask {
39    // Create a mask allowing all rows, this is an alias for [default]
40    pub fn all_rows() -> Self {
41        Self::default()
42    }
43
44    // Create a mask that doesn't allow anything
45    pub fn allow_nothing() -> Self {
46        Self::AllowList(RowAddrTreeMap::new())
47    }
48
49    // Create a mask from an allow list
50    pub fn from_allowed(allow_list: RowAddrTreeMap) -> Self {
51        Self::AllowList(allow_list)
52    }
53
54    // Create a mask from a block list
55    pub fn from_block(block_list: RowAddrTreeMap) -> Self {
56        Self::BlockList(block_list)
57    }
58
59    pub fn block_list(&self) -> Option<&RowAddrTreeMap> {
60        match self {
61            Self::BlockList(block_list) => Some(block_list),
62            _ => None,
63        }
64    }
65
66    pub fn allow_list(&self) -> Option<&RowAddrTreeMap> {
67        match self {
68            Self::AllowList(allow_list) => Some(allow_list),
69            _ => None,
70        }
71    }
72
73    /// True if the row_id is selected by the mask, false otherwise
74    pub fn selected(&self, row_id: u64) -> bool {
75        match self {
76            Self::AllowList(allow_list) => allow_list.contains(row_id),
77            Self::BlockList(block_list) => !block_list.contains(row_id),
78        }
79    }
80
81    /// Return the indices of the input row ids that were valid
82    pub fn selected_indices<'a>(&self, row_ids: impl Iterator<Item = &'a u64> + 'a) -> Vec<u64> {
83        row_ids
84            .enumerate()
85            .filter_map(|(idx, row_id)| {
86                if self.selected(*row_id) {
87                    Some(idx as u64)
88                } else {
89                    None
90                }
91            })
92            .collect()
93    }
94
95    /// Also block the given addrs
96    pub fn also_block(self, block_list: RowAddrTreeMap) -> Self {
97        match self {
98            Self::AllowList(allow_list) => Self::AllowList(allow_list - block_list),
99            Self::BlockList(existing) => Self::BlockList(existing | block_list),
100        }
101    }
102
103    /// Also allow the given addrs
104    pub fn also_allow(self, allow_list: RowAddrTreeMap) -> Self {
105        match self {
106            Self::AllowList(existing) => Self::AllowList(existing | allow_list),
107            Self::BlockList(block_list) => Self::BlockList(block_list - allow_list),
108        }
109    }
110
111    /// Convert a mask into an arrow array
112    ///
113    /// A row addr mask is not very arrow-compatible.  We can't make it a batch with
114    /// two columns because the block list and allow list will have different lengths.  Also,
115    /// there is no Arrow type for compressed bitmaps.
116    ///
117    /// However, we need to shove it into some kind of Arrow container to pass it along the
118    /// datafusion stream.  Perhaps, in the future, we can add row addr masks as first class
119    /// types in datafusion, and this can be passed along as a mask / selection vector.
120    ///
121    /// We serialize this as a variable length binary array with two items.  The first item
122    /// is the block list and the second item is the allow list.
123    pub fn into_arrow(&self) -> Result<BinaryArray> {
124        // NOTE: This serialization format must be stable as it is used in IPC.
125        let (block_list, allow_list) = match self {
126            Self::AllowList(allow_list) => (None, Some(allow_list)),
127            Self::BlockList(block_list) => (Some(block_list), None),
128        };
129
130        let block_list_length = block_list
131            .as_ref()
132            .map(|bl| bl.serialized_size())
133            .unwrap_or(0);
134        let allow_list_length = allow_list
135            .as_ref()
136            .map(|al| al.serialized_size())
137            .unwrap_or(0);
138        let lengths = vec![block_list_length, allow_list_length];
139        let offsets = OffsetBuffer::from_lengths(lengths);
140        let mut value_bytes = vec![0; block_list_length + allow_list_length];
141        let mut validity = vec![false, false];
142        if let Some(block_list) = &block_list {
143            validity[0] = true;
144            block_list.serialize_into(&mut value_bytes[0..])?;
145        }
146        if let Some(allow_list) = &allow_list {
147            validity[1] = true;
148            allow_list.serialize_into(&mut value_bytes[block_list_length..])?;
149        }
150        let values = Buffer::from(value_bytes);
151        let nulls = NullBuffer::from(validity);
152        Ok(BinaryArray::try_new(offsets, values, Some(nulls))?)
153    }
154
155    /// Deserialize a row address mask from Arrow
156    pub fn from_arrow(array: &GenericBinaryArray<i32>) -> Result<Self> {
157        let block_list = if array.is_null(0) {
158            None
159        } else {
160            Some(RowAddrTreeMap::deserialize_from(array.value(0)))
161        }
162        .transpose()?;
163
164        let allow_list = if array.is_null(1) {
165            None
166        } else {
167            Some(RowAddrTreeMap::deserialize_from(array.value(1)))
168        }
169        .transpose()?;
170
171        let res = match (block_list, allow_list) {
172            (Some(bl), None) => Self::BlockList(bl),
173            (None, Some(al)) => Self::AllowList(al),
174            (Some(block), Some(allow)) => Self::AllowList(allow).also_block(block),
175            (None, None) => Self::all_rows(),
176        };
177        Ok(res)
178    }
179
180    /// Return the maximum number of row addresses that could be selected by this mask
181    ///
182    /// Will be None if this is a BlockList (unbounded)
183    pub fn max_len(&self) -> Option<u64> {
184        match self {
185            Self::AllowList(selection) => selection.len(),
186            Self::BlockList(_) => None,
187        }
188    }
189
190    /// Iterate over the row addresses that are selected by the mask
191    ///
192    /// This is only possible if this is an AllowList and the maps don't contain
193    /// any "full fragment" blocks.
194    pub fn iter_addrs(&self) -> Option<Box<dyn Iterator<Item = RowAddress> + '_>> {
195        match self {
196            Self::AllowList(allow_list) => {
197                if let Some(allow_iter) = allow_list.row_addrs() {
198                    Some(Box::new(allow_iter))
199                } else {
200                    None
201                }
202            }
203            Self::BlockList(_) => None, // Can't iterate over block list
204        }
205    }
206}
207
208impl std::ops::Not for RowAddrMask {
209    type Output = Self;
210
211    fn not(self) -> Self::Output {
212        match self {
213            Self::AllowList(allow_list) => Self::BlockList(allow_list),
214            Self::BlockList(block_list) => Self::AllowList(block_list),
215        }
216    }
217}
218
219impl std::ops::BitAnd for RowAddrMask {
220    type Output = Self;
221
222    fn bitand(self, rhs: Self) -> Self::Output {
223        match (self, rhs) {
224            (Self::AllowList(a), Self::AllowList(b)) => Self::AllowList(a & b),
225            (Self::AllowList(allow), Self::BlockList(block))
226            | (Self::BlockList(block), Self::AllowList(allow)) => Self::AllowList(allow - block),
227            (Self::BlockList(a), Self::BlockList(b)) => Self::BlockList(a | b),
228        }
229    }
230}
231
232impl std::ops::BitOr for RowAddrMask {
233    type Output = Self;
234
235    fn bitor(self, rhs: Self) -> Self::Output {
236        match (self, rhs) {
237            (Self::AllowList(a), Self::AllowList(b)) => Self::AllowList(a | b),
238            (Self::AllowList(allow), Self::BlockList(block))
239            | (Self::BlockList(block), Self::AllowList(allow)) => Self::BlockList(block - allow),
240            (Self::BlockList(a), Self::BlockList(b)) => Self::BlockList(a & b),
241        }
242    }
243}
244
245/// Common operations over a set of rows (either row ids or row addresses).
246///
247/// The concrete representation can be address-based (`RowAddrTreeMap`) or
248/// id-based (for example a future `RowIdSet`), but the semantics are the same:
249/// a set of unique rows.
250pub trait RowSetOps: Clone + Sized {
251    /// Logical row handle (`u64` for both row ids and row addresses).
252    type Row;
253
254    /// Returns true if the set is empty.
255    fn is_empty(&self) -> bool;
256
257    /// Returns the number of rows in the set, if it is known.
258    ///
259    /// Implementations that cannot always compute an exact size (for example
260    /// because of "full fragment" markers) should return `None`.
261    fn len(&self) -> Option<u64>;
262
263    /// Remove a value from the row set.
264    fn remove(&mut self, row: Self::Row) -> bool;
265
266    /// Returns whether this set contains the given row.
267    fn contains(&self, row: Self::Row) -> bool;
268
269    /// Returns the union of `other` and init self.
270    fn union_all(other: &[&Self]) -> Self;
271
272    /// Builds a row set from an iterator of rows.
273    fn from_sorted_iter<I>(iter: I) -> Result<Self>
274    where
275        I: IntoIterator<Item = Self::Row>;
276}
277
278/// A collection of row addresses.
279///
280/// Note: For stable row id mode, this may be split into a separate structure in the future.
281///
282/// These row ids may either be stable-style (where they can be an incrementing
283/// u64 sequence) or address style, where they are a fragment id and a row offset.
284/// When address style, this supports setting entire fragments as selected,
285/// without needing to enumerate all the ids in the fragment.
286///
287/// This is similar to a [RoaringTreemap] but it is optimized for the case where
288/// entire fragments are selected or deselected.
289#[derive(Clone, Debug, Default, PartialEq, DeepSizeOf)]
290pub struct RowAddrTreeMap {
291    /// The contents of the set. If there is a pair (k, Full) then the entire
292    /// fragment k is selected. If there is a pair (k, Partial(v)) then the
293    /// fragment k has the selected rows in v.
294    inner: BTreeMap<u32, RowAddrSelection>,
295}
296
297#[derive(Clone, Debug, PartialEq)]
298pub enum RowAddrSelection {
299    Full,
300    Partial(RoaringBitmap),
301}
302
303impl DeepSizeOf for RowAddrSelection {
304    fn deep_size_of_children(&self, _context: &mut deepsize::Context) -> usize {
305        match self {
306            Self::Full => 0,
307            Self::Partial(bitmap) => bitmap.serialized_size(),
308        }
309    }
310}
311
312impl RowAddrSelection {
313    fn union_all(selections: &[&Self]) -> Self {
314        let mut is_full = false;
315
316        let res = Self::Partial(
317            selections
318                .iter()
319                .filter_map(|selection| match selection {
320                    Self::Full => {
321                        is_full = true;
322                        None
323                    }
324                    Self::Partial(bitmap) => Some(bitmap),
325                })
326                .union(),
327        );
328
329        if is_full { Self::Full } else { res }
330    }
331}
332
333impl RowSetOps for RowAddrTreeMap {
334    type Row = u64;
335
336    fn is_empty(&self) -> bool {
337        self.inner.is_empty()
338    }
339
340    fn len(&self) -> Option<u64> {
341        self.inner
342            .values()
343            .map(|row_addr_selection| match row_addr_selection {
344                RowAddrSelection::Full => None,
345                RowAddrSelection::Partial(indices) => Some(indices.len()),
346            })
347            .try_fold(0_u64, |acc, next| next.map(|next| next + acc))
348    }
349
350    fn remove(&mut self, row: Self::Row) -> bool {
351        let upper = (row >> 32) as u32;
352        let lower = row as u32;
353        match self.inner.get_mut(&upper) {
354            None => false,
355            Some(RowAddrSelection::Full) => {
356                let mut set = RoaringBitmap::full();
357                set.remove(lower);
358                self.inner.insert(upper, RowAddrSelection::Partial(set));
359                true
360            }
361            Some(RowAddrSelection::Partial(lower_set)) => {
362                let removed = lower_set.remove(lower);
363                if lower_set.is_empty() {
364                    self.inner.remove(&upper);
365                }
366                removed
367            }
368        }
369    }
370
371    fn contains(&self, row: Self::Row) -> bool {
372        let upper = (row >> 32) as u32;
373        let lower = row as u32;
374        match self.inner.get(&upper) {
375            None => false,
376            Some(RowAddrSelection::Full) => true,
377            Some(RowAddrSelection::Partial(fragment_set)) => fragment_set.contains(lower),
378        }
379    }
380
381    fn union_all(other: &[&Self]) -> Self {
382        let mut new_map = BTreeMap::new();
383
384        for map in other {
385            for (fragment, selection) in &map.inner {
386                new_map
387                    .entry(fragment)
388                    // I hate this allocation, but I can't think of a better way
389                    .or_insert_with(|| Vec::with_capacity(other.len()))
390                    .push(selection);
391            }
392        }
393
394        let new_map = new_map
395            .into_iter()
396            .map(|(&fragment, selections)| (fragment, RowAddrSelection::union_all(&selections)))
397            .collect();
398
399        Self { inner: new_map }
400    }
401
402    #[track_caller]
403    fn from_sorted_iter<I>(iter: I) -> Result<Self>
404    where
405        I: IntoIterator<Item = Self::Row>,
406    {
407        let mut iter = iter.into_iter().peekable();
408        let mut inner = BTreeMap::new();
409
410        while let Some(row_id) = iter.peek() {
411            let fragment_id = (row_id >> 32) as u32;
412            let next_bitmap_iter = iter
413                .peeking_take_while(|row_id| (row_id >> 32) as u32 == fragment_id)
414                .map(|row_id| row_id as u32);
415            let Ok(bitmap) = RoaringBitmap::from_sorted_iter(next_bitmap_iter) else {
416                return Err(Error::internal(
417                    "RowAddrTreeMap::from_sorted_iter called with non-sorted input",
418                ));
419            };
420            inner.insert(fragment_id, RowAddrSelection::Partial(bitmap));
421        }
422
423        Ok(Self { inner })
424    }
425}
426
427impl RowAddrTreeMap {
428    /// Create an empty set
429    pub fn new() -> Self {
430        Self::default()
431    }
432
433    /// An iterator of row addrs
434    ///
435    /// If there are any "full fragment" items then this can't be calculated and None
436    /// is returned
437    pub fn row_addrs(&self) -> Option<impl Iterator<Item = RowAddress> + '_> {
438        let inner_iters = self
439            .inner
440            .iter()
441            .filter_map(|(frag_id, row_addr_selection)| match row_addr_selection {
442                RowAddrSelection::Full => None,
443                RowAddrSelection::Partial(bitmap) => Some(
444                    bitmap
445                        .iter()
446                        .map(|row_offset| RowAddress::new_from_parts(*frag_id, row_offset)),
447                ),
448            })
449            .collect::<Vec<_>>();
450        if inner_iters.len() != self.inner.len() {
451            None
452        } else {
453            Some(inner_iters.into_iter().flatten())
454        }
455    }
456
457    /// Insert a single value into the set
458    ///
459    /// Returns true if the value was not already in the set.
460    ///
461    /// ```rust
462    /// use lance_select::{RowAddrTreeMap, RowSetOps};
463    ///
464    /// let mut set = RowAddrTreeMap::new();
465    /// assert_eq!(set.insert(10), true);
466    /// assert_eq!(set.insert(10), false);
467    /// assert_eq!(set.contains(10), true);
468    /// ```
469    pub fn insert(&mut self, value: u64) -> bool {
470        let fragment = (value >> 32) as u32;
471        let row_addr = value as u32;
472        match self.inner.get_mut(&fragment) {
473            None => {
474                let mut set = RoaringBitmap::new();
475                set.insert(row_addr);
476                self.inner.insert(fragment, RowAddrSelection::Partial(set));
477                true
478            }
479            Some(RowAddrSelection::Full) => false,
480            Some(RowAddrSelection::Partial(set)) => set.insert(row_addr),
481        }
482    }
483
484    /// Insert a range of values into the set
485    pub fn insert_range<R: RangeBounds<u64>>(&mut self, range: R) -> u64 {
486        // Separate the start and end into high and low bits.
487        let (mut start_high, mut start_low) = match range.start_bound() {
488            std::ops::Bound::Included(&start) => ((start >> 32) as u32, start as u32),
489            std::ops::Bound::Excluded(&start) => {
490                let start = start.saturating_add(1);
491                ((start >> 32) as u32, start as u32)
492            }
493            std::ops::Bound::Unbounded => (0, 0),
494        };
495
496        let (end_high, end_low) = match range.end_bound() {
497            std::ops::Bound::Included(&end) => ((end >> 32) as u32, end as u32),
498            std::ops::Bound::Excluded(&end) => {
499                let end = end.saturating_sub(1);
500                ((end >> 32) as u32, end as u32)
501            }
502            std::ops::Bound::Unbounded => (u32::MAX, u32::MAX),
503        };
504
505        let mut count = 0;
506
507        while start_high <= end_high {
508            let start = start_low;
509            let end = if start_high == end_high {
510                end_low
511            } else {
512                u32::MAX
513            };
514            let fragment = start_high;
515            match self.inner.get_mut(&fragment) {
516                None => {
517                    let mut set = RoaringBitmap::new();
518                    count += set.insert_range(start..=end);
519                    self.inner.insert(fragment, RowAddrSelection::Partial(set));
520                }
521                Some(RowAddrSelection::Full) => {}
522                Some(RowAddrSelection::Partial(set)) => {
523                    count += set.insert_range(start..=end);
524                }
525            }
526            start_high += 1;
527            start_low = 0;
528        }
529
530        count
531    }
532
533    /// Add a bitmap for a single fragment
534    pub fn insert_bitmap(&mut self, fragment: u32, bitmap: RoaringBitmap) {
535        self.inner
536            .insert(fragment, RowAddrSelection::Partial(bitmap));
537    }
538
539    /// Add a whole fragment to the set
540    pub fn insert_fragment(&mut self, fragment_id: u32) {
541        self.inner.insert(fragment_id, RowAddrSelection::Full);
542    }
543
544    pub fn get_fragment_bitmap(&self, fragment_id: u32) -> Option<&RoaringBitmap> {
545        match self.inner.get(&fragment_id) {
546            None => None,
547            Some(RowAddrSelection::Full) => None,
548            Some(RowAddrSelection::Partial(set)) => Some(set),
549        }
550    }
551
552    /// Get the selection for a fragment
553    pub fn get(&self, fragment_id: &u32) -> Option<&RowAddrSelection> {
554        self.inner.get(fragment_id)
555    }
556
557    /// Iterate over (fragment_id, selection) pairs
558    pub fn iter(&self) -> impl Iterator<Item = (&u32, &RowAddrSelection)> {
559        self.inner.iter()
560    }
561
562    pub fn retain_fragments(&mut self, frag_ids: impl IntoIterator<Item = u32>) {
563        let frag_id_set = frag_ids.into_iter().collect::<HashSet<_>>();
564        self.inner
565            .retain(|frag_id, _| frag_id_set.contains(frag_id));
566    }
567
568    /// Compute the serialized size of the set.
569    pub fn serialized_size(&self) -> usize {
570        // Starts at 4 because of the u32 num_entries
571        let mut size = 4;
572        for set in self.inner.values() {
573            // Each entry is 8 bytes for the fragment id and the bitmap size
574            size += 8;
575            if let RowAddrSelection::Partial(set) = set {
576                size += set.serialized_size();
577            }
578        }
579        size
580    }
581
582    /// Serialize the set into the given buffer
583    ///
584    /// The serialization format is stable and used for index serialization
585    ///
586    /// The serialization format is:
587    /// * u32: num_entries
588    ///
589    /// for each entry:
590    ///   * u32: fragment_id
591    ///   * u32: bitmap size
592    ///   * \[u8\]: bitmap
593    ///
594    /// If bitmap size is zero then the entire fragment is selected.
595    pub fn serialize_into<W: Write>(&self, mut writer: W) -> Result<()> {
596        writer.write_u32::<byteorder::LittleEndian>(self.inner.len() as u32)?;
597        for (fragment, set) in &self.inner {
598            writer.write_u32::<byteorder::LittleEndian>(*fragment)?;
599            if let RowAddrSelection::Partial(set) = set {
600                writer.write_u32::<byteorder::LittleEndian>(set.serialized_size() as u32)?;
601                set.serialize_into(&mut writer)?;
602            } else {
603                writer.write_u32::<byteorder::LittleEndian>(0)?;
604            }
605        }
606        Ok(())
607    }
608
609    /// Deserialize the set from the given buffer
610    pub fn deserialize_from<R: Read>(mut reader: R) -> Result<Self> {
611        let num_entries = reader.read_u32::<byteorder::LittleEndian>()?;
612        let mut inner = BTreeMap::new();
613        for _ in 0..num_entries {
614            let fragment = reader.read_u32::<byteorder::LittleEndian>()?;
615            let bitmap_size = reader.read_u32::<byteorder::LittleEndian>()?;
616            if bitmap_size == 0 {
617                inner.insert(fragment, RowAddrSelection::Full);
618            } else {
619                let mut buffer = vec![0; bitmap_size as usize];
620                reader.read_exact(&mut buffer)?;
621                let set = RoaringBitmap::deserialize_from(&buffer[..])?;
622                inner.insert(fragment, RowAddrSelection::Partial(set));
623            }
624        }
625        Ok(Self { inner })
626    }
627
628    /// Apply a mask to the row addrs
629    ///
630    /// For AllowList: only keep rows that are in the selection and not null
631    /// For BlockList: remove rows that are blocked (not null) and remove nulls
632    pub fn mask(&mut self, mask: &RowAddrMask) {
633        match mask {
634            RowAddrMask::AllowList(allow_list) => {
635                *self &= allow_list;
636            }
637            RowAddrMask::BlockList(block_list) => {
638                *self -= block_list;
639            }
640        }
641    }
642
643    /// Convert the set into an iterator of row addrs
644    ///
645    /// # Safety
646    ///
647    /// This is unsafe because if any of the inner RowAddrSelection elements
648    /// is not a Partial then the iterator will panic because we don't know
649    /// the size of the bitmap.
650    pub unsafe fn into_addr_iter(self) -> impl Iterator<Item = u64> {
651        self.inner
652            .into_iter()
653            .flat_map(|(fragment, selection)| match selection {
654                RowAddrSelection::Full => panic!("Size of full fragment is unknown"),
655                RowAddrSelection::Partial(bitmap) => bitmap.into_iter().map(move |val| {
656                    let fragment = fragment as u64;
657                    let row_offset = val as u64;
658                    (fragment << 32) | row_offset
659                }),
660            })
661    }
662
663    /// Iterate the selected row addresses as `(fragment_id, run)` pairs.
664    ///
665    /// Range-shaped counterpart to [`Self::into_addr_iter`]. A contiguous
666    /// run of N selected rows yields one item, not N. Uses roaring's
667    /// `Iter::next_range`, which walks each underlying container's runs
668    /// rather than its individual bits, so dense ranges cost
669    /// O(num_containers) (roughly num_rows / 65536) instead of O(num_rows).
670    ///
671    /// # Safety
672    /// Same contract as [`Self::into_addr_iter`]: panics if any entry is
673    /// `Full`, since the fragment size is unknown at this layer.
674    pub unsafe fn iter_runs(&self) -> impl Iterator<Item = (u32, RangeInclusive<u32>)> + '_ {
675        self.inner
676            .iter()
677            .flat_map(|(&fragment, selection)| match selection {
678                RowAddrSelection::Full => panic!("Size of full fragment is unknown"),
679                RowAddrSelection::Partial(bitmap) => {
680                    let mut iter = bitmap.iter();
681                    std::iter::from_fn(move || iter.next_range().map(|r| (fragment, r)))
682                }
683            })
684    }
685}
686
687impl CacheCodecImpl for RowAddrTreeMap {
688    fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
689        self.serialize_into(writer)
690    }
691
692    fn deserialize(data: &bytes::Bytes) -> Result<Self> {
693        Self::deserialize_from(data.as_ref())
694    }
695}
696
697impl std::ops::BitOr<Self> for RowAddrTreeMap {
698    type Output = Self;
699
700    fn bitor(mut self, rhs: Self) -> Self::Output {
701        self |= rhs;
702        self
703    }
704}
705
706impl std::ops::BitOr<&Self> for RowAddrTreeMap {
707    type Output = Self;
708
709    fn bitor(mut self, rhs: &Self) -> Self::Output {
710        self |= rhs;
711        self
712    }
713}
714
715impl std::ops::BitOrAssign<Self> for RowAddrTreeMap {
716    fn bitor_assign(&mut self, rhs: Self) {
717        *self |= &rhs;
718    }
719}
720
721impl std::ops::BitOrAssign<&Self> for RowAddrTreeMap {
722    fn bitor_assign(&mut self, rhs: &Self) {
723        for (fragment, rhs_set) in &rhs.inner {
724            let lhs_set = self.inner.get_mut(fragment);
725            if let Some(lhs_set) = lhs_set {
726                match lhs_set {
727                    RowAddrSelection::Full => {
728                        // If the fragment is already selected then there is nothing to do
729                    }
730                    RowAddrSelection::Partial(lhs_bitmap) => match rhs_set {
731                        RowAddrSelection::Full => {
732                            *lhs_set = RowAddrSelection::Full;
733                        }
734                        RowAddrSelection::Partial(rhs_set) => {
735                            *lhs_bitmap |= rhs_set;
736                        }
737                    },
738                }
739            } else {
740                self.inner.insert(*fragment, rhs_set.clone());
741            }
742        }
743    }
744}
745
746impl std::ops::BitAnd<Self> for RowAddrTreeMap {
747    type Output = Self;
748
749    fn bitand(mut self, rhs: Self) -> Self::Output {
750        self &= &rhs;
751        self
752    }
753}
754
755impl std::ops::BitAnd<&Self> for RowAddrTreeMap {
756    type Output = Self;
757
758    fn bitand(mut self, rhs: &Self) -> Self::Output {
759        self &= rhs;
760        self
761    }
762}
763
764impl std::ops::BitAndAssign<Self> for RowAddrTreeMap {
765    fn bitand_assign(&mut self, rhs: Self) {
766        *self &= &rhs;
767    }
768}
769
770impl std::ops::BitAndAssign<&Self> for RowAddrTreeMap {
771    fn bitand_assign(&mut self, rhs: &Self) {
772        // Remove fragment that aren't on the RHS
773        self.inner
774            .retain(|fragment, _| rhs.inner.contains_key(fragment));
775
776        // For fragments that are on the RHS, intersect the bitmaps
777        for (fragment, mut lhs_set) in &mut self.inner {
778            match (&mut lhs_set, rhs.inner.get(fragment)) {
779                (_, None) => {} // Already handled by retain
780                (_, Some(RowAddrSelection::Full)) => {
781                    // Everything selected on RHS, so can leave LHS untouched.
782                }
783                (RowAddrSelection::Partial(lhs_set), Some(RowAddrSelection::Partial(rhs_set))) => {
784                    *lhs_set &= rhs_set;
785                }
786                (RowAddrSelection::Full, Some(RowAddrSelection::Partial(rhs_set))) => {
787                    *lhs_set = RowAddrSelection::Partial(rhs_set.clone());
788                }
789            }
790        }
791        // Some bitmaps might now be empty. If they are, we should remove them.
792        self.inner.retain(|_, set| match set {
793            RowAddrSelection::Partial(set) => !set.is_empty(),
794            RowAddrSelection::Full => true,
795        });
796    }
797}
798
799impl std::ops::Sub<Self> for RowAddrTreeMap {
800    type Output = Self;
801
802    fn sub(mut self, rhs: Self) -> Self {
803        self -= &rhs;
804        self
805    }
806}
807
808impl std::ops::Sub<&Self> for RowAddrTreeMap {
809    type Output = Self;
810
811    fn sub(mut self, rhs: &Self) -> Self {
812        self -= rhs;
813        self
814    }
815}
816
817impl std::ops::SubAssign<&Self> for RowAddrTreeMap {
818    fn sub_assign(&mut self, rhs: &Self) {
819        for (fragment, rhs_set) in &rhs.inner {
820            match self.inner.get_mut(fragment) {
821                None => {}
822                Some(RowAddrSelection::Full) => {
823                    // If the fragment is already selected then there is nothing to do
824                    match rhs_set {
825                        RowAddrSelection::Full => {
826                            self.inner.remove(fragment);
827                        }
828                        RowAddrSelection::Partial(rhs_set) => {
829                            // This generally won't be hit.
830                            let mut set = RoaringBitmap::full();
831                            set -= rhs_set;
832                            self.inner.insert(*fragment, RowAddrSelection::Partial(set));
833                        }
834                    }
835                }
836                Some(RowAddrSelection::Partial(lhs_set)) => match rhs_set {
837                    RowAddrSelection::Full => {
838                        self.inner.remove(fragment);
839                    }
840                    RowAddrSelection::Partial(rhs_set) => {
841                        *lhs_set -= rhs_set;
842                        if lhs_set.is_empty() {
843                            self.inner.remove(fragment);
844                        }
845                    }
846                },
847            }
848        }
849    }
850}
851
852impl FromIterator<u64> for RowAddrTreeMap {
853    fn from_iter<T: IntoIterator<Item = u64>>(iter: T) -> Self {
854        let mut inner = BTreeMap::new();
855        for row_addr in iter {
856            let upper = (row_addr >> 32) as u32;
857            let lower = row_addr as u32;
858            match inner.get_mut(&upper) {
859                None => {
860                    let mut set = RoaringBitmap::new();
861                    set.insert(lower);
862                    inner.insert(upper, RowAddrSelection::Partial(set));
863                }
864                Some(RowAddrSelection::Full) => {
865                    // If the fragment is already selected then there is nothing to do
866                }
867                Some(RowAddrSelection::Partial(set)) => {
868                    set.insert(lower);
869                }
870            }
871        }
872        Self { inner }
873    }
874}
875
876impl<'a> FromIterator<&'a u64> for RowAddrTreeMap {
877    fn from_iter<T: IntoIterator<Item = &'a u64>>(iter: T) -> Self {
878        Self::from_iter(iter.into_iter().copied())
879    }
880}
881
882impl From<Range<u64>> for RowAddrTreeMap {
883    fn from(range: Range<u64>) -> Self {
884        let mut map = Self::default();
885        map.insert_range(range);
886        map
887    }
888}
889
890impl From<RangeInclusive<u64>> for RowAddrTreeMap {
891    fn from(range: RangeInclusive<u64>) -> Self {
892        let mut map = Self::default();
893        map.insert_range(range);
894        map
895    }
896}
897
898impl From<RoaringTreemap> for RowAddrTreeMap {
899    fn from(roaring: RoaringTreemap) -> Self {
900        let mut inner = BTreeMap::new();
901        for (fragment, set) in roaring.bitmaps() {
902            inner.insert(fragment, RowAddrSelection::Partial(set.clone()));
903        }
904        Self { inner }
905    }
906}
907
908impl Extend<u64> for RowAddrTreeMap {
909    fn extend<T: IntoIterator<Item = u64>>(&mut self, iter: T) {
910        for row_addr in iter {
911            let upper = (row_addr >> 32) as u32;
912            let lower = row_addr as u32;
913            match self.inner.get_mut(&upper) {
914                None => {
915                    let mut set = RoaringBitmap::new();
916                    set.insert(lower);
917                    self.inner.insert(upper, RowAddrSelection::Partial(set));
918                }
919                Some(RowAddrSelection::Full) => {
920                    // If the fragment is already selected then there is nothing to do
921                }
922                Some(RowAddrSelection::Partial(set)) => {
923                    set.insert(lower);
924                }
925            }
926        }
927    }
928}
929
930impl<'a> Extend<&'a u64> for RowAddrTreeMap {
931    fn extend<T: IntoIterator<Item = &'a u64>>(&mut self, iter: T) {
932        self.extend(iter.into_iter().copied())
933    }
934}
935
936// Extending with RowAddrTreeMap is basically a cumulative set union
937impl Extend<Self> for RowAddrTreeMap {
938    fn extend<T: IntoIterator<Item = Self>>(&mut self, iter: T) {
939        for other in iter {
940            for (fragment, set) in other.inner {
941                match self.inner.get_mut(&fragment) {
942                    None => {
943                        self.inner.insert(fragment, set);
944                    }
945                    Some(RowAddrSelection::Full) => {
946                        // If the fragment is already selected then there is nothing to do
947                    }
948                    Some(RowAddrSelection::Partial(lhs_set)) => match set {
949                        RowAddrSelection::Full => {
950                            self.inner.insert(fragment, RowAddrSelection::Full);
951                        }
952                        RowAddrSelection::Partial(rhs_set) => {
953                            *lhs_set |= rhs_set;
954                        }
955                    },
956                }
957            }
958        }
959    }
960}
961
962pub fn bitmap_to_ranges(bitmap: &RoaringBitmap) -> Vec<Range<u64>> {
963    let mut ranges = Vec::new();
964    let mut iter = bitmap.iter();
965    while let Some(r) = iter.next_range() {
966        ranges.push(*r.start() as u64..(*r.end() as u64 + 1));
967    }
968    ranges
969}
970
971pub fn ranges_to_bitmap(ranges: &[Range<u64>], sorted: bool) -> RoaringBitmap {
972    if ranges.is_empty() {
973        return RoaringBitmap::new();
974    }
975    if sorted {
976        let sample_size = ranges.len().min(10);
977        let avg_len: u64 = ranges
978            .iter()
979            .take(sample_size)
980            .map(|r| r.end - r.start)
981            .sum::<u64>()
982            / sample_size as u64;
983        // from_sorted_iter appends each value in O(1) but must visit every u32.
984        // insert_range bulk-fills containers but does a binary search per call.
985        // Crossover is ~6: below that, iterating all values is cheaper.
986        if avg_len <= 6 {
987            return RoaringBitmap::from_sorted_iter(
988                ranges.iter().flat_map(|r| r.start as u32..r.end as u32),
989            )
990            .unwrap();
991        }
992    }
993    let mut bm = RoaringBitmap::new();
994    for r in ranges {
995        bm.insert_range(r.start as u32..r.end as u32);
996    }
997    bm
998}
999
1000/// A set of stable row ids backed by a 64-bit Roaring bitmap.
1001///
1002/// This is a thin wrapper around [`RoaringTreemap`]. It represents a
1003/// collection of unique row ids and provides the common row-set
1004/// operations defined by [`RowSetOps`].
1005#[derive(Clone, Debug, Default, PartialEq)]
1006pub struct RowIdSet {
1007    inner: RoaringTreemap,
1008}
1009
1010impl RowIdSet {
1011    /// Creates an empty set of row ids.
1012    pub fn new() -> Self {
1013        Self::default()
1014    }
1015    /// Returns an iterator over the contained row ids in ascending order.
1016    pub fn iter(&self) -> impl Iterator<Item = u64> + '_ {
1017        self.inner.iter()
1018    }
1019    /// Returns the union of `self` and `other`.
1020    pub fn union(mut self, other: &Self) -> Self {
1021        self.inner |= &other.inner;
1022        self
1023    }
1024    /// Returns the set difference `self \\ other`.
1025    pub fn difference(mut self, other: &Self) -> Self {
1026        self.inner -= &other.inner;
1027        self
1028    }
1029}
1030
1031impl RowSetOps for RowIdSet {
1032    type Row = u64;
1033    fn is_empty(&self) -> bool {
1034        self.inner.is_empty()
1035    }
1036    fn len(&self) -> Option<u64> {
1037        Some(self.inner.len())
1038    }
1039    fn remove(&mut self, row: Self::Row) -> bool {
1040        self.inner.remove(row)
1041    }
1042    fn contains(&self, row: Self::Row) -> bool {
1043        self.inner.contains(row)
1044    }
1045    fn union_all(other: &[&Self]) -> Self {
1046        let mut result = other
1047            .first()
1048            .map_or(Self::default(), |&first| first.clone());
1049        for set in other {
1050            result.inner |= &set.inner;
1051        }
1052        result
1053    }
1054    #[track_caller]
1055    fn from_sorted_iter<I>(iter: I) -> Result<Self>
1056    where
1057        I: IntoIterator<Item = Self::Row>,
1058    {
1059        let mut inner = RoaringTreemap::new();
1060        let mut last: Option<u64> = None;
1061        for value in iter {
1062            if let Some(prev) = last
1063                && value < prev
1064            {
1065                return Err(Error::internal(
1066                    "RowIdSet::from_sorted_iter called with non-sorted input",
1067                ));
1068            }
1069            inner.insert(value);
1070            last = Some(value);
1071        }
1072        Ok(Self { inner })
1073    }
1074}
1075
1076/// A mask over stable row ids based on an allow-list or block-list.
1077///
1078/// The semantics mirror [`RowAddrMask`], but operate on stable
1079/// row ids instead of physical row addresses.
1080#[derive(Clone, Debug, PartialEq)]
1081pub enum RowIdMask {
1082    /// Only the ids in the set are selected.
1083    AllowList(RowIdSet),
1084    /// All ids are selected except those in the set.
1085    BlockList(RowIdSet),
1086}
1087
1088impl Default for RowIdMask {
1089    fn default() -> Self {
1090        // Empty block list means all rows are allowed
1091        Self::BlockList(RowIdSet::default())
1092    }
1093}
1094impl RowIdMask {
1095    /// Create a mask allowing all rows, this is an alias for [`Default`].
1096    pub fn all_rows() -> Self {
1097        Self::default()
1098    }
1099    /// Create a mask that doesn't allow any row id.
1100    pub fn allow_nothing() -> Self {
1101        Self::AllowList(RowIdSet::default())
1102    }
1103    /// Create a mask from an allow list.
1104    pub fn from_allowed(allow_list: RowIdSet) -> Self {
1105        Self::AllowList(allow_list)
1106    }
1107    /// Create a mask from a block list.
1108    pub fn from_block(block_list: RowIdSet) -> Self {
1109        Self::BlockList(block_list)
1110    }
1111    /// True if the row id is selected by the mask, false otherwise.
1112    pub fn selected(&self, row_id: u64) -> bool {
1113        match self {
1114            Self::AllowList(allow_list) => allow_list.contains(row_id),
1115            Self::BlockList(block_list) => !block_list.contains(row_id),
1116        }
1117    }
1118    /// Return the indices of the input row ids that are selected by the mask.
1119    pub fn selected_indices<'a>(&self, row_ids: impl Iterator<Item = &'a u64> + 'a) -> Vec<u64> {
1120        row_ids
1121            .enumerate()
1122            .filter_map(|(idx, row_id)| {
1123                if self.selected(*row_id) {
1124                    Some(idx as u64)
1125                } else {
1126                    None
1127                }
1128            })
1129            .collect()
1130    }
1131    /// Also block the given ids.
1132    ///
1133    /// * `AllowList(a)` -> `AllowList(a \\ block_list)`
1134    /// * `BlockList(b)` -> `BlockList(b union block_list)`
1135    pub fn also_block(self, block_list: RowIdSet) -> Self {
1136        match self {
1137            Self::AllowList(allow_list) => Self::AllowList(allow_list.difference(&block_list)),
1138            Self::BlockList(existing) => Self::BlockList(existing.union(&block_list)),
1139        }
1140    }
1141    /// Also allow the given ids.
1142    ///
1143    /// * `AllowList(a)` -> `AllowList(a union allow_list)`
1144    /// * `BlockList(b)` -> `BlockList(b \\ allow_list)`
1145    pub fn also_allow(self, allow_list: RowIdSet) -> Self {
1146        match self {
1147            Self::AllowList(existing) => Self::AllowList(existing.union(&allow_list)),
1148            Self::BlockList(block_list) => Self::BlockList(block_list.difference(&allow_list)),
1149        }
1150    }
1151    /// Return the maximum number of row ids that could be selected by this mask.
1152    ///
1153    /// Will be `None` if this is a `BlockList` (unbounded).
1154    pub fn max_len(&self) -> Option<u64> {
1155        match self {
1156            Self::AllowList(selection) => selection.len(),
1157            Self::BlockList(_) => None,
1158        }
1159    }
1160    /// Iterate over the row ids that are selected by the mask.
1161    ///
1162    /// This is only possible if this is an `AllowList`. For a `BlockList`
1163    /// the domain of possible row ids is unbounded.
1164    pub fn iter_ids(&self) -> Option<Box<dyn Iterator<Item = u64> + '_>> {
1165        match self {
1166            Self::AllowList(allow_list) => Some(Box::new(allow_list.iter())),
1167            Self::BlockList(_) => None,
1168        }
1169    }
1170}
1171
1172#[cfg(test)]
1173mod tests {
1174    use super::*;
1175    use proptest::{prop_assert, prop_assert_eq};
1176
1177    fn rows(ids: &[u64]) -> RowAddrTreeMap {
1178        RowAddrTreeMap::from_iter(ids)
1179    }
1180
1181    fn assert_mask_selects(mask: &RowAddrMask, selected: &[u64], not_selected: &[u64]) {
1182        for &id in selected {
1183            assert!(mask.selected(id), "Expected row {} to be selected", id);
1184        }
1185        for &id in not_selected {
1186            assert!(!mask.selected(id), "Expected row {} to NOT be selected", id);
1187        }
1188    }
1189
1190    fn selected_in_range(mask: &RowAddrMask, range: std::ops::Range<u64>) -> Vec<u64> {
1191        range.filter(|val| mask.selected(*val)).collect()
1192    }
1193
1194    #[test]
1195    fn test_row_addr_mask_construction() {
1196        let full_mask = RowAddrMask::all_rows();
1197        assert_eq!(full_mask.max_len(), None);
1198        assert_mask_selects(&full_mask, &[0, 1, 4 << 32 | 3], &[]);
1199        assert_eq!(full_mask.allow_list(), None);
1200        assert_eq!(full_mask.block_list(), Some(&RowAddrTreeMap::default()));
1201        assert!(full_mask.iter_addrs().is_none());
1202
1203        let empty_mask = RowAddrMask::allow_nothing();
1204        assert_eq!(empty_mask.max_len(), Some(0));
1205        assert_mask_selects(&empty_mask, &[], &[0, 1, 4 << 32 | 3]);
1206        assert_eq!(empty_mask.allow_list(), Some(&RowAddrTreeMap::default()));
1207        assert_eq!(empty_mask.block_list(), None);
1208        let iter = empty_mask.iter_addrs();
1209        assert!(iter.is_some());
1210        assert_eq!(iter.unwrap().count(), 0);
1211
1212        let allow_list = RowAddrMask::from_allowed(rows(&[10, 20, 30]));
1213        assert_eq!(allow_list.max_len(), Some(3));
1214        assert_mask_selects(&allow_list, &[10, 20, 30], &[0, 15, 25, 40]);
1215        assert_eq!(allow_list.allow_list(), Some(&rows(&[10, 20, 30])));
1216        assert_eq!(allow_list.block_list(), None);
1217        let iter = allow_list.iter_addrs();
1218        assert!(iter.is_some());
1219        let ids: Vec<u64> = iter.unwrap().map(|addr| addr.into()).collect();
1220        assert_eq!(ids, vec![10, 20, 30]);
1221
1222        let mut full_frag = RowAddrTreeMap::default();
1223        full_frag.insert_fragment(2);
1224        let allow_list = RowAddrMask::from_allowed(full_frag);
1225        assert_eq!(allow_list.max_len(), None);
1226        assert_mask_selects(&allow_list, &[(2 << 32) + 5], &[(3 << 32) + 5]);
1227        assert!(allow_list.iter_addrs().is_none());
1228    }
1229
1230    #[test]
1231    fn test_selected_indices() {
1232        // Allow list
1233        let mask = RowAddrMask::from_allowed(rows(&[10, 20, 40]));
1234        assert!(mask.selected_indices(std::iter::empty()).is_empty());
1235        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[1, 3]);
1236
1237        // Block list
1238        let mask = RowAddrMask::from_block(rows(&[10, 20, 40]));
1239        assert!(mask.selected_indices(std::iter::empty()).is_empty());
1240        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[0, 2]);
1241    }
1242
1243    #[test]
1244    fn test_also_allow() {
1245        // Allow list
1246        let mask = RowAddrMask::from_allowed(rows(&[10, 20]));
1247        let new_mask = mask.also_allow(rows(&[20, 30, 40]));
1248        assert_eq!(new_mask, RowAddrMask::from_allowed(rows(&[10, 20, 30, 40])));
1249
1250        // Block list
1251        let mask = RowAddrMask::from_block(rows(&[10, 20, 30]));
1252        let new_mask = mask.also_allow(rows(&[20, 40]));
1253        assert_eq!(new_mask, RowAddrMask::from_block(rows(&[10, 30])));
1254    }
1255
1256    #[test]
1257    fn test_also_block() {
1258        // Allow list
1259        let mask = RowAddrMask::from_allowed(rows(&[10, 20, 30]));
1260        let new_mask = mask.also_block(rows(&[20, 40]));
1261        assert_eq!(new_mask, RowAddrMask::from_allowed(rows(&[10, 30])));
1262
1263        // Block list
1264        let mask = RowAddrMask::from_block(rows(&[10, 20]));
1265        let new_mask = mask.also_block(rows(&[20, 30, 40]));
1266        assert_eq!(new_mask, RowAddrMask::from_block(rows(&[10, 20, 30, 40])));
1267    }
1268
1269    #[test]
1270    fn test_iter_ids() {
1271        // Allow list
1272        let mask = RowAddrMask::from_allowed(rows(&[10, 20, 30]));
1273        let expected: Vec<_> = [10, 20, 30].into_iter().map(RowAddress::from).collect();
1274        assert_eq!(mask.iter_addrs().unwrap().collect::<Vec<_>>(), expected);
1275
1276        // Allow list with full fragment
1277        let mut inner = RowAddrTreeMap::default();
1278        inner.insert_fragment(10);
1279        let mask = RowAddrMask::from_allowed(inner);
1280        assert!(mask.iter_addrs().is_none());
1281
1282        // Block list
1283        let mask = RowAddrMask::from_block(rows(&[10, 20, 30]));
1284        assert!(mask.iter_addrs().is_none());
1285    }
1286
1287    #[test]
1288    fn test_row_addr_mask_not() {
1289        let allow_list = RowAddrMask::from_allowed(rows(&[1, 2, 3]));
1290        let block_list = !allow_list.clone();
1291        assert_eq!(block_list, RowAddrMask::from_block(rows(&[1, 2, 3])));
1292        // Can roundtrip by negating again
1293        assert_eq!(!block_list, allow_list);
1294    }
1295
1296    #[test]
1297    fn test_ops() {
1298        let mask = RowAddrMask::default();
1299        assert_mask_selects(&mask, &[1, 5], &[]);
1300
1301        let block_list = mask.also_block(rows(&[0, 5, 15]));
1302        assert_mask_selects(&block_list, &[1], &[5]);
1303
1304        let allow_list = RowAddrMask::from_allowed(rows(&[0, 2, 5]));
1305        assert_mask_selects(&allow_list, &[5], &[1]);
1306
1307        let combined = block_list & allow_list;
1308        assert_mask_selects(&combined, &[2], &[0, 5]);
1309
1310        let other = RowAddrMask::from_allowed(rows(&[3]));
1311        let combined = combined | other;
1312        assert_mask_selects(&combined, &[2, 3], &[0, 5]);
1313
1314        let block_list = RowAddrMask::from_block(rows(&[0]));
1315        let allow_list = RowAddrMask::from_allowed(rows(&[3]));
1316
1317        let combined = block_list | allow_list;
1318        assert_mask_selects(&combined, &[1], &[]);
1319    }
1320
1321    #[test]
1322    fn test_logical_and() {
1323        let allow1 = RowAddrMask::from_allowed(rows(&[0, 1]));
1324        let block1 = RowAddrMask::from_block(rows(&[1, 2]));
1325        let allow2 = RowAddrMask::from_allowed(rows(&[1, 2, 3, 4]));
1326        let block2 = RowAddrMask::from_block(rows(&[3, 4]));
1327
1328        fn check(lhs: &RowAddrMask, rhs: &RowAddrMask, expected: &[u64]) {
1329            for mask in [lhs.clone() & rhs.clone(), rhs.clone() & lhs.clone()] {
1330                assert_eq!(selected_in_range(&mask, 0..10), expected);
1331            }
1332        }
1333
1334        // Allow & Allow
1335        check(&allow1, &allow1, &[0, 1]);
1336        check(&allow1, &allow2, &[1]);
1337
1338        // Block & Block
1339        check(&block1, &block1, &[0, 3, 4, 5, 6, 7, 8, 9]);
1340        check(&block1, &block2, &[0, 5, 6, 7, 8, 9]);
1341
1342        // Allow & Block
1343        check(&allow1, &block1, &[0]);
1344        check(&allow1, &block2, &[0, 1]);
1345        check(&allow2, &block1, &[3, 4]);
1346        check(&allow2, &block2, &[1, 2]);
1347    }
1348
1349    #[test]
1350    fn test_logical_or() {
1351        let allow1 = RowAddrMask::from_allowed(rows(&[5, 6, 7, 8, 9]));
1352        let block1 = RowAddrMask::from_block(rows(&[5, 6]));
1353        let mixed1 = allow1.clone().also_block(rows(&[5, 6]));
1354        let allow2 = RowAddrMask::from_allowed(rows(&[2, 3, 4, 5, 6, 7, 8]));
1355        let block2 = RowAddrMask::from_block(rows(&[4, 5]));
1356        let mixed2 = allow2.clone().also_block(rows(&[4, 5]));
1357
1358        fn check(lhs: &RowAddrMask, rhs: &RowAddrMask, expected: &[u64]) {
1359            for mask in [lhs.clone() | rhs.clone(), rhs.clone() | lhs.clone()] {
1360                assert_eq!(selected_in_range(&mask, 0..10), expected);
1361            }
1362        }
1363
1364        check(&allow1, &allow1, &[5, 6, 7, 8, 9]);
1365        check(&block1, &block1, &[0, 1, 2, 3, 4, 7, 8, 9]);
1366        check(&mixed1, &mixed1, &[7, 8, 9]);
1367        check(&allow2, &allow2, &[2, 3, 4, 5, 6, 7, 8]);
1368        check(&block2, &block2, &[0, 1, 2, 3, 6, 7, 8, 9]);
1369        check(&mixed2, &mixed2, &[2, 3, 6, 7, 8]);
1370
1371        check(&allow1, &block1, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1372        check(&allow1, &mixed1, &[5, 6, 7, 8, 9]);
1373        check(&allow1, &allow2, &[2, 3, 4, 5, 6, 7, 8, 9]);
1374        check(&allow1, &block2, &[0, 1, 2, 3, 5, 6, 7, 8, 9]);
1375        check(&allow1, &mixed2, &[2, 3, 5, 6, 7, 8, 9]);
1376        check(&block1, &mixed1, &[0, 1, 2, 3, 4, 7, 8, 9]);
1377        check(&block1, &allow2, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1378        check(&block1, &block2, &[0, 1, 2, 3, 4, 6, 7, 8, 9]);
1379        check(&block1, &mixed2, &[0, 1, 2, 3, 4, 6, 7, 8, 9]);
1380        check(&mixed1, &allow2, &[2, 3, 4, 5, 6, 7, 8, 9]);
1381        check(&mixed1, &block2, &[0, 1, 2, 3, 6, 7, 8, 9]);
1382        check(&mixed1, &mixed2, &[2, 3, 6, 7, 8, 9]);
1383        check(&allow2, &block2, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1384        check(&allow2, &mixed2, &[2, 3, 4, 5, 6, 7, 8]);
1385        check(&block2, &mixed2, &[0, 1, 2, 3, 6, 7, 8, 9]);
1386    }
1387
1388    #[test]
1389    fn test_deserialize_legacy_format() {
1390        // Test that we can deserialize the old format where both allow_list
1391        // and block_list could be present in the serialized form.
1392        //
1393        // The old format (before this PR) used a struct with both allow_list and block_list
1394        // fields. The new format uses an enum. The deserialization code should handle
1395        // the case where both lists are present by converting to AllowList(allow - block).
1396
1397        // Create the RowIdTreeMaps and serialize them directly
1398        let allow = rows(&[1, 2, 3, 4, 5, 10, 15]);
1399        let block = rows(&[2, 4, 15]);
1400
1401        // Serialize using the stable RowIdTreeMap serialization format
1402        let block_bytes = {
1403            let mut buf = Vec::with_capacity(block.serialized_size());
1404            block.serialize_into(&mut buf).unwrap();
1405            buf
1406        };
1407        let allow_bytes = {
1408            let mut buf = Vec::with_capacity(allow.serialized_size());
1409            allow.serialize_into(&mut buf).unwrap();
1410            buf
1411        };
1412
1413        // Construct a binary array with both values present (simulating old format)
1414        let old_format_array =
1415            BinaryArray::from_opt_vec(vec![Some(&block_bytes), Some(&allow_bytes)]);
1416
1417        // Deserialize - should handle this by creating AllowList(allow - block)
1418        let deserialized = RowAddrMask::from_arrow(&old_format_array).unwrap();
1419
1420        // The expected result: AllowList([1, 2, 3, 4, 5, 10, 15] - [2, 4, 15]) = [1, 3, 5, 10]
1421        assert_mask_selects(&deserialized, &[1, 3, 5, 10], &[2, 4, 15]);
1422        assert!(
1423            deserialized.allow_list().is_some(),
1424            "Should deserialize to AllowList variant"
1425        );
1426    }
1427
1428    #[test]
1429    fn test_roundtrip_arrow() {
1430        let row_addrs = rows(&[1, 2, 3, 100, 2000]);
1431
1432        // Allow list
1433        let original = RowAddrMask::from_allowed(row_addrs.clone());
1434        let array = original.into_arrow().unwrap();
1435        assert_eq!(RowAddrMask::from_arrow(&array).unwrap(), original);
1436
1437        // Block list
1438        let original = RowAddrMask::from_block(row_addrs);
1439        let array = original.into_arrow().unwrap();
1440        assert_eq!(RowAddrMask::from_arrow(&array).unwrap(), original);
1441    }
1442
1443    #[test]
1444    fn test_deserialize_legacy_empty_lists() {
1445        // Case 1: Both None (should become all_rows)
1446        let array = BinaryArray::from_opt_vec(vec![None, None]);
1447        let mask = RowAddrMask::from_arrow(&array).unwrap();
1448        assert_mask_selects(&mask, &[0, 100, u64::MAX], &[]);
1449
1450        // Case 2: Only block list (no allow list)
1451        let block = rows(&[5, 10]);
1452        let block_bytes = {
1453            let mut buf = Vec::with_capacity(block.serialized_size());
1454            block.serialize_into(&mut buf).unwrap();
1455            buf
1456        };
1457        let array = BinaryArray::from_opt_vec(vec![Some(&block_bytes[..]), None]);
1458        let mask = RowAddrMask::from_arrow(&array).unwrap();
1459        assert_mask_selects(&mask, &[0, 15], &[5, 10]);
1460
1461        // Case 3: Only allow list (no block list)
1462        let allow = rows(&[5, 10]);
1463        let allow_bytes = {
1464            let mut buf = Vec::with_capacity(allow.serialized_size());
1465            allow.serialize_into(&mut buf).unwrap();
1466            buf
1467        };
1468        let array = BinaryArray::from_opt_vec(vec![None, Some(&allow_bytes[..])]);
1469        let mask = RowAddrMask::from_arrow(&array).unwrap();
1470        assert_mask_selects(&mask, &[5, 10], &[0, 15]);
1471    }
1472
1473    #[test]
1474    fn test_map_insert() {
1475        let mut map = RowAddrTreeMap::default();
1476
1477        assert!(!map.contains(20));
1478        assert!(map.insert(20));
1479        assert!(map.contains(20));
1480        assert!(!map.insert(20)); // Inserting again should be no-op
1481
1482        let bitmap = map.get_fragment_bitmap(0);
1483        assert!(bitmap.is_some());
1484        let bitmap = bitmap.unwrap();
1485        assert_eq!(bitmap.len(), 1);
1486
1487        assert!(map.get_fragment_bitmap(1).is_none());
1488
1489        map.insert_fragment(0);
1490        assert!(map.contains(0));
1491        assert!(!map.insert(0)); // Inserting into full fragment should be no-op
1492        assert!(map.get_fragment_bitmap(0).is_none());
1493    }
1494
1495    #[test]
1496    fn test_map_insert_range() {
1497        let ranges = &[
1498            (0..10),
1499            (40..500),
1500            ((u32::MAX as u64 - 10)..(u32::MAX as u64 + 20)),
1501        ];
1502
1503        for range in ranges {
1504            let mut mask = RowAddrTreeMap::default();
1505
1506            let count = mask.insert_range(range.clone());
1507            let expected = range.end - range.start;
1508            assert_eq!(count, expected);
1509
1510            let count = mask.insert_range(range.clone());
1511            assert_eq!(count, 0);
1512
1513            let new_range = range.start + 5..range.end + 5;
1514            let count = mask.insert_range(new_range.clone());
1515            assert_eq!(count, 5);
1516        }
1517
1518        let mut mask = RowAddrTreeMap::default();
1519        let count = mask.insert_range(..10);
1520        assert_eq!(count, 10);
1521        assert!(mask.contains(0));
1522
1523        let count = mask.insert_range(20..=24);
1524        assert_eq!(count, 5);
1525
1526        mask.insert_fragment(0);
1527        let count = mask.insert_range(100..200);
1528        assert_eq!(count, 0);
1529    }
1530
1531    #[test]
1532    fn test_map_remove() {
1533        let mut mask = RowAddrTreeMap::default();
1534
1535        assert!(!mask.remove(20));
1536
1537        mask.insert(20);
1538        assert!(mask.contains(20));
1539        assert!(mask.remove(20));
1540        assert!(!mask.contains(20));
1541
1542        mask.insert_range(10..=20);
1543        assert!(mask.contains(15));
1544        assert!(mask.remove(15));
1545        assert!(!mask.contains(15));
1546
1547        // We don't test removing from a full fragment, because that would take
1548        // a lot of memory.
1549    }
1550
1551    #[test]
1552    fn test_map_mask() {
1553        let mask = rows(&[0, 1, 2]);
1554        let mask2 = rows(&[0, 2, 3]);
1555
1556        let allow_list = RowAddrMask::AllowList(mask2.clone());
1557        let mut actual = mask.clone();
1558        actual.mask(&allow_list);
1559        assert_eq!(actual, rows(&[0, 2]));
1560
1561        let block_list = RowAddrMask::BlockList(mask2);
1562        let mut actual = mask;
1563        actual.mask(&block_list);
1564        assert_eq!(actual, rows(&[1]));
1565    }
1566
1567    #[test]
1568    #[should_panic(expected = "Size of full fragment is unknown")]
1569    fn test_map_insert_full_fragment_row() {
1570        let mut mask = RowAddrTreeMap::default();
1571        mask.insert_fragment(0);
1572
1573        unsafe {
1574            let _ = mask.into_addr_iter().collect::<Vec<u64>>();
1575        }
1576    }
1577
1578    #[test]
1579    fn test_map_into_addr_iter() {
1580        let mut mask = RowAddrTreeMap::default();
1581        mask.insert(0);
1582        mask.insert(1);
1583        mask.insert(1 << 32 | 5);
1584        mask.insert(2 << 32 | 10);
1585
1586        let expected = vec![0u64, 1, 1 << 32 | 5, 2 << 32 | 10];
1587        let actual: Vec<u64> = unsafe { mask.into_addr_iter().collect() };
1588        assert_eq!(actual, expected);
1589    }
1590
1591    #[test]
1592    fn test_map_iter_runs() {
1593        // Three contiguous regions across two fragments.
1594        let mut mask = RowAddrTreeMap::default();
1595        mask.insert_range(0..3);
1596        mask.insert_range(10..15);
1597        mask.insert_range((1u64 << 32) + 100..(1u64 << 32) + 103);
1598
1599        // SAFETY: only Partial entries.
1600        let runs: Vec<(u32, RangeInclusive<u32>)> = unsafe { mask.iter_runs().collect() };
1601        assert_eq!(runs, vec![(0, 0..=2), (0, 10..=14), (1, 100..=102)]);
1602    }
1603
1604    #[test]
1605    fn test_map_iter_runs_matches_into_addr_iter() {
1606        // Confirm iter_runs and into_addr_iter agree on a non-trivial shape.
1607        let mut mask = RowAddrTreeMap::default();
1608        mask.insert_range(5..7);
1609        mask.insert_range(11..12);
1610        mask.insert_range(20..25);
1611        mask.insert_range((1u64 << 32)..(1u64 << 32) + 3);
1612
1613        let from_runs: Vec<u64> = unsafe { mask.iter_runs() }
1614            .flat_map(|(frag, run)| {
1615                let frag = u64::from(frag);
1616                (*run.start()..=*run.end()).map(move |v| (frag << 32) | u64::from(v))
1617            })
1618            .collect();
1619        let from_bits: Vec<u64> = unsafe { mask.clone().into_addr_iter() }.collect();
1620        assert_eq!(from_runs, from_bits);
1621    }
1622
1623    #[test]
1624    fn test_map_from() {
1625        let map = RowAddrTreeMap::from(10..12);
1626        assert!(map.contains(10));
1627        assert!(map.contains(11));
1628        assert!(!map.contains(12));
1629        assert!(!map.contains(3));
1630
1631        let map = RowAddrTreeMap::from(10..=12);
1632        assert!(map.contains(10));
1633        assert!(map.contains(11));
1634        assert!(map.contains(12));
1635        assert!(!map.contains(3));
1636    }
1637
1638    #[test]
1639    fn test_map_from_roaring() {
1640        let bitmap = RoaringTreemap::from_iter(&[0, 1, 1 << 32]);
1641        let map = RowAddrTreeMap::from(bitmap);
1642        assert!(map.contains(0) && map.contains(1) && map.contains(1 << 32));
1643        assert!(!map.contains(2));
1644    }
1645
1646    #[test]
1647    fn test_map_extend() {
1648        let mut map = RowAddrTreeMap::default();
1649        map.insert(0);
1650        map.insert_fragment(1);
1651
1652        let other_rows = [0, 2, 1 << 32 | 10, 3 << 32 | 5];
1653        map.extend(other_rows.iter().copied());
1654
1655        assert!(map.contains(0));
1656        assert!(map.contains(2));
1657        assert!(map.contains(1 << 32 | 5));
1658        assert!(map.contains(1 << 32 | 10));
1659        assert!(map.contains(3 << 32 | 5));
1660        assert!(!map.contains(3));
1661    }
1662
1663    #[test]
1664    fn test_map_extend_other_maps() {
1665        let mut map = RowAddrTreeMap::default();
1666        map.insert(0);
1667        map.insert_fragment(1);
1668        map.insert(4 << 32);
1669
1670        let mut other_map = rows(&[0, 2, 1 << 32 | 10, 3 << 32 | 5]);
1671        other_map.insert_fragment(4);
1672        map.extend(std::iter::once(other_map));
1673
1674        for id in [
1675            0,
1676            2,
1677            1 << 32 | 5,
1678            1 << 32 | 10,
1679            3 << 32 | 5,
1680            4 << 32,
1681            4 << 32 | 7,
1682        ] {
1683            assert!(map.contains(id), "Expected {} to be contained", id);
1684        }
1685        assert!(!map.contains(3));
1686    }
1687
1688    proptest::proptest! {
1689        #[test]
1690        fn test_map_serialization_roundtrip(
1691            values in proptest::collection::vec(
1692                (0..u32::MAX, proptest::option::of(proptest::collection::vec(0..u32::MAX, 0..1000))),
1693                0..10
1694            )
1695        ) {
1696            let mut mask = RowAddrTreeMap::default();
1697            for (fragment, rows) in values {
1698                if let Some(rows) = rows {
1699                    let bitmap = RoaringBitmap::from_iter(rows);
1700                    mask.insert_bitmap(fragment, bitmap);
1701                } else {
1702                    mask.insert_fragment(fragment);
1703                }
1704            }
1705
1706            let mut data = Vec::new();
1707            mask.serialize_into(&mut data).unwrap();
1708            let deserialized = RowAddrTreeMap::deserialize_from(data.as_slice()).unwrap();
1709            prop_assert_eq!(mask, deserialized);
1710        }
1711
1712        #[test]
1713        fn test_map_intersect(
1714            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1715            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1716            right_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1717            right_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1718        ) {
1719            let mut left = RowAddrTreeMap::default();
1720            for fragment in left_full_fragments.clone() {
1721                left.insert_fragment(fragment);
1722            }
1723            left.extend(left_rows.iter().copied());
1724
1725            let mut right = RowAddrTreeMap::default();
1726            for fragment in right_full_fragments.clone() {
1727                right.insert_fragment(fragment);
1728            }
1729            right.extend(right_rows.iter().copied());
1730
1731            let mut expected = RowAddrTreeMap::default();
1732            for fragment in &left_full_fragments {
1733                if right_full_fragments.contains(fragment) {
1734                    expected.insert_fragment(*fragment);
1735                }
1736            }
1737
1738            let left_in_right = left_rows.iter().filter(|row| {
1739                right_rows.contains(row)
1740                    || right_full_fragments.contains(&((*row >> 32) as u32))
1741            });
1742            expected.extend(left_in_right);
1743            let right_in_left = right_rows.iter().filter(|row| {
1744                left_rows.contains(row)
1745                    || left_full_fragments.contains(&((*row >> 32) as u32))
1746            });
1747            expected.extend(right_in_left);
1748
1749            let actual = left & right;
1750            prop_assert_eq!(expected, actual);
1751        }
1752
1753        #[test]
1754        fn test_map_union(
1755            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1756            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1757            right_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1758            right_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1759        ) {
1760            let mut left = RowAddrTreeMap::default();
1761            for fragment in left_full_fragments.clone() {
1762                left.insert_fragment(fragment);
1763            }
1764            left.extend(left_rows.iter().copied());
1765
1766            let mut right = RowAddrTreeMap::default();
1767            for fragment in right_full_fragments.clone() {
1768                right.insert_fragment(fragment);
1769            }
1770            right.extend(right_rows.iter().copied());
1771
1772            let mut expected = RowAddrTreeMap::default();
1773            for fragment in left_full_fragments {
1774                expected.insert_fragment(fragment);
1775            }
1776            for fragment in right_full_fragments {
1777                expected.insert_fragment(fragment);
1778            }
1779
1780            let combined_rows = left_rows.iter().chain(right_rows.iter());
1781            expected.extend(combined_rows);
1782
1783            let actual = left | right;
1784            for actual_key_val in &actual.inner {
1785                proptest::prop_assert!(expected.inner.contains_key(actual_key_val.0));
1786                let expected_val = expected.inner.get(actual_key_val.0).unwrap();
1787                prop_assert_eq!(
1788                    actual_key_val.1,
1789                    expected_val,
1790                    "error on key {}",
1791                    actual_key_val.0
1792                );
1793            }
1794            prop_assert_eq!(expected, actual);
1795        }
1796
1797        #[test]
1798        fn test_map_subassign_rows(
1799            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1800            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1801            right_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1802        ) {
1803            let mut left = RowAddrTreeMap::default();
1804            for fragment in left_full_fragments {
1805                left.insert_fragment(fragment);
1806            }
1807            left.extend(left_rows.iter().copied());
1808
1809            let mut right = RowAddrTreeMap::default();
1810            right.extend(right_rows.iter().copied());
1811
1812            let mut expected = left.clone();
1813            for row in right_rows {
1814                expected.remove(row);
1815            }
1816
1817            left -= &right;
1818            prop_assert_eq!(expected, left);
1819        }
1820
1821        #[test]
1822        fn test_map_subassign_frags(
1823            left_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1824            right_full_fragments in proptest::collection::vec(0..u32::MAX, 0..10),
1825            left_rows in proptest::collection::vec(0..u64::MAX, 0..1000),
1826        ) {
1827            let mut left = RowAddrTreeMap::default();
1828            for fragment in left_full_fragments {
1829                left.insert_fragment(fragment);
1830            }
1831            left.extend(left_rows.iter().copied());
1832
1833            let mut right = RowAddrTreeMap::default();
1834            for fragment in right_full_fragments.clone() {
1835                right.insert_fragment(fragment);
1836            }
1837
1838            let mut expected = left.clone();
1839            for fragment in right_full_fragments {
1840                expected.inner.remove(&fragment);
1841            }
1842
1843            left -= &right;
1844            prop_assert_eq!(expected, left);
1845        }
1846
1847        #[test]
1848        fn test_from_sorted_iter(
1849            mut rows in proptest::collection::vec(0..u64::MAX, 0..1000)
1850        ) {
1851            rows.sort();
1852            let num_rows = rows.len();
1853            let mask = RowAddrTreeMap::from_sorted_iter(rows).unwrap();
1854            prop_assert_eq!(mask.len(), Some(num_rows as u64));
1855        }
1856
1857
1858    }
1859
1860    #[test]
1861    fn test_row_addr_selection_deep_size_of() {
1862        use deepsize::DeepSizeOf;
1863
1864        // Test Full variant - should have minimal size (just the enum discriminant)
1865        let full = RowAddrSelection::Full;
1866        let full_size = full.deep_size_of();
1867        // Full variant has no heap allocations beyond the enum itself
1868        assert!(full_size < 100); // Small sanity check
1869
1870        // Test Partial variant - should include bitmap size
1871        let mut bitmap = RoaringBitmap::new();
1872        bitmap.insert_range(0..100);
1873        let partial = RowAddrSelection::Partial(bitmap.clone());
1874        let partial_size = partial.deep_size_of();
1875        // Partial variant should be larger due to bitmap
1876        assert!(partial_size >= bitmap.serialized_size());
1877    }
1878
1879    #[test]
1880    fn test_row_addr_selection_union_all_with_full() {
1881        let full = RowAddrSelection::Full;
1882        let partial = RowAddrSelection::Partial(RoaringBitmap::from_iter(&[1, 2, 3]));
1883
1884        assert!(matches!(
1885            RowAddrSelection::union_all(&[&full, &partial]),
1886            RowAddrSelection::Full
1887        ));
1888
1889        let partial2 = RowAddrSelection::Partial(RoaringBitmap::from_iter(&[4, 5, 6]));
1890        let RowAddrSelection::Partial(bitmap) = RowAddrSelection::union_all(&[&partial, &partial2])
1891        else {
1892            panic!("Expected Partial");
1893        };
1894        assert!(bitmap.contains(1) && bitmap.contains(4));
1895    }
1896
1897    #[test]
1898    fn test_insert_range_unbounded_start() {
1899        let mut map = RowAddrTreeMap::default();
1900
1901        // Test exclusive start bound
1902        let count = map.insert_range((std::ops::Bound::Excluded(5), std::ops::Bound::Included(10)));
1903        assert_eq!(count, 5); // 6, 7, 8, 9, 10
1904        assert!(!map.contains(5));
1905        assert!(map.contains(6));
1906        assert!(map.contains(10));
1907
1908        // Test unbounded end
1909        let mut map2 = RowAddrTreeMap::default();
1910        let count = map2.insert_range(0..5);
1911        assert_eq!(count, 5);
1912        assert!(map2.contains(0));
1913        assert!(map2.contains(4));
1914        assert!(!map2.contains(5));
1915    }
1916
1917    #[test]
1918    fn test_remove_from_full_fragment() {
1919        let mut map = RowAddrTreeMap::default();
1920        map.insert_fragment(0);
1921
1922        // Verify it's a full fragment - get_fragment_bitmap returns None for Full
1923        for id in [0, 100, u32::MAX as u64] {
1924            assert!(map.contains(id));
1925        }
1926        assert!(map.get_fragment_bitmap(0).is_none());
1927
1928        // Remove a value from the full fragment
1929        assert!(map.remove(50));
1930
1931        // Now it should be partial (a full RoaringBitmap minus one value)
1932        assert!(map.contains(0) && !map.contains(50) && map.contains(100));
1933        assert!(map.get_fragment_bitmap(0).is_some());
1934    }
1935
1936    #[test]
1937    fn test_retain_fragments() {
1938        let mut map = RowAddrTreeMap::default();
1939        map.insert(0); // fragment 0
1940        map.insert(1 << 32 | 5); // fragment 1
1941        map.insert(2 << 32 | 10); // fragment 2
1942        map.insert_fragment(3); // fragment 3
1943
1944        map.retain_fragments([0, 2]);
1945
1946        assert!(map.contains(0) && map.contains(2 << 32 | 10));
1947        assert!(!map.contains(1 << 32 | 5) && !map.contains(3 << 32));
1948    }
1949
1950    #[test]
1951    fn test_bitor_assign_full_fragment() {
1952        // Test BitOrAssign when LHS has Full and RHS has Partial
1953        let mut map1 = RowAddrTreeMap::default();
1954        map1.insert_fragment(0);
1955        let mut map2 = RowAddrTreeMap::default();
1956        map2.insert(5);
1957
1958        map1 |= &map2;
1959        // Full | Partial = Full
1960        assert!(map1.contains(0) && map1.contains(5) && map1.contains(100));
1961
1962        // Test BitOrAssign when LHS has Partial and RHS has Full
1963        let mut map3 = RowAddrTreeMap::default();
1964        map3.insert(5);
1965        let mut map4 = RowAddrTreeMap::default();
1966        map4.insert_fragment(0);
1967
1968        map3 |= &map4;
1969        // Partial | Full = Full
1970        assert!(map3.contains(0) && map3.contains(5) && map3.contains(100));
1971    }
1972
1973    #[test]
1974    fn test_bitand_assign_full_fragments() {
1975        // Test BitAndAssign when both have Full for same fragment
1976        let mut map1 = RowAddrTreeMap::default();
1977        map1.insert_fragment(0);
1978        let mut map2 = RowAddrTreeMap::default();
1979        map2.insert_fragment(0);
1980
1981        map1 &= &map2;
1982        // Full & Full = Full
1983        assert!(map1.contains(0) && map1.contains(100));
1984
1985        // Test BitAndAssign when LHS Full, RHS Partial
1986        let mut map3 = RowAddrTreeMap::default();
1987        map3.insert_fragment(0);
1988        let mut map4 = RowAddrTreeMap::default();
1989        map4.insert(5);
1990        map4.insert(10);
1991
1992        map3 &= &map4;
1993        // Full & Partial([5,10]) = Partial([5,10])
1994        assert!(map3.contains(5) && map3.contains(10));
1995        assert!(!map3.contains(0) && !map3.contains(100));
1996
1997        // Test that empty intersection results in removal
1998        let mut map5 = RowAddrTreeMap::default();
1999        map5.insert(5);
2000        let mut map6 = RowAddrTreeMap::default();
2001        map6.insert(10);
2002
2003        map5 &= &map6;
2004        assert!(map5.is_empty());
2005    }
2006
2007    #[test]
2008    fn test_sub_assign_with_full_fragments() {
2009        // Test SubAssign when LHS is Full and RHS is Partial
2010        let mut map1 = RowAddrTreeMap::default();
2011        map1.insert_fragment(0);
2012        let mut map2 = RowAddrTreeMap::default();
2013        map2.insert(5);
2014        map2.insert(10);
2015
2016        map1 -= &map2;
2017        // Full - Partial([5,10]) = Full minus those values
2018        assert!(map1.contains(0) && map1.contains(100));
2019        assert!(!map1.contains(5) && !map1.contains(10));
2020
2021        // Test SubAssign when both are Full for same fragment
2022        let mut map3 = RowAddrTreeMap::default();
2023        map3.insert_fragment(0);
2024        let mut map4 = RowAddrTreeMap::default();
2025        map4.insert_fragment(0);
2026
2027        map3 -= &map4;
2028        // Full - Full = empty
2029        assert!(map3.is_empty());
2030
2031        // Test SubAssign when LHS is Partial and RHS is Full
2032        let mut map5 = RowAddrTreeMap::default();
2033        map5.insert(5);
2034        map5.insert(10);
2035        let mut map6 = RowAddrTreeMap::default();
2036        map6.insert_fragment(0);
2037
2038        map5 -= &map6;
2039        // Partial - Full = empty
2040        assert!(map5.is_empty());
2041    }
2042
2043    #[test]
2044    fn test_from_iterator_with_full_fragment() {
2045        // Test that inserting into a full fragment is a no-op
2046        let mut map = RowAddrTreeMap::default();
2047        map.insert_fragment(0);
2048
2049        // Extend with values that would go into fragment 0
2050        map.extend([5u64, 10, 100].iter());
2051
2052        // Should still be full fragment
2053        for id in [0, 5, 10, 100, u32::MAX as u64] {
2054            assert!(map.contains(id));
2055        }
2056    }
2057
2058    #[test]
2059    fn test_insert_range_excluded_end() {
2060        // Test excluded end bound (line 391-393)
2061        let mut map = RowAddrTreeMap::default();
2062        // Using RangeFrom with small range won't hit the unbounded case
2063        // Instead test Bound::Excluded for end
2064        let count = map.insert_range((std::ops::Bound::Included(5), std::ops::Bound::Excluded(10)));
2065        assert_eq!(count, 5); // 5, 6, 7, 8, 9
2066        assert!(map.contains(5));
2067        assert!(map.contains(9));
2068        assert!(!map.contains(10));
2069    }
2070
2071    #[test]
2072    fn test_bitand_assign_owned() {
2073        // Test BitAndAssign<Self> (owned, not reference)
2074        let mut map1 = RowAddrTreeMap::default();
2075        map1.insert(5);
2076        map1.insert(10);
2077
2078        // Using owned rhs (not reference)
2079        map1 &= rows(&[5, 15]);
2080
2081        assert!(map1.contains(5));
2082        assert!(!map1.contains(10) && !map1.contains(15));
2083    }
2084
2085    #[test]
2086    fn test_from_iter_with_full_fragment() {
2087        // When we collect into RowAddrTreeMap, it should handle duplicates
2088        let map: RowAddrTreeMap = vec![5u64, 10, 100].into_iter().collect();
2089        assert!(map.contains(5) && map.contains(10));
2090
2091        // Test that extending a map with full fragment ignores new values
2092        let mut map = RowAddrTreeMap::default();
2093        map.insert_fragment(0);
2094        for val in [5, 10, 100] {
2095            map.insert(val); // This should be no-op since fragment is full
2096        }
2097        // Still full fragment
2098        for id in [0, 5, u32::MAX as u64] {
2099            assert!(map.contains(id));
2100        }
2101    }
2102
2103    // ============================================================================
2104    // Tests for bitmap_to_ranges / ranges_to_bitmap
2105    // ============================================================================
2106
2107    #[test]
2108    fn test_bitmap_to_ranges_empty() {
2109        let bm = RoaringBitmap::new();
2110        assert!(bitmap_to_ranges(&bm).is_empty());
2111    }
2112
2113    #[test]
2114    fn test_bitmap_to_ranges_single() {
2115        let bm = RoaringBitmap::from_iter([5]);
2116        assert_eq!(bitmap_to_ranges(&bm), vec![5..6]);
2117    }
2118
2119    #[test]
2120    fn test_bitmap_to_ranges_contiguous() {
2121        let mut bm = RoaringBitmap::new();
2122        bm.insert_range(10..20);
2123        assert_eq!(bitmap_to_ranges(&bm), vec![10..20]);
2124    }
2125
2126    #[test]
2127    fn test_bitmap_to_ranges_multiple() {
2128        let mut bm = RoaringBitmap::new();
2129        bm.insert_range(0..3);
2130        bm.insert_range(10..15);
2131        bm.insert(100);
2132        assert_eq!(bitmap_to_ranges(&bm), vec![0..3, 10..15, 100..101]);
2133    }
2134
2135    #[test]
2136    fn test_ranges_to_bitmap_empty() {
2137        let bm = ranges_to_bitmap(&[], true);
2138        assert!(bm.is_empty());
2139    }
2140
2141    #[test]
2142    fn test_ranges_to_bitmap_sorted_short_ranges() {
2143        // avg len = 1, uses from_sorted_iter path
2144        let ranges = vec![0..1, 5..6, 10..11];
2145        let bm = ranges_to_bitmap(&ranges, true);
2146        assert!(bm.contains(0) && bm.contains(5) && bm.contains(10));
2147        assert_eq!(bm.len(), 3);
2148    }
2149
2150    #[test]
2151    fn test_ranges_to_bitmap_sorted_long_ranges() {
2152        // avg len = 100, uses insert_range path
2153        let ranges = vec![0..100, 200..300];
2154        let bm = ranges_to_bitmap(&ranges, true);
2155        assert_eq!(bm.len(), 200);
2156        assert!(bm.contains(0) && bm.contains(99));
2157        assert!(!bm.contains(100));
2158        assert!(bm.contains(200) && bm.contains(299));
2159    }
2160
2161    #[test]
2162    fn test_ranges_to_bitmap_unsorted() {
2163        let ranges = vec![200..300, 0..100];
2164        let bm = ranges_to_bitmap(&ranges, false);
2165        assert_eq!(bm.len(), 200);
2166        assert!(bm.contains(0) && bm.contains(250));
2167    }
2168
2169    #[test]
2170    fn test_bitmap_ranges_roundtrip() {
2171        let mut original = RoaringBitmap::new();
2172        original.insert_range(0..50);
2173        original.insert_range(100..200);
2174        original.insert(500);
2175        original.insert_range(1000..1010);
2176
2177        let ranges = bitmap_to_ranges(&original);
2178        let reconstructed = ranges_to_bitmap(&ranges, true);
2179        assert_eq!(original, reconstructed);
2180    }
2181
2182    // ============================================================================
2183    // Tests for RowIdSet
2184    // ============================================================================
2185
2186    fn row_ids(ids: &[u64]) -> RowIdSet {
2187        let mut set = RowIdSet::new();
2188        for &id in ids {
2189            set.inner.insert(id);
2190        }
2191        set
2192    }
2193
2194    #[test]
2195    fn test_row_id_set_construction() {
2196        let set = RowIdSet::new();
2197        assert!(set.is_empty());
2198        assert_eq!(set.len(), Some(0));
2199
2200        let set = row_ids(&[10, 20, 30]);
2201        assert!(!set.is_empty());
2202        assert_eq!(set.len(), Some(3));
2203        assert!(set.contains(10));
2204        assert!(set.contains(20));
2205        assert!(set.contains(30));
2206        assert!(!set.contains(15));
2207    }
2208
2209    #[test]
2210    fn test_row_id_set_remove() {
2211        let mut set = row_ids(&[10, 20, 30]);
2212
2213        assert!(!set.remove(15)); // Not present
2214        assert_eq!(set.len(), Some(3));
2215
2216        assert!(set.remove(20)); // Present
2217        assert_eq!(set.len(), Some(2));
2218        assert!(!set.contains(20));
2219        assert!(set.contains(10));
2220        assert!(set.contains(30));
2221
2222        assert!(!set.remove(20)); // Already removed
2223    }
2224
2225    #[test]
2226    fn test_row_id_set_union() {
2227        let set1 = row_ids(&[10, 20, 30]);
2228        let set2 = row_ids(&[20, 30, 40]);
2229
2230        let result = set1.union(&set2);
2231        assert_eq!(result.len(), Some(4));
2232        for id in [10, 20, 30, 40] {
2233            assert!(result.contains(id));
2234        }
2235    }
2236
2237    #[test]
2238    fn test_row_id_set_difference() {
2239        let set1 = row_ids(&[10, 20, 30, 40]);
2240        let set2 = row_ids(&[20, 40]);
2241
2242        let result = set1.difference(&set2);
2243        assert_eq!(result.len(), Some(2));
2244        assert!(result.contains(10));
2245        assert!(result.contains(30));
2246        assert!(!result.contains(20));
2247        assert!(!result.contains(40));
2248    }
2249
2250    #[test]
2251    fn test_row_id_set_union_all() {
2252        let set1 = row_ids(&[10, 20]);
2253        let set2 = row_ids(&[20, 30]);
2254        let set3 = row_ids(&[30, 40]);
2255
2256        let result = RowIdSet::union_all(&[&set1, &set2, &set3]);
2257        assert_eq!(result.len(), Some(4));
2258        for id in [10, 20, 30, 40] {
2259            assert!(result.contains(id));
2260        }
2261
2262        // Empty slice should return empty set
2263        let result = RowIdSet::union_all(&[]);
2264        assert!(result.is_empty());
2265    }
2266
2267    #[test]
2268    fn test_row_id_set_iter() {
2269        let set = row_ids(&[10, 20, 30]);
2270        let collected: Vec<u64> = set.iter().collect();
2271        assert_eq!(collected, vec![10, 20, 30]);
2272
2273        let empty = RowIdSet::new();
2274        assert_eq!(empty.iter().count(), 0);
2275    }
2276
2277    #[test]
2278    fn test_row_id_set_from_sorted_iter() {
2279        // Valid sorted input
2280        let set = RowIdSet::from_sorted_iter([10, 20, 30, 40]).unwrap();
2281        assert_eq!(set.len(), Some(4));
2282        for id in [10, 20, 30, 40] {
2283            assert!(set.contains(id));
2284        }
2285
2286        // Empty iterator
2287        let set = RowIdSet::from_sorted_iter(std::iter::empty()).unwrap();
2288        assert!(set.is_empty());
2289
2290        // Single element
2291        let set = RowIdSet::from_sorted_iter([42]).unwrap();
2292        assert_eq!(set.len(), Some(1));
2293        assert!(set.contains(42));
2294    }
2295
2296    #[test]
2297    fn test_row_id_set_from_sorted_iter_unsorted() {
2298        // Non-sorted input should return error
2299        let result = RowIdSet::from_sorted_iter([30, 10, 20]);
2300        assert!(result.is_err());
2301        assert!(result.unwrap_err().to_string().contains("non-sorted"));
2302    }
2303
2304    #[test]
2305    fn test_row_id_set_large_values() {
2306        // Test with large u64 values
2307        let large_ids = [u64::MAX - 10, u64::MAX - 5, u64::MAX - 1];
2308        let set = row_ids(&large_ids);
2309
2310        for &id in &large_ids {
2311            assert!(set.contains(id));
2312        }
2313        assert!(!set.contains(u64::MAX));
2314        assert_eq!(set.len(), Some(3));
2315    }
2316
2317    // ============================================================================
2318    // Tests for RowIdMask
2319    // ============================================================================
2320
2321    fn assert_row_id_mask_selects(mask: &RowIdMask, selected: &[u64], not_selected: &[u64]) {
2322        for &id in selected {
2323            assert!(mask.selected(id), "Expected row id {} to be selected", id);
2324        }
2325        for &id in not_selected {
2326            assert!(
2327                !mask.selected(id),
2328                "Expected row id {} to NOT be selected",
2329                id
2330            );
2331        }
2332    }
2333
2334    #[test]
2335    fn test_row_id_mask_construction() {
2336        let full_mask = RowIdMask::all_rows();
2337        assert_eq!(full_mask.max_len(), None);
2338        assert_row_id_mask_selects(&full_mask, &[0, 1, 100, u64::MAX - 1], &[]);
2339
2340        let empty_mask = RowIdMask::allow_nothing();
2341        assert_eq!(empty_mask.max_len(), Some(0));
2342        assert_row_id_mask_selects(&empty_mask, &[], &[0, 1, 100]);
2343
2344        let allow_list = RowIdMask::from_allowed(row_ids(&[10, 20, 30]));
2345        assert_eq!(allow_list.max_len(), Some(3));
2346        assert_row_id_mask_selects(&allow_list, &[10, 20, 30], &[0, 15, 25, 40]);
2347
2348        let block_list = RowIdMask::from_block(row_ids(&[10, 20, 30]));
2349        assert_eq!(block_list.max_len(), None);
2350        assert_row_id_mask_selects(&block_list, &[0, 15, 25, 40], &[10, 20, 30]);
2351    }
2352
2353    #[test]
2354    fn test_row_id_mask_selected_indices() {
2355        // Allow list
2356        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 40]));
2357        assert!(mask.selected_indices(std::iter::empty()).is_empty());
2358        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[1, 3]);
2359
2360        // Block list
2361        let mask = RowIdMask::from_block(row_ids(&[10, 20, 40]));
2362        assert!(mask.selected_indices(std::iter::empty()).is_empty());
2363        assert_eq!(mask.selected_indices([25, 20, 14, 10].iter()), &[0, 2]);
2364    }
2365
2366    #[test]
2367    fn test_row_id_mask_also_allow() {
2368        // Allow list
2369        let mask = RowIdMask::from_allowed(row_ids(&[10, 20]));
2370        let new_mask = mask.also_allow(row_ids(&[20, 30, 40]));
2371        assert_eq!(
2372            new_mask,
2373            RowIdMask::from_allowed(row_ids(&[10, 20, 30, 40]))
2374        );
2375
2376        // Block list
2377        let mask = RowIdMask::from_block(row_ids(&[10, 20, 30]));
2378        let new_mask = mask.also_allow(row_ids(&[20, 40]));
2379        assert_eq!(new_mask, RowIdMask::from_block(row_ids(&[10, 30])));
2380    }
2381
2382    #[test]
2383    fn test_row_id_mask_also_block() {
2384        // Allow list
2385        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 30]));
2386        let new_mask = mask.also_block(row_ids(&[20, 40]));
2387        assert_eq!(new_mask, RowIdMask::from_allowed(row_ids(&[10, 30])));
2388
2389        // Block list
2390        let mask = RowIdMask::from_block(row_ids(&[10, 20]));
2391        let new_mask = mask.also_block(row_ids(&[20, 30, 40]));
2392        assert_eq!(new_mask, RowIdMask::from_block(row_ids(&[10, 20, 30, 40])));
2393    }
2394
2395    #[test]
2396    fn test_row_id_mask_iter_ids() {
2397        // Allow list
2398        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 30]));
2399        let ids: Vec<u64> = mask.iter_ids().unwrap().collect();
2400        assert_eq!(ids, vec![10, 20, 30]);
2401
2402        // Empty allow list
2403        let mask = RowIdMask::allow_nothing();
2404        let iter = mask.iter_ids();
2405        assert!(iter.is_some());
2406        assert_eq!(iter.unwrap().count(), 0);
2407
2408        // Block list
2409        let mask = RowIdMask::from_block(row_ids(&[10, 20, 30]));
2410        assert!(mask.iter_ids().is_none());
2411    }
2412
2413    #[test]
2414    fn test_row_id_mask_default() {
2415        let mask = RowIdMask::default();
2416        // Default should be BlockList with empty set (all rows allowed)
2417        assert_row_id_mask_selects(&mask, &[0, 1, 100, 1000], &[]);
2418        assert_eq!(mask.max_len(), None);
2419    }
2420
2421    #[test]
2422    fn test_row_id_mask_ops() {
2423        let mask = RowIdMask::default();
2424        assert_row_id_mask_selects(&mask, &[1, 5, 100], &[]);
2425
2426        let block_list = mask.also_block(row_ids(&[0, 5, 15]));
2427        assert_row_id_mask_selects(&block_list, &[1, 100], &[5]);
2428
2429        let allow_list = RowIdMask::from_allowed(row_ids(&[0, 2, 5]));
2430        assert_row_id_mask_selects(&allow_list, &[5], &[1, 100]);
2431    }
2432
2433    #[test]
2434    fn test_row_id_mask_combined_ops() {
2435        // Test combining allow and block operations
2436        let mask = RowIdMask::from_allowed(row_ids(&[10, 20, 30, 40, 50]));
2437        let mask = mask.also_block(row_ids(&[20, 40]));
2438        assert_row_id_mask_selects(&mask, &[10, 30, 50], &[20, 40]);
2439
2440        let mask = mask.also_allow(row_ids(&[20, 60]));
2441        assert_row_id_mask_selects(&mask, &[10, 20, 30, 50, 60], &[40]);
2442    }
2443
2444    #[test]
2445    fn test_row_id_mask_with_large_values() {
2446        let large_ids = [u64::MAX - 10, u64::MAX - 5, u64::MAX - 1];
2447
2448        // Allow list with large values
2449        let mask = RowIdMask::from_allowed(row_ids(&large_ids));
2450        for &id in &large_ids {
2451            assert!(mask.selected(id));
2452        }
2453        assert!(!mask.selected(u64::MAX));
2454        assert!(!mask.selected(0));
2455
2456        // Block list with large values
2457        let mask = RowIdMask::from_block(row_ids(&large_ids));
2458        for &id in &large_ids {
2459            assert!(!mask.selected(id));
2460        }
2461        assert!(mask.selected(u64::MAX));
2462        assert!(mask.selected(0));
2463    }
2464
2465    proptest::proptest! {
2466        #[test]
2467        fn test_row_id_set_from_sorted_iter_proptest(
2468            mut row_ids in proptest::collection::vec(0..u64::MAX, 0..1000)
2469        ) {
2470            row_ids.sort();
2471            row_ids.dedup();
2472            let num_rows = row_ids.len();
2473            let set = RowIdSet::from_sorted_iter(row_ids.clone()).unwrap();
2474            prop_assert_eq!(set.len(), Some(num_rows as u64));
2475            for id in row_ids {
2476                prop_assert!(set.contains(id));
2477            }
2478        }
2479
2480        #[test]
2481        fn test_row_id_set_union_proptest(
2482            ids1 in proptest::collection::vec(0..u64::MAX, 0..500),
2483            ids2 in proptest::collection::vec(0..u64::MAX, 0..500),
2484        ) {
2485            let set1 = row_ids(&ids1);
2486            let set2 = row_ids(&ids2);
2487
2488            let result = set1.union(&set2);
2489
2490            // All ids from both sets should be in result
2491            for id in ids1.iter().chain(ids2.iter()) {
2492                prop_assert!(result.contains(*id));
2493            }
2494
2495            // Result size should be union size
2496            let expected_size = ids1.iter().chain(ids2.iter()).collect::<std::collections::HashSet<_>>().len();
2497            prop_assert_eq!(result.len(), Some(expected_size as u64));
2498        }
2499
2500        #[test]
2501        fn test_row_id_set_difference_proptest(
2502            ids1 in proptest::collection::vec(0..u64::MAX, 0..500),
2503            ids2 in proptest::collection::vec(0..u64::MAX, 0..500),
2504        ) {
2505            let set1 = row_ids(&ids1);
2506            let set2 = row_ids(&ids2);
2507
2508            let result = set1.difference(&set2);
2509
2510            // Items in ids1 but not in ids2 should be in result
2511            for id in &ids1 {
2512                if !ids2.contains(id) {
2513                    prop_assert!(result.contains(*id));
2514                } else {
2515                    prop_assert!(!result.contains(*id));
2516                }
2517            }
2518        }
2519
2520        #[test]
2521        fn test_row_id_mask_allow_block_proptest(
2522            allow_ids in proptest::collection::vec(0..10000u64, 0..100),
2523            block_ids in proptest::collection::vec(0..10000u64, 0..100),
2524            test_ids in proptest::collection::vec(0..10000u64, 0..50),
2525        ) {
2526            let mask = RowIdMask::from_allowed(row_ids(&allow_ids))
2527                .also_block(row_ids(&block_ids));
2528
2529            for id in test_ids {
2530                let expected = allow_ids.contains(&id) && !block_ids.contains(&id);
2531                prop_assert_eq!(mask.selected(id), expected);
2532            }
2533        }
2534    }
2535}