libperl_macrogen/
intern.rs1use std::collections::HashMap;
2
3#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
9pub struct InternedStr(u32);
10
11impl InternedStr {
12 pub fn as_u32(self) -> u32 {
14 self.0
15 }
16}
17
18#[derive(Clone, Debug, Default)]
20pub struct StringInterner {
21 strings: Vec<String>,
22 map: HashMap<String, InternedStr>,
23}
24
25impl StringInterner {
26 pub fn new() -> Self {
28 Self {
29 strings: Vec::new(),
30 map: HashMap::new(),
31 }
32 }
33
34 pub fn intern(&mut self, s: &str) -> InternedStr {
36 if let Some(&id) = self.map.get(s) {
37 return id;
38 }
39 let id = InternedStr(self.strings.len() as u32);
40 self.strings.push(s.to_owned());
41 self.map.insert(s.to_owned(), id);
42 id
43 }
44
45 pub fn get(&self, id: InternedStr) -> &str {
47 &self.strings[id.0 as usize]
48 }
49
50 pub fn lookup(&self, s: &str) -> Option<InternedStr> {
52 self.map.get(s).copied()
53 }
54
55 pub fn len(&self) -> usize {
57 self.strings.len()
58 }
59
60 pub fn is_empty(&self) -> bool {
62 self.strings.is_empty()
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_intern_new_string() {
72 let mut interner = StringInterner::new();
73 let id1 = interner.intern("hello");
74 let id2 = interner.intern("world");
75
76 assert_ne!(id1, id2);
77 assert_eq!(interner.get(id1), "hello");
78 assert_eq!(interner.get(id2), "world");
79 }
80
81 #[test]
82 fn test_intern_same_string() {
83 let mut interner = StringInterner::new();
84 let id1 = interner.intern("hello");
85 let id2 = interner.intern("hello");
86
87 assert_eq!(id1, id2);
88 assert_eq!(interner.len(), 1);
89 }
90
91 #[test]
92 fn test_intern_empty_string() {
93 let mut interner = StringInterner::new();
94 let id = interner.intern("");
95 assert_eq!(interner.get(id), "");
96 }
97}