From 8b8419293cb69d208a0d4f3a89dd01b0d394a6c6 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 31 Jan 2014 16:42:33 -0800 Subject: [PATCH] libsyntax: Remove `@str` from the interner --- src/libsyntax/ast_map.rs | 26 +++++--- src/libsyntax/parse/parser.rs | 3 +- src/libsyntax/parse/token.rs | 22 ++++--- src/libsyntax/util/interner.rs | 117 ++++++++++++++++++++++----------- 4 files changed, 112 insertions(+), 56 deletions(-) diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index bb66d620d2910..89209ab2104f0 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -62,9 +62,10 @@ pub fn path_to_str_with_sep(p: &[PathElem], sep: &str, itr: @IdentInterner) pub fn path_ident_to_str(p: &Path, i: Ident, itr: @IdentInterner) -> ~str { if p.is_empty() { - itr.get(i.name).to_owned() + itr.get(i.name).into_owned() } else { - format!("{}::{}", path_to_str(*p, itr), itr.get(i.name)) + let string = itr.get(i.name); + format!("{}::{}", path_to_str(*p, itr), string.as_slice()) } } @@ -75,7 +76,7 @@ pub fn path_to_str(p: &[PathElem], itr: @IdentInterner) -> ~str { pub fn path_elem_to_str(pe: PathElem, itr: @IdentInterner) -> ~str { match pe { PathMod(s) | PathName(s) | PathPrettyName(s, _) => { - itr.get(s.name).to_owned() + itr.get(s.name).into_owned() } } } @@ -105,7 +106,11 @@ fn pretty_ty(ty: &Ty, itr: @IdentInterner, out: &mut ~str) { // need custom handling. TyNil => { out.push_str("$NIL$"); return } TyPath(ref path, _, _) => { - out.push_str(itr.get(path.segments.last().unwrap().identifier.name)); + out.push_str(itr.get(path.segments + .last() + .unwrap() + .identifier + .name).as_slice()); return } TyTup(ref tys) => { @@ -138,7 +143,8 @@ pub fn impl_pretty_name(trait_ref: &Option, ty: &Ty) -> PathElem { match *trait_ref { None => pretty = ~"", Some(ref trait_ref) => { - pretty = itr.get(trait_ref.path.segments.last().unwrap().identifier.name).to_owned(); + pretty = itr.get(trait_ref.path.segments.last().unwrap().identifier.name) + .into_owned(); pretty.push_char('$'); } }; @@ -489,17 +495,21 @@ pub fn node_id_to_str(map: Map, id: NodeId, itr: @IdentInterner) -> ~str { path_ident_to_str(path, item.ident, itr), abi, id) } Some(NodeMethod(m, _, path)) => { + let name = itr.get(m.ident.name); format!("method {} in {} (id={})", - itr.get(m.ident.name), path_to_str(*path, itr), id) + name.as_slice(), path_to_str(*path, itr), id) } Some(NodeTraitMethod(ref tm, _, path)) => { let m = ast_util::trait_method_to_ty_method(&**tm); + let name = itr.get(m.ident.name); format!("method {} in {} (id={})", - itr.get(m.ident.name), path_to_str(*path, itr), id) + name.as_slice(), path_to_str(*path, itr), id) } Some(NodeVariant(ref variant, _, path)) => { + let name = itr.get(variant.node.name.name); format!("variant {} in {} (id={})", - itr.get(variant.node.name.name), path_to_str(*path, itr), id) + name.as_slice(), + path_to_str(*path, itr), id) } Some(NodeExpr(expr)) => { format!("expr {} (id={})", pprust::expr_to_str(expr, itr), id) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8691371180114..dc16f32b87251 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3979,8 +3979,9 @@ impl Parser { fields.push(self.parse_struct_decl_field()); } if fields.len() == 0 { + let string = get_ident_interner().get(class_name.name); self.fatal(format!("Unit-like struct definition should be written as `struct {};`", - get_ident_interner().get(class_name.name))); + string.as_slice())); } self.bump(); } else if self.token == token::LPAREN { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 806c84c555301..eb2fa151f51eb 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -12,7 +12,7 @@ use ast; use ast::{P, Name, Mrk}; use ast_util; use parse::token; -use util::interner::StrInterner; +use util::interner::{RcStr, StrInterner}; use util::interner; use extra::serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -214,8 +214,11 @@ pub fn to_str(input: @IdentInterner, t: &Token) -> ~str { } /* Name components */ - IDENT(s, _) => input.get(s.name).to_owned(), - LIFETIME(s) => format!("'{}", input.get(s.name)), + IDENT(s, _) => input.get(s.name).into_owned(), + LIFETIME(s) => { + let name = input.get(s.name); + format!("'{}", name.as_slice()) + } UNDERSCORE => ~"_", /* Other */ @@ -549,7 +552,7 @@ pub fn get_ident_interner() -> @IdentInterner { #[no_send] #[deriving(Clone, Eq, IterBytes, Ord, TotalEq, TotalOrd)] pub struct InternedString { - priv string: @str, + priv string: RcStr, } #[unsafe_destructor] @@ -563,13 +566,12 @@ impl InternedString { #[inline] pub fn new(string: &'static str) -> InternedString { InternedString { - string: string.to_managed(), + string: RcStr::new(string), } } - // NB: Do not make this public. We are trying to remove `@str`. #[inline] - fn new_from_at_str(string: @str) -> InternedString { + fn new_from_rc_str(string: RcStr) -> InternedString { InternedString { string: string, } @@ -594,7 +596,7 @@ impl BytesContainer for InternedString { impl fmt::Default for InternedString { fn fmt(obj: &InternedString, f: &mut fmt::Formatter) { - write!(f.buf, "{}", obj.string); + write!(f.buf, "{}", obj.string.as_slice()); } } @@ -613,7 +615,7 @@ impl Decodable for InternedString { impl Encodable for InternedString { fn encode(&self, e: &mut E) { - e.emit_str(self.string) + e.emit_str(self.string.as_slice()) } } @@ -622,7 +624,7 @@ impl Encodable for InternedString { #[inline] pub fn get_ident(idx: Name) -> InternedString { let interner = get_ident_interner(); - InternedString::new_from_at_str(interner.get(idx)) + InternedString::new_from_rc_str(interner.get(idx)) } /// Interns and returns the string contents of an identifier, using the diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index c0fe19ede0130..e20efda9c6ecc 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -18,6 +18,7 @@ use std::cast; use std::cell::RefCell; use std::cmp::Equiv; use std::hashmap::HashMap; +use std::rc::Rc; pub struct Interner { priv map: @RefCell>, @@ -83,11 +84,49 @@ impl Interner { } } +#[deriving(Clone, Eq, IterBytes, Ord)] +pub struct RcStr { + priv string: Rc<~str>, +} + +impl TotalEq for RcStr { + fn equals(&self, other: &RcStr) -> bool { + self.as_slice().equals(&other.as_slice()) + } +} + +impl TotalOrd for RcStr { + fn cmp(&self, other: &RcStr) -> Ordering { + self.as_slice().cmp(&other.as_slice()) + } +} + +impl Str for RcStr { + #[inline] + fn as_slice<'a>(&'a self) -> &'a str { + let s: &'a str = *self.string.borrow(); + s + } + + #[inline] + fn into_owned(self) -> ~str { + self.string.borrow().to_owned() + } +} + +impl RcStr { + pub fn new(string: &str) -> RcStr { + RcStr { + string: Rc::new(string.to_owned()), + } + } +} + // A StrInterner differs from Interner in that it accepts // references rather than @ ones, resulting in less allocation. pub struct StrInterner { - priv map: @RefCell>, - priv vect: @RefCell<~[@str]>, + priv map: @RefCell>, + priv vect: @RefCell<~[RcStr]>, } // when traits can extend traits, we should extend index to get [] @@ -113,8 +152,8 @@ impl StrInterner { } let new_idx = self.len() as Name; - let val = val.to_managed(); - map.get().insert(val, new_idx); + let val = RcStr::new(val); + map.get().insert(val.clone(), new_idx); let mut vect = self.vect.borrow_mut(); vect.get().push(val); new_idx @@ -124,7 +163,7 @@ impl StrInterner { let new_idx = self.len() as Name; // leave out of .map to avoid colliding let mut vect = self.vect.borrow_mut(); - vect.get().push(val.to_managed()); + vect.get().push(RcStr::new(val)); new_idx } @@ -142,21 +181,21 @@ impl StrInterner { let new_idx = self.len() as Name; // leave out of map to avoid colliding let mut vect = self.vect.borrow_mut(); - let existing = vect.get()[idx]; + let existing = vect.get()[idx].clone(); vect.get().push(existing); new_idx } - pub fn get(&self, idx: Name) -> @str { + pub fn get(&self, idx: Name) -> RcStr { let vect = self.vect.borrow(); - vect.get()[idx] + vect.get()[idx].clone() } /// Returns this string with lifetime tied to the interner. Since /// strings may never be removed from the interner, this is safe. pub fn get_ref<'a>(&'a self, idx: Name) -> &'a str { let vect = self.vect.borrow(); - let s: &str = vect.get()[idx]; + let s: &str = vect.get()[idx].as_slice(); unsafe { cast::transmute(s) } @@ -167,7 +206,7 @@ impl StrInterner { vect.get().len() } - pub fn find_equiv>(&self, val: &Q) + pub fn find_equiv>(&self, val: &Q) -> Option { let map = self.map.borrow(); match map.get().find_equiv(val) { @@ -183,42 +222,46 @@ mod tests { #[test] #[should_fail] fn i1 () { - let i : Interner<@str> = Interner::new(); + let i : Interner = Interner::new(); i.get(13); } #[test] fn interner_tests () { - let i : Interner<@str> = Interner::new(); + let i : Interner = Interner::new(); // first one is zero: - assert_eq!(i.intern(@"dog"), 0); + assert_eq!(i.intern(RcStr::new("dog")), 0); // re-use gets the same entry: - assert_eq!(i.intern(@"dog"), 0); + assert_eq!(i.intern(RcStr::new("dog")), 0); // different string gets a different #: - assert_eq!(i.intern(@"cat"), 1); - assert_eq!(i.intern(@"cat"), 1); + assert_eq!(i.intern(RcStr::new("cat")), 1); + assert_eq!(i.intern(RcStr::new("cat")), 1); // dog is still at zero - assert_eq!(i.intern(@"dog"), 0); + assert_eq!(i.intern(RcStr::new("dog")), 0); // gensym gets 3 - assert_eq!(i.gensym(@"zebra" ), 2); + assert_eq!(i.gensym(RcStr::new("zebra") ), 2); // gensym of same string gets new number : - assert_eq!(i.gensym (@"zebra" ), 3); + assert_eq!(i.gensym (RcStr::new("zebra") ), 3); // gensym of *existing* string gets new number: - assert_eq!(i.gensym(@"dog"), 4); - assert_eq!(i.get(0), @"dog"); - assert_eq!(i.get(1), @"cat"); - assert_eq!(i.get(2), @"zebra"); - assert_eq!(i.get(3), @"zebra"); - assert_eq!(i.get(4), @"dog"); + assert_eq!(i.gensym(RcStr::new("dog")), 4); + assert_eq!(i.get(0), RcStr::new("dog")); + assert_eq!(i.get(1), RcStr::new("cat")); + assert_eq!(i.get(2), RcStr::new("zebra")); + assert_eq!(i.get(3), RcStr::new("zebra")); + assert_eq!(i.get(4), RcStr::new("dog")); } #[test] fn i3 () { - let i : Interner<@str> = Interner::prefill([@"Alan",@"Bob",@"Carol"]); - assert_eq!(i.get(0), @"Alan"); - assert_eq!(i.get(1), @"Bob"); - assert_eq!(i.get(2), @"Carol"); - assert_eq!(i.intern(@"Bob"), 1); + let i : Interner<@~str> = Interner::prefill([ + RcStr::new("Alan"), + RcStr::new("Bob"), + RcStr::new("Carol") + ]); + assert_eq!(i.get(0), RcStr::new("Alan")); + assert_eq!(i.get(1), RcStr::new("Bob")); + assert_eq!(i.get(2), RcStr::new("Carol")); + assert_eq!(i.intern(RcStr::new("Bob")), 1); } #[test] @@ -241,13 +284,13 @@ mod tests { assert_eq!(i.gensym("dog"), 4); // gensym tests again with gensym_copy: assert_eq!(i.gensym_copy(2), 5); - assert_eq!(i.get(5), @"zebra"); + assert_eq!(i.get(5), RcStr::new("zebra")); assert_eq!(i.gensym_copy(2), 6); - assert_eq!(i.get(6), @"zebra"); - assert_eq!(i.get(0), @"dog"); - assert_eq!(i.get(1), @"cat"); - assert_eq!(i.get(2), @"zebra"); - assert_eq!(i.get(3), @"zebra"); - assert_eq!(i.get(4), @"dog"); + assert_eq!(i.get(6), RcStr::new("zebra")); + assert_eq!(i.get(0), RcStr::new("dog")); + assert_eq!(i.get(1), RcStr::new("cat")); + assert_eq!(i.get(2), RcStr::new("zebra")); + assert_eq!(i.get(3), RcStr::new("zebra")); + assert_eq!(i.get(4), RcStr::new("dog")); } }