Skip to content

Commit

Permalink
Factor the RefCell out of the Interner.
Browse files Browse the repository at this point in the history
  • Loading branch information
jseyfried committed Jul 11, 2016
1 parent 752d441 commit 060b5c5
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 66 deletions.
13 changes: 7 additions & 6 deletions src/libsyntax/parse/token.rs
Expand Up @@ -21,6 +21,7 @@ use util::interner::Interner;
use tokenstream;

use serialize::{Decodable, Decoder, Encodable, Encoder};
use std::cell::RefCell;
use std::fmt;
use std::ops::Deref;
use std::rc::Rc;
Expand Down Expand Up @@ -477,20 +478,20 @@ pub type IdentInterner = Interner;
// if an interner exists in TLS, return it. Otherwise, prepare a
// fresh one.
// FIXME(eddyb) #8726 This should probably use a thread-local reference.
pub fn with_ident_interner<T, F: FnOnce(&IdentInterner) -> T>(f: F) -> T {
thread_local!(static KEY: IdentInterner = {
mk_fresh_ident_interner()
pub fn with_ident_interner<T, F: FnOnce(&mut IdentInterner) -> T>(f: F) -> T {
thread_local!(static KEY: RefCell<IdentInterner> = {
RefCell::new(mk_fresh_ident_interner())
});
KEY.with(f)
KEY.with(|interner| f(&mut *interner.borrow_mut()))
}

/// Reset the ident interner to its initial state.
pub fn reset_ident_interner() {
with_ident_interner(|interner| interner.reset(mk_fresh_ident_interner()));
with_ident_interner(|interner| *interner = mk_fresh_ident_interner());
}

pub fn clear_ident_interner() {
with_ident_interner(|interner| interner.clear());
with_ident_interner(|interner| *interner = IdentInterner::new());
}

/// Represents a string stored in the thread-local interner. Because the
Expand Down
94 changes: 34 additions & 60 deletions src/libsyntax/util/interner.rs
Expand Up @@ -15,7 +15,6 @@
use ast::Name;

use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

Expand All @@ -28,85 +27,60 @@ impl Borrow<str> for RcStr {
}
}

#[derive(Default)]
pub struct Interner {
map: RefCell<HashMap<RcStr, Name>>,
vect: RefCell<Vec<Rc<String>> >,
names: HashMap<RcStr, Name>,
strings: Vec<Rc<String>>,
}

/// When traits can extend traits, we should extend index<Name,T> to get []
impl Interner {
pub fn new() -> Self {
Interner {
map: RefCell::new(HashMap::new()),
vect: RefCell::new(Vec::new()),
}
Interner::default()
}

pub fn prefill(init: &[&str]) -> Self {
let rv = Interner::new();
for &v in init { rv.intern(v); }
rv
}

pub fn intern<T: Borrow<str> + Into<String>>(&self, val: T) -> Name {
let mut map = self.map.borrow_mut();
if let Some(&idx) = map.get(val.borrow()) {
return idx;
let mut this = Interner::new();
for &string in init {
this.intern(string);
}

let new_idx = Name(self.len() as u32);
let val = Rc::new(val.into());
map.insert(RcStr(val.clone()), new_idx);
self.vect.borrow_mut().push(val);
new_idx
this
}

pub fn gensym(&self, val: &str) -> Name {
let new_idx = Name(self.len() as u32);
// leave out of .map to avoid colliding
self.vect.borrow_mut().push(Rc::new(val.to_owned()));
new_idx
}

// I want these gensyms to share name pointers
// with existing entries. This would be automatic,
// except that the existing gensym creates its
// own managed ptr using to_managed. I think that
// adding this utility function is the most
// lightweight way to get what I want, though not
// necessarily the cleanest.

/// Create a gensym with the same name as an existing
/// entry.
pub fn gensym_copy(&self, idx : Name) -> Name {
let new_idx = Name(self.len() as u32);
// leave out of map to avoid colliding
let mut vect = self.vect.borrow_mut();
let existing = (*vect)[idx.0 as usize].clone();
vect.push(existing);
new_idx
}
pub fn intern<T: Borrow<str> + Into<String>>(&mut self, string: T) -> Name {
if let Some(&name) = self.names.get(string.borrow()) {
return name;
}

pub fn get(&self, idx: Name) -> Rc<String> {
(*self.vect.borrow())[idx.0 as usize].clone()
let name = Name(self.strings.len() as u32);
let string = Rc::new(string.into());
self.strings.push(string.clone());
self.names.insert(RcStr(string), name);
name
}

pub fn len(&self) -> usize {
self.vect.borrow().len()
pub fn gensym(&mut self, string: &str) -> Name {
let gensym = Name(self.strings.len() as u32);
// leave out of `names` to avoid colliding
self.strings.push(Rc::new(string.to_owned()));
gensym
}

pub fn find(&self, val: &str) -> Option<Name> {
self.map.borrow().get(val).cloned()
/// Create a gensym with the same name as an existing entry.
pub fn gensym_copy(&mut self, name: Name) -> Name {
let gensym = Name(self.strings.len() as u32);
// leave out of `names` to avoid colliding
let string = self.strings[name.0 as usize].clone();
self.strings.push(string);
gensym
}

pub fn clear(&self) {
*self.map.borrow_mut() = HashMap::new();
*self.vect.borrow_mut() = Vec::new();
pub fn get(&self, name: Name) -> Rc<String> {
self.strings[name.0 as usize].clone()
}

pub fn reset(&self, other: Interner) {
*self.map.borrow_mut() = other.map.into_inner();
*self.vect.borrow_mut() = other.vect.into_inner();
pub fn find(&self, string: &str) -> Option<Name> {
self.names.get(string).cloned()
}
}

Expand All @@ -117,7 +91,7 @@ mod tests {

#[test]
fn interner_tests() {
let i : Interner = Interner::new();
let mut i: Interner = Interner::new();
// first one is zero:
assert_eq!(i.intern("dog"), Name(0));
// re-use gets the same entry:
Expand Down

0 comments on commit 060b5c5

Please sign in to comment.