1use std::collections::HashMap;
17
18use rucc_base::Symbol;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub struct HideSet(u32);
26
27impl HideSet {
28 pub const EMPTY: HideSet = HideSet(0);
33
34 #[inline]
36 pub const fn is_empty(self) -> bool {
37 self.0 == 0
38 }
39
40 #[inline]
42 pub const fn raw(self) -> u32 {
43 self.0
44 }
45}
46
47#[derive(Debug)]
52pub struct HideSets {
53 sets: Vec<Box<[Symbol]>>,
55 map: HashMap<Box<[Symbol]>, HideSet>,
57}
58
59impl Default for HideSets {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl HideSets {
66 pub fn new() -> Self {
68 let empty: Box<[Symbol]> = Box::new([]);
69 let mut map = HashMap::new();
70 map.insert(empty.clone(), HideSet::EMPTY);
71 Self { sets: vec![empty], map }
72 }
73
74 pub fn members(&self, set: HideSet) -> &[Symbol] {
80 &self.sets[set.0 as usize]
81 }
82
83 pub fn len(&self) -> usize {
86 self.sets.len()
87 }
88
89 pub fn is_empty(&self) -> bool {
91 false
92 }
93
94 #[inline]
100 pub fn contains(&self, set: HideSet, name: Symbol) -> bool {
101 !set.is_empty() && self.sets[set.0 as usize].binary_search(&name).is_ok()
104 }
105
106 pub fn add(&mut self, set: HideSet, name: Symbol) -> HideSet {
113 let current = &self.sets[set.0 as usize];
114 let Err(at) = current.binary_search(&name) else {
115 return set;
116 };
117 let mut next = Vec::with_capacity(current.len() + 1);
118 next.extend_from_slice(¤t[..at]);
119 next.push(name);
120 next.extend_from_slice(¤t[at..]);
121 self.insert(next)
122 }
123
124 pub fn union(&mut self, a: HideSet, b: HideSet) -> HideSet {
134 if a == b || b.is_empty() {
135 return a;
136 }
137 if a.is_empty() {
138 return b;
139 }
140 let merged = merge(&self.sets[a.0 as usize], &self.sets[b.0 as usize], Merge::Union);
141 self.insert(merged)
142 }
143
144 pub fn intersect(&mut self, a: HideSet, b: HideSet) -> HideSet {
154 if a == b {
155 return a;
156 }
157 if a.is_empty() || b.is_empty() {
158 return HideSet::EMPTY;
159 }
160 let merged = merge(&self.sets[a.0 as usize], &self.sets[b.0 as usize], Merge::Intersect);
161 self.insert(merged)
162 }
163
164 fn insert(&mut self, sorted: Vec<Symbol>) -> HideSet {
166 let sorted: Box<[Symbol]> = sorted.into_boxed_slice();
167 if let Some(&found) = self.map.get(&sorted) {
168 return found;
169 }
170 let id = HideSet(u32::try_from(self.sets.len()).expect("too many hide sets"));
171 self.sets.push(sorted.clone());
172 self.map.insert(sorted, id);
173 id
174 }
175}
176
177#[derive(Clone, Copy)]
179enum Merge {
180 Union,
181 Intersect,
182}
183
184fn merge(a: &[Symbol], b: &[Symbol], op: Merge) -> Vec<Symbol> {
187 let mut out = Vec::with_capacity(match op {
188 Merge::Union => a.len() + b.len(),
189 Merge::Intersect => a.len().min(b.len()),
190 });
191 let (mut i, mut j) = (0, 0);
192 while i < a.len() && j < b.len() {
193 match a[i].cmp(&b[j]) {
194 std::cmp::Ordering::Less => {
195 if matches!(op, Merge::Union) {
196 out.push(a[i]);
197 }
198 i += 1;
199 }
200 std::cmp::Ordering::Greater => {
201 if matches!(op, Merge::Union) {
202 out.push(b[j]);
203 }
204 j += 1;
205 }
206 std::cmp::Ordering::Equal => {
207 out.push(a[i]);
208 i += 1;
209 j += 1;
210 }
211 }
212 }
213 if matches!(op, Merge::Union) {
214 out.extend_from_slice(&a[i..]);
215 out.extend_from_slice(&b[j..]);
216 }
217 out
218}
219
220#[cfg(test)]
221mod tests {
222 use rucc_base::Interner;
223
224 use super::*;
225
226 fn syms(n: usize) -> (Interner, Vec<Symbol>) {
227 let mut interner = Interner::new();
228 let names = (0..n).map(|i| interner.intern(&format!("M{i}"))).collect();
229 (interner, names)
230 }
231
232 #[test]
233 fn the_empty_set_is_index_zero_and_hides_nothing() {
234 let (_i, s) = syms(1);
235 let sets = HideSets::new();
236 assert_eq!(HideSet::EMPTY.raw(), 0);
237 assert!(!sets.contains(HideSet::EMPTY, s[0]));
238 }
239
240 #[test]
241 fn adding_a_name_makes_it_hidden() {
242 let (_i, s) = syms(2);
243 let mut sets = HideSets::new();
244 let one = sets.add(HideSet::EMPTY, s[0]);
245 assert!(sets.contains(one, s[0]));
246 assert!(!sets.contains(one, s[1]));
247 }
248
249 #[test]
250 fn adding_the_same_name_twice_changes_nothing() {
251 let (_i, s) = syms(1);
252 let mut sets = HideSets::new();
253 let one = sets.add(HideSet::EMPTY, s[0]);
254 assert_eq!(sets.add(one, s[0]), one);
255 }
256
257 #[test]
258 fn sets_built_in_different_orders_are_the_same_set() {
259 let (_i, s) = syms(3);
260 let mut sets = HideSets::new();
261 let forward = {
262 let a = sets.add(HideSet::EMPTY, s[0]);
263 let b = sets.add(a, s[1]);
264 sets.add(b, s[2])
265 };
266 let backward = {
267 let a = sets.add(HideSet::EMPTY, s[2]);
268 let b = sets.add(a, s[0]);
269 sets.add(b, s[1])
270 };
271 assert_eq!(forward, backward, "interning must not depend on insertion order");
272 assert_eq!(sets.members(forward).len(), 3);
273 }
274
275 #[test]
276 fn union_keeps_everything_from_both() {
277 let (_i, s) = syms(3);
278 let mut sets = HideSets::new();
279 let a = sets.add(HideSet::EMPTY, s[0]);
280 let a = sets.add(a, s[1]);
281 let b = sets.add(HideSet::EMPTY, s[1]);
282 let b = sets.add(b, s[2]);
283 let u = sets.union(a, b);
284 assert_eq!(sets.members(u), &[s[0], s[1], s[2]]);
285 }
286
287 #[test]
288 fn intersect_keeps_only_what_is_in_both() {
289 let (_i, s) = syms(3);
290 let mut sets = HideSets::new();
291 let a = sets.add(HideSet::EMPTY, s[0]);
292 let a = sets.add(a, s[1]);
293 let b = sets.add(HideSet::EMPTY, s[1]);
294 let b = sets.add(b, s[2]);
295 let x = sets.intersect(a, b);
296 assert_eq!(sets.members(x), &[s[1]]);
297 }
298
299 #[test]
300 fn intersecting_with_the_empty_set_is_empty() {
301 let (_i, s) = syms(1);
302 let mut sets = HideSets::new();
303 let a = sets.add(HideSet::EMPTY, s[0]);
304 assert_eq!(sets.intersect(a, HideSet::EMPTY), HideSet::EMPTY);
305 }
306
307 #[test]
308 fn a_hide_set_is_four_bytes() {
309 assert_eq!(size_of::<HideSet>(), 4);
310 }
311}