Allocate Symbol strings from an arena · rust-lang/rust@ca32340 (original) (raw)
`@@ -16,8 +16,10 @@ use hygiene::SyntaxContext;
`
16
16
`use {Span, DUMMY_SP, GLOBALS};
`
17
17
``
18
18
`use rustc_data_structures::fx::FxHashMap;
`
``
19
`+
use arena::DroplessArena;
`
19
20
`use serialize::{Decodable, Decoder, Encodable, Encoder};
`
20
21
`use std::fmt;
`
``
22
`+
use std::str;
`
21
23
`use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
`
22
24
`use std::hash::{Hash, Hasher};
`
23
25
``
`@@ -198,22 +200,35 @@ impl<T: ::std::ops::Deref<Target=str>> PartialEq for Symbol {
`
198
200
`}
`
199
201
`}
`
200
202
``
201
``
`-
#[derive(Default)]
`
``
203
`+
// The &'static strs in this type actually point into the arena
`
202
204
`pub struct Interner {
`
203
``
`-
names: FxHashMap<Box, Symbol>,
`
204
``
`-
strings: Vec<Box>,
`
``
205
`+
arena: DroplessArena,
`
``
206
`+
names: FxHashMap<&'static str, Symbol>,
`
``
207
`+
strings: Vec<&'static str>,
`
205
208
`gensyms: Vec,
`
206
209
`}
`
207
210
``
208
211
`impl Interner {
`
209
212
`pub fn new() -> Self {
`
210
``
`-
Interner::default()
`
``
213
`+
Interner {
`
``
214
`+
arena: DroplessArena::new(),
`
``
215
`+
names: Default::default(),
`
``
216
`+
strings: Default::default(),
`
``
217
`+
gensyms: Default::default(),
`
``
218
`+
}
`
211
219
`}
`
212
220
``
213
221
`fn prefill(init: &[&str]) -> Self {
`
214
222
`let mut this = Interner::new();
`
215
223
`for &string in init {
`
216
``
`-
this.intern(string);
`
``
224
`+
if string == "" {
`
``
225
`+
// We can't allocate empty strings in the arena, so handle this here
`
``
226
`+
let name = Symbol(this.strings.len() as u32);
`
``
227
`+
this.names.insert("", name);
`
``
228
`+
this.strings.push("");
`
``
229
`+
} else {
`
``
230
`+
this.intern(string);
`
``
231
`+
}
`
217
232
`}
`
218
233
` this
`
219
234
`}
`
`@@ -224,8 +239,17 @@ impl Interner {
`
224
239
`}
`
225
240
``
226
241
`let name = Symbol(self.strings.len() as u32);
`
227
``
`-
let string = string.to_string().into_boxed_str();
`
228
``
`-
self.strings.push(string.clone());
`
``
242
+
``
243
`+
// from_utf8_unchecked is safe since we just allocated a &str which is known to be utf8
`
``
244
`+
let string: &str = unsafe {
`
``
245
`+
str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes()))
`
``
246
`+
};
`
``
247
`+
// It is safe to extend the arena allocation to 'static because we only access
`
``
248
`+
// these while the arena is still alive
`
``
249
`+
let string: &'static str = unsafe {
`
``
250
`+
&*(string as *const str)
`
``
251
`+
};
`
``
252
`+
self.strings.push(string);
`
229
253
`self.names.insert(string, name);
`
230
254
` name
`
231
255
`}
`
`@@ -254,7 +278,7 @@ impl Interner {
`
254
278
``
255
279
`pub fn get(&self, symbol: Symbol) -> &str {
`
256
280
`match self.strings.get(symbol.0 as usize) {
`
257
``
`-
Some(ref string) => string,
`
``
281
`+
Some(string) => string,
`
258
282
`None => self.get(self.gensyms[(!0 - symbol.0) as usize]),
`
259
283
`}
`
260
284
`}
`