Encapsulate RcStr in syntax::util::interner.

This commit is contained in:
Jeffrey Seyfried 2016-07-11 07:55:54 +00:00
parent 6d5f85996e
commit f8a934e971
2 changed files with 25 additions and 62 deletions

View file

@ -17,8 +17,7 @@ pub use self::Token::*;
use ast::{self, BinOpKind}; use ast::{self, BinOpKind};
use ext::mtwt; use ext::mtwt;
use ptr::P; use ptr::P;
use util::interner::{RcStr, StrInterner}; use util::interner::StrInterner;
use util::interner;
use tokenstream; use tokenstream;
use serialize::{Decodable, Decoder, Encodable, Encoder}; use serialize::{Decodable, Decoder, Encodable, Encoder};
@ -397,7 +396,7 @@ macro_rules! declare_keywords {(
} }
fn mk_fresh_ident_interner() -> IdentInterner { fn mk_fresh_ident_interner() -> IdentInterner {
interner::StrInterner::prefill(&[$($string,)*]) StrInterner::prefill(&[$($string,)*])
} }
}} }}
@ -502,19 +501,19 @@ pub fn reset_ident_interner() {
/// somehow. /// somehow.
#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
pub struct InternedString { pub struct InternedString {
string: RcStr, string: Rc<String>,
} }
impl InternedString { impl InternedString {
#[inline] #[inline]
pub fn new(string: &'static str) -> InternedString { pub fn new(string: &'static str) -> InternedString {
InternedString { InternedString {
string: RcStr::new(string), string: Rc::new(string.to_owned()),
} }
} }
#[inline] #[inline]
fn new_from_rc_str(string: RcStr) -> InternedString { fn new_from_rc_str(string: Rc<String>) -> InternedString {
InternedString { InternedString {
string: string, string: string,
} }

View file

@ -16,11 +16,8 @@ use ast::Name;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
pub struct Interner<T> { pub struct Interner<T> {
@ -91,56 +88,26 @@ impl<T: Eq + Hash + Clone + 'static> Interner<T> {
} }
} }
#[derive(Clone, PartialEq, Hash, PartialOrd)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct RcStr { struct RcStr(Rc<String>);
string: Rc<String>,
}
impl RcStr { impl RcStr {
pub fn new(string: &str) -> RcStr { fn new(string: &str) -> Self {
RcStr { RcStr(Rc::new(string.to_owned()))
string: Rc::new(string.to_string()),
}
}
}
impl Eq for RcStr {}
impl Ord for RcStr {
fn cmp(&self, other: &RcStr) -> Ordering {
self[..].cmp(&other[..])
}
}
impl fmt::Debug for RcStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self[..].fmt(f)
}
}
impl fmt::Display for RcStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self[..].fmt(f)
} }
} }
impl Borrow<str> for RcStr { impl Borrow<str> for RcStr {
fn borrow(&self) -> &str { fn borrow(&self) -> &str {
&self.string[..] &self.0
} }
} }
impl Deref for RcStr {
type Target = str;
fn deref(&self) -> &str { &self.string[..] }
}
/// A StrInterner differs from Interner<String> in that it accepts /// A StrInterner differs from Interner<String> in that it accepts
/// &str rather than RcStr, resulting in less allocation. /// &str rather than RcStr, resulting in less allocation.
pub struct StrInterner { pub struct StrInterner {
map: RefCell<HashMap<RcStr, Name>>, map: RefCell<HashMap<RcStr, Name>>,
vect: RefCell<Vec<RcStr> >, vect: RefCell<Vec<Rc<String>> >,
} }
/// When traits can extend traits, we should extend index<Name,T> to get [] /// When traits can extend traits, we should extend index<Name,T> to get []
@ -165,8 +132,8 @@ impl StrInterner {
} }
let new_idx = Name(self.len() as u32); let new_idx = Name(self.len() as u32);
let val = RcStr::new(val); let val = Rc::new(val.to_owned());
map.insert(val.clone(), new_idx); map.insert(RcStr(val.clone()), new_idx);
self.vect.borrow_mut().push(val); self.vect.borrow_mut().push(val);
new_idx new_idx
} }
@ -174,7 +141,7 @@ impl StrInterner {
pub fn gensym(&self, val: &str) -> Name { pub fn gensym(&self, val: &str) -> Name {
let new_idx = Name(self.len() as u32); let new_idx = Name(self.len() as u32);
// leave out of .map to avoid colliding // leave out of .map to avoid colliding
self.vect.borrow_mut().push(RcStr::new(val)); self.vect.borrow_mut().push(Rc::new(val.to_owned()));
new_idx new_idx
} }
@ -197,7 +164,7 @@ impl StrInterner {
new_idx new_idx
} }
pub fn get(&self, idx: Name) -> RcStr { pub fn get(&self, idx: Name) -> Rc<String> {
(*self.vect.borrow())[idx.0 as usize].clone() (*self.vect.borrow())[idx.0 as usize].clone()
} }
@ -205,12 +172,8 @@ impl StrInterner {
self.vect.borrow().len() self.vect.borrow().len()
} }
pub fn find<Q: ?Sized>(&self, val: &Q) -> Option<Name> pub fn find(&self, val: &str) -> Option<Name> {
where RcStr: Borrow<Q>, Q: Eq + Hash { self.map.borrow().get(val).cloned()
match (*self.map.borrow()).get(val) {
Some(v) => Some(*v),
None => None,
}
} }
pub fn clear(&self) { pub fn clear(&self) {
@ -227,6 +190,7 @@ impl StrInterner {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use super::RcStr;
use ast::Name; use ast::Name;
#[test] #[test]
@ -294,13 +258,13 @@ mod tests {
assert_eq!(i.gensym("dog"), Name(4)); assert_eq!(i.gensym("dog"), Name(4));
// gensym tests again with gensym_copy: // gensym tests again with gensym_copy:
assert_eq!(i.gensym_copy(Name(2)), Name(5)); assert_eq!(i.gensym_copy(Name(2)), Name(5));
assert_eq!(i.get(Name(5)), RcStr::new("zebra")); assert_eq!(*i.get(Name(5)), "zebra");
assert_eq!(i.gensym_copy(Name(2)), Name(6)); assert_eq!(i.gensym_copy(Name(2)), Name(6));
assert_eq!(i.get(Name(6)), RcStr::new("zebra")); assert_eq!(*i.get(Name(6)), "zebra");
assert_eq!(i.get(Name(0)), RcStr::new("dog")); assert_eq!(*i.get(Name(0)), "dog");
assert_eq!(i.get(Name(1)), RcStr::new("cat")); assert_eq!(*i.get(Name(1)), "cat");
assert_eq!(i.get(Name(2)), RcStr::new("zebra")); assert_eq!(*i.get(Name(2)), "zebra");
assert_eq!(i.get(Name(3)), RcStr::new("zebra")); assert_eq!(*i.get(Name(3)), "zebra");
assert_eq!(i.get(Name(4)), RcStr::new("dog")); assert_eq!(*i.get(Name(4)), "dog");
} }
} }