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