/src/wasmi/crates/collections/src/string_interner.rs
Line | Count | Source |
1 | | //! Data structure to efficiently store and deduplicate strings. |
2 | | |
3 | | #[cfg(all( |
4 | | feature = "hash-collections", |
5 | | not(feature = "prefer-btree-collections") |
6 | | ))] |
7 | | mod detail { |
8 | | use super::{GetOrInternWithHint, Sym}; |
9 | | use crate::hash; |
10 | | use string_interner::{StringInterner, Symbol, backend::BufferBackend}; |
11 | | |
12 | | pub type StringInternerImpl = StringInterner<BufferBackend<Sym>, hash::RandomState>; |
13 | | |
14 | | impl GetOrInternWithHint for StringInternerImpl { |
15 | | #[inline] |
16 | | fn get_or_intern_with_hint<T>(&mut self, string: T, _hint: super::InternHint) -> Sym |
17 | | where |
18 | | T: AsRef<str>, |
19 | | { |
20 | | self.get_or_intern(string) |
21 | | } |
22 | | } |
23 | | |
24 | | impl Symbol for Sym { |
25 | | #[inline] |
26 | | fn try_from_usize(index: usize) -> Option<Self> { |
27 | | let Ok(value) = u32::try_from(index) else { |
28 | | return None; |
29 | | }; |
30 | | Some(Self::from_u32(value)) |
31 | | } |
32 | | |
33 | | #[inline] |
34 | | fn to_usize(self) -> usize { |
35 | | self.into_u32() as usize |
36 | | } |
37 | | } |
38 | | } |
39 | | |
40 | | #[cfg(any( |
41 | | not(feature = "hash-collections"), |
42 | | feature = "prefer-btree-collections" |
43 | | ))] |
44 | | mod detail; |
45 | | |
46 | | /// Internment hint to speed-up certain use cases. |
47 | | #[derive(Debug, Copy, Clone)] |
48 | | pub enum InternHint { |
49 | | /// No hint is given to the [`StringInterner`]. |
50 | | None, |
51 | | /// Hint that the string to be interned likely already exists. |
52 | | LikelyExists, |
53 | | /// Hint that the string to be interned likely does not yet exist. |
54 | | LikelyNew, |
55 | | } |
56 | | |
57 | | /// Symbols returned by the [`StringInterner`] to resolve interned strings. |
58 | | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
59 | | pub struct Sym(u32); |
60 | | |
61 | | impl Sym { |
62 | | /// Creates a new [`Sym`] from the `u32` value. |
63 | 0 | pub fn from_u32(value: u32) -> Self { |
64 | 0 | Self(value) |
65 | 0 | } |
66 | | |
67 | | /// Creates a new [`Sym`] from the `usize` value. |
68 | | /// |
69 | | /// # Panics |
70 | | /// |
71 | | /// If the `usize` value is out of bounds for [`Sym`]. |
72 | 0 | pub fn from_usize(value: usize) -> Self { |
73 | 0 | u32::try_from(value).map_or_else(|_| panic!("out of bounds symbol index: {value}"), Self) |
74 | 0 | } |
75 | | |
76 | | /// Returns the `u32` value of the [`Sym`]. |
77 | 0 | pub fn into_u32(self) -> u32 { |
78 | 0 | self.0 |
79 | 0 | } |
80 | | |
81 | | /// Returns the value of the [`Sym`] as `usize`. |
82 | 0 | pub fn into_usize(self) -> usize { |
83 | 0 | self.0 as usize |
84 | 0 | } |
85 | | } |
86 | | |
87 | | /// Efficiently interns and deduplicates strings. |
88 | | #[derive(Debug, Clone, PartialEq, Eq)] |
89 | | pub struct StringInterner { |
90 | | inner: detail::StringInternerImpl, |
91 | | } |
92 | | |
93 | | impl Default for StringInterner { |
94 | | #[inline] |
95 | 31.6k | fn default() -> Self { |
96 | 31.6k | Self::new() |
97 | 31.6k | } |
98 | | } |
99 | | |
100 | | impl StringInterner { |
101 | | /// Creates a new empty [`StringInterner`]. |
102 | | #[inline] |
103 | 31.6k | pub fn new() -> Self { |
104 | 31.6k | Self { |
105 | 31.6k | inner: detail::StringInternerImpl::new(), |
106 | 31.6k | } |
107 | 31.6k | } |
108 | | |
109 | | /// Returns the number of strings interned by the [`StringInterner`]. |
110 | | #[inline] |
111 | 0 | pub fn len(&self) -> usize { |
112 | 0 | self.inner.len() |
113 | 0 | } |
114 | | |
115 | | /// Returns `true` if the [`StringInterner`] has no interned strings. |
116 | | #[inline] |
117 | 0 | pub fn is_empty(&self) -> bool { |
118 | 0 | self.inner.is_empty() |
119 | 0 | } |
120 | | |
121 | | /// Returns the symbol for the given string if any. |
122 | | /// |
123 | | /// Can be used to query if a string has already been interned without interning. |
124 | | #[inline] |
125 | 5.56k | pub fn get<T>(&self, string: T) -> Option<Sym> |
126 | 5.56k | where |
127 | 5.56k | T: AsRef<str>, |
128 | | { |
129 | 5.56k | self.inner.get(string) |
130 | 5.56k | } <wasmi_collections::string_interner::StringInterner>::get::<&str> Line | Count | Source | 125 | 1.28k | pub fn get<T>(&self, string: T) -> Option<Sym> | 126 | 1.28k | where | 127 | 1.28k | T: AsRef<str>, | 128 | | { | 129 | 1.28k | self.inner.get(string) | 130 | 1.28k | } |
Unexecuted instantiation: <wasmi_collections::string_interner::StringInterner>::get::<_> <wasmi_collections::string_interner::StringInterner>::get::<&str> Line | Count | Source | 125 | 4.28k | pub fn get<T>(&self, string: T) -> Option<Sym> | 126 | 4.28k | where | 127 | 4.28k | T: AsRef<str>, | 128 | | { | 129 | 4.28k | self.inner.get(string) | 130 | 4.28k | } |
|
131 | | |
132 | | /// Interns the given string. |
133 | | /// |
134 | | /// Returns a symbol for resolution into the original string. |
135 | | /// |
136 | | /// # Panics |
137 | | /// |
138 | | /// If the interner already interns the maximum number of strings possible |
139 | | /// by the chosen symbol type. |
140 | | #[inline] |
141 | 0 | pub fn get_or_intern<T>(&mut self, string: T) -> Sym |
142 | 0 | where |
143 | 0 | T: AsRef<str>, |
144 | | { |
145 | 0 | self.inner.get_or_intern_with_hint(string, InternHint::None) |
146 | 0 | } |
147 | | |
148 | | /// Interns the given string with usage hint. |
149 | | /// |
150 | | /// Returns a symbol for resolution into the original string. |
151 | | /// |
152 | | /// # Panics |
153 | | /// |
154 | | /// If the interner already interns the maximum number of strings possible |
155 | | /// by the chosen symbol type. |
156 | | #[inline] |
157 | 0 | pub fn get_or_intern_with_hint<T>(&mut self, string: T, hint: InternHint) -> Sym |
158 | 0 | where |
159 | 0 | T: AsRef<str>, |
160 | | { |
161 | 0 | self.inner.get_or_intern_with_hint(string, hint) |
162 | 0 | } |
163 | | |
164 | | /// Returns the string for the given symbol if any. |
165 | | #[inline] |
166 | 0 | pub fn resolve(&self, symbol: Sym) -> Option<&str> { |
167 | 0 | self.inner.resolve(symbol) |
168 | 0 | } |
169 | | } |
170 | | |
171 | | /// Extension trait for [`StringInterner`] backends. |
172 | | trait GetOrInternWithHint { |
173 | | /// Interns the given string with usage hint. |
174 | | /// |
175 | | /// Returns a symbol for resolution into the original string. |
176 | | /// |
177 | | /// # Panics |
178 | | /// |
179 | | /// If the interner already interns the maximum number of strings possible |
180 | | /// by the chosen symbol type. |
181 | | fn get_or_intern_with_hint<T>(&mut self, string: T, hint: InternHint) -> Sym |
182 | | where |
183 | | T: AsRef<str>; |
184 | | } |