prune_lang/utils/
intern.rs1use once_cell::sync::Lazy;
2use std::collections::HashMap;
3use std::fmt;
4use std::sync;
5
6static INDEXD_BUF_SIZE: usize = 256;
7
8static INTERNER: Lazy<sync::Mutex<Interner>> = Lazy::new(|| {
9 let mut interner = Interner {
10 str_to_idx: HashMap::new(),
11 idx_to_str: Vec::new(),
12 };
13 for i in 0..INDEXD_BUF_SIZE {
14 let s = format!("x_{}", i);
15 let s = s.leak();
16 interner.str_to_idx.insert(s.to_string(), i);
17 interner.idx_to_str.push(s);
18 }
19 sync::Mutex::new(interner)
20});
21
22struct Interner {
23 str_to_idx: HashMap<String, usize>,
24 idx_to_str: Vec<&'static str>,
25}
26
27#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord)]
28pub struct InternStr(usize);
29impl InternStr {
30 pub fn new<S: AsRef<str>>(s: S) -> InternStr {
31 let mut interner = INTERNER.lock().unwrap();
32 if let Some(idx) = interner.str_to_idx.get(s.as_ref()) {
33 InternStr(*idx)
34 } else {
35 let s = s.as_ref().to_string();
36 let idx = interner.idx_to_str.len();
37 interner.str_to_idx.insert(s.clone(), idx);
38 interner.idx_to_str.push(Box::leak(Box::new(s)));
39 InternStr(idx)
40 }
41 }
42
43 pub fn indexd(idx: usize) -> InternStr {
44 if idx < INDEXD_BUF_SIZE {
45 InternStr(idx)
46 } else {
47 InternStr::new(format!("x_{}", idx).as_str())
48 }
49 }
50
51 pub fn as_str(&self) -> &'static str {
52 let interner = INTERNER.lock().unwrap();
53 interner.idx_to_str[self.0]
54 }
55}
56
57impl fmt::Debug for InternStr {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 write!(f, "{}", self.as_str())
60 }
61}
62
63impl fmt::Display for InternStr {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 write!(f, "{}", self.as_str())
66 }
67}
68
69impl AsRef<str> for InternStr {
70 fn as_ref(&self) -> &str {
71 self.as_str()
72 }
73}
74
75#[test]
76fn intern_new_test() {
77 let foo1: &str = "foo";
79 let foo2: String = "foo".to_string();
80 let bar1: &str = "bar";
81 let bar2: String = "bar".to_string();
82 let s1 = InternStr::new(&foo1);
83 let s2 = InternStr::new(&foo2);
84 let s3 = InternStr::new(&bar1);
85 let s4 = InternStr::new(&bar2);
86 assert_eq!(s1, s2);
87 assert_eq!(s3, s4);
88 assert_ne!(s1, s3);
89 assert_ne!(s2, s4);
90 assert_eq!(format!("{}", s1), "foo");
91 assert_eq!(format!("{}", s2), "foo");
92 assert_eq!(format!("{}", s3), "bar");
93 assert_eq!(format!("{}", s4), "bar");
94}
95
96#[test]
97fn intern_indexd_test() {
98 let s1 = InternStr::indexd(42);
99 let s2 = InternStr::indexd(42);
100 let s3 = InternStr::indexd(500);
101 let s4 = InternStr::indexd(500);
102 assert_eq!(s1, s2);
103 assert_eq!(s3, s4);
104 assert_ne!(s1, s3);
105 assert_ne!(s2, s4);
106 assert_eq!(format!("{}", s1), "x_42");
107 assert_eq!(format!("{}", s2), "x_42");
108 assert_eq!(format!("{}", s3), "x_500");
109 assert_eq!(format!("{}", s4), "x_500");
110}