Skip to main content

formualizer_eval/engine/
row_visibility.rs

1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2pub enum RowVisibilitySource {
3    Manual,
4    Filter,
5}
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum VisibilityMaskMode {
9    IncludeAll,
10    ExcludeManualHidden,
11    ExcludeFilterHidden,
12    ExcludeManualOrFilterHidden,
13}
14
15#[derive(Debug, Clone, Default, PartialEq, Eq)]
16struct RowBitSet {
17    words: Vec<u64>,
18}
19
20impl RowBitSet {
21    fn is_empty(&self) -> bool {
22        self.words.iter().all(|w| *w == 0)
23    }
24
25    fn get(&self, row0: u32) -> bool {
26        let word_idx = (row0 / 64) as usize;
27        let bit_idx = row0 % 64;
28        self.words
29            .get(word_idx)
30            .map(|word| (word & (1u64 << bit_idx)) != 0)
31            .unwrap_or(false)
32    }
33
34    fn set(&mut self, row0: u32, hidden: bool) -> bool {
35        let word_idx = (row0 / 64) as usize;
36        let bit_idx = row0 % 64;
37
38        if word_idx >= self.words.len() {
39            if !hidden {
40                return false;
41            }
42            self.words.resize(word_idx + 1, 0);
43        }
44
45        let mask = 1u64 << bit_idx;
46        let word = &mut self.words[word_idx];
47        let old = (*word & mask) != 0;
48        if old == hidden {
49            return false;
50        }
51
52        if hidden {
53            *word |= mask;
54        } else {
55            *word &= !mask;
56            self.trim_trailing_zeros();
57        }
58        true
59    }
60
61    fn set_range(&mut self, start_row0: u32, end_row0: u32, hidden: bool) -> bool {
62        if start_row0 > end_row0 {
63            return false;
64        }
65
66        let mut changed = false;
67        for row0 in start_row0..=end_row0 {
68            changed |= self.set(row0, hidden);
69        }
70        changed
71    }
72
73    fn insert_rows(&mut self, before0: u32, count: u32) -> bool {
74        if count == 0 {
75            return false;
76        }
77
78        let old_rows = self.collect_set_rows();
79        if old_rows.is_empty() {
80            return false;
81        }
82
83        let mut changed = false;
84        let mut new_rows = Vec::with_capacity(old_rows.len());
85        for row0 in old_rows {
86            let shifted = if row0 >= before0 {
87                changed = true;
88                row0.saturating_add(count)
89            } else {
90                row0
91            };
92            new_rows.push(shifted);
93        }
94
95        if changed {
96            self.rebuild_from_set_rows(&new_rows);
97        }
98        changed
99    }
100
101    fn delete_rows(&mut self, start0: u32, count: u32) -> bool {
102        if count == 0 {
103            return false;
104        }
105
106        let old_rows = self.collect_set_rows();
107        if old_rows.is_empty() {
108            return false;
109        }
110
111        let end0 = start0.saturating_add(count.saturating_sub(1));
112        let mut changed = false;
113        let mut new_rows = Vec::with_capacity(old_rows.len());
114
115        for row0 in old_rows {
116            if row0 < start0 {
117                new_rows.push(row0);
118                continue;
119            }
120            if row0 <= end0 {
121                changed = true;
122                continue;
123            }
124
125            changed = true;
126            new_rows.push(row0 - count);
127        }
128
129        if changed {
130            self.rebuild_from_set_rows(&new_rows);
131        }
132        changed
133    }
134
135    fn collect_set_rows(&self) -> Vec<u32> {
136        let mut rows = Vec::new();
137        for (word_idx, word) in self.words.iter().copied().enumerate() {
138            let mut bits = word;
139            while bits != 0 {
140                let tz = bits.trailing_zeros();
141                rows.push((word_idx as u32) * 64 + tz);
142                bits &= bits - 1;
143            }
144        }
145        rows
146    }
147
148    fn rebuild_from_set_rows(&mut self, rows: &[u32]) {
149        self.words.clear();
150        for row0 in rows {
151            let _ = self.set(*row0, true);
152        }
153    }
154
155    fn trim_trailing_zeros(&mut self) {
156        while self.words.last().copied() == Some(0) {
157            self.words.pop();
158        }
159    }
160}
161
162#[derive(Debug, Clone, Default, PartialEq, Eq)]
163pub struct RowVisibilityState {
164    manual_hidden: RowBitSet,
165    filter_hidden: RowBitSet,
166    version: u64,
167}
168
169impl RowVisibilityState {
170    pub fn version(&self) -> u64 {
171        self.version
172    }
173
174    pub fn is_empty(&self) -> bool {
175        self.manual_hidden.is_empty() && self.filter_hidden.is_empty()
176    }
177
178    pub fn set_row_hidden(&mut self, row0: u32, hidden: bool, source: RowVisibilitySource) -> bool {
179        let changed = match source {
180            RowVisibilitySource::Manual => self.manual_hidden.set(row0, hidden),
181            RowVisibilitySource::Filter => self.filter_hidden.set(row0, hidden),
182        };
183        if changed {
184            self.version = self.version.saturating_add(1);
185        }
186        changed
187    }
188
189    pub fn set_rows_hidden(
190        &mut self,
191        start_row0: u32,
192        end_row0: u32,
193        hidden: bool,
194        source: RowVisibilitySource,
195    ) -> bool {
196        let changed = match source {
197            RowVisibilitySource::Manual => {
198                self.manual_hidden.set_range(start_row0, end_row0, hidden)
199            }
200            RowVisibilitySource::Filter => {
201                self.filter_hidden.set_range(start_row0, end_row0, hidden)
202            }
203        };
204        if changed {
205            self.version = self.version.saturating_add(1);
206        }
207        changed
208    }
209
210    pub fn is_row_hidden(&self, row0: u32, source: Option<RowVisibilitySource>) -> bool {
211        match source {
212            Some(RowVisibilitySource::Manual) => self.manual_hidden.get(row0),
213            Some(RowVisibilitySource::Filter) => self.filter_hidden.get(row0),
214            None => self.manual_hidden.get(row0) || self.filter_hidden.get(row0),
215        }
216    }
217
218    pub fn rows_hidden(
219        &self,
220        start_row0: u32,
221        end_row0: u32,
222        source: Option<RowVisibilitySource>,
223    ) -> Vec<bool> {
224        if start_row0 > end_row0 {
225            return Vec::new();
226        }
227        (start_row0..=end_row0)
228            .map(|row0| self.is_row_hidden(row0, source))
229            .collect()
230    }
231
232    pub fn insert_rows(&mut self, before0: u32, count: u32) -> bool {
233        let changed = self.manual_hidden.insert_rows(before0, count)
234            | self.filter_hidden.insert_rows(before0, count);
235        if changed {
236            self.version = self.version.saturating_add(1);
237        }
238        changed
239    }
240
241    pub fn delete_rows(&mut self, start0: u32, count: u32) -> bool {
242        let changed = self.manual_hidden.delete_rows(start0, count)
243            | self.filter_hidden.delete_rows(start0, count);
244        if changed {
245            self.version = self.version.saturating_add(1);
246        }
247        changed
248    }
249}