revmc_codegen/bytecode/
interner.rs1use indexmap::IndexSet;
2use oxc_index::Idx;
3use std::hash::{BuildHasher, Hash};
4
5pub(crate) struct Interner<I: Idx, T, S = alloy_primitives::map::DefaultHashBuilder> {
10 set: IndexSet<T, S>,
11 _marker: std::marker::PhantomData<fn() -> I>,
12}
13
14impl<I: Idx, T: Hash + Eq, S: BuildHasher + Default> Default for Interner<I, T, S> {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl<I: Idx, T: Hash + Eq, S: BuildHasher + Default> Interner<I, T, S> {
21 pub(crate) fn new() -> Self {
22 Self::with_capacity(0)
23 }
24
25 pub(crate) fn with_capacity(capacity: usize) -> Self {
26 Self {
27 set: IndexSet::with_capacity_and_hasher(capacity, S::default()),
28 _marker: std::marker::PhantomData,
29 }
30 }
31
32 pub(crate) fn intern(&mut self, value: T) -> I {
34 let (idx, _) = self.set.insert_full(value);
35 I::from_usize(idx)
36 }
37}
38
39impl<I: Idx, T, S> Interner<I, T, S> {
40 #[inline]
42 pub(crate) fn get(&self, idx: I) -> &T {
43 &self.set[idx.index()]
44 }
45
46 #[inline]
47 #[allow(dead_code)]
48 pub(crate) fn len(&self) -> usize {
49 self.set.len()
50 }
51}
52
53impl<I: Idx, T, S> std::ops::Index<I> for Interner<I, T, S> {
54 type Output = T;
55
56 #[inline]
57 fn index(&self, idx: I) -> &T {
58 &self.set[idx.index()]
59 }
60}
61
62impl<I: Idx, T: std::fmt::Debug, S> std::fmt::Debug for Interner<I, T, S> {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 f.debug_set().entries(self.set.iter()).finish()
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::bytecode::Inst as TestIdx;
72
73 #[test]
74 fn deduplication() {
75 let mut interner = Interner::<TestIdx, &str>::new();
76 let a = interner.intern("hello");
77 let b = interner.intern("world");
78 let c = interner.intern("hello");
79 assert_eq!(a, c);
80 assert_ne!(a, b);
81 assert_eq!(interner.len(), 2);
82 }
83
84 #[test]
85 fn get_and_index() {
86 let mut interner = Interner::<TestIdx, u64>::new();
87 let idx = interner.intern(42);
88 assert_eq!(*interner.get(idx), 42);
89 assert_eq!(interner[idx], 42);
90 }
91
92 #[test]
93 fn stable_indices() {
94 let mut interner = Interner::<TestIdx, u64>::new();
95 let indices: Vec<_> = (0..100).map(|i| interner.intern(i)).collect();
96 for i in 0..100u64 {
98 assert_eq!(interner.intern(i), indices[i as usize]);
99 }
100 assert_eq!(interner.len(), 100);
101 }
102
103 #[test]
104 fn with_capacity() {
105 let mut interner = Interner::<TestIdx, &str>::with_capacity(16);
106 let idx = interner.intern("test");
107 assert_eq!(*interner.get(idx), "test");
108 }
109}