Created
August 11, 2013 20:39
-
-
Save orenbenkiki/6206763 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
src/anthill/intern.rs:71:24: 73:25 error: instantiating a type parameter with an incompatible type `intern::intern::Interner`, which does not fulfill `Send+Freeze` | |
src/anthill/intern.rs:71 do arc_interner.read |interner| { | |
src/anthill/intern.rs:72 interner.id_to_str[self.id].clone() | |
src/anthill/intern.rs:73 } | |
src/anthill/intern.rs:88:20: 108:21 error: instantiating a type parameter with an incompatible type `intern::intern::Interner`, which does not fulfill `Send+Freeze` | |
src/anthill/intern.rs:88 do arc_interner.read |interner| { | |
src/anthill/intern.rs:89 match interner.str_to_intern.find(&burrowed.to_str()) { | |
src/anthill/intern.rs:90 Some(intern) => *intern, | |
src/anthill/intern.rs:91 None => { | |
src/anthill/intern.rs:92 // TRICKY: If we didn't find it above, we need | |
src/anthill/intern.rs:93 // to get a write lock and re-find it, to | |
... | |
src/anthill/intern.rs:99:32: 105:33 error: instantiating a type parameter with an incompatible type `intern::intern::Interner`, which does not fulfill `Send+Freeze` | |
src/anthill/intern.rs:99 do arc_interner.write |mut_interner: &mut Interner| { | |
src/anthill/intern.rs:100 let intern = do mut_interner.str_to_intern.find_or_insert_with(burrowed.to_str()) |owned| { | |
src/anthill/intern.rs:101 mut_interner.id_to_str.push(owned.clone()); | |
src/anthill/intern.rs:102 Intern { id: mut_interner.id_to_str.len() - 1 } | |
src/anthill/intern.rs:103 }; | |
src/anthill/intern.rs:104 *intern | |
... | |
src/anthill/intern.rs:118:36: 118:46 error: instantiating a type parameter with an incompatible type `intern::intern::Interner`, which does not fulfill `Send+Freeze` | |
src/anthill/intern.rs:118 set_task_local_arc_interner(RWArc::new(Interner::new())); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Interns are an efficient representation of a string (also known as | |
/// "interned strings", "atoms", "symbols", ...). They allow efficient | |
/// comparison for equality, use as keys, etc. | |
/// | |
/// The implementation in this module relies on the program to create a global | |
/// interner and pass it to all the tasks. This ensures interns created | |
/// anywhere in the program will be compatible (like the Erlang atom | |
/// mechanism). TODO: It would be nice to do this in a safer way without | |
/// requiring the program's cooperation. | |
mod intern { | |
use extra::arc::RWArc; | |
use std::hashmap::HashMap; | |
use std::local_data; | |
static KEY_ARC_INTERNER: local_data::Key<RWArc<Interner>> = &local_data::Key; | |
/// Set the task local ARC for the global interner. This assumes "someone" | |
/// creates a single global interner and hands it off to each task. Once | |
/// this is done, interns created anywhere will be compatible with each | |
/// other. If this isn't done, "bad things will happen". | |
pub fn set_task_local_arc_interner(arc_interner: RWArc<Interner>) { | |
local_data::set(KEY_ARC_INTERNER, arc_interner) | |
} | |
/// An interner holds all the known strings, ensuring re-interning the same | |
/// string will always return the same intern. | |
struct Interner { | |
str_to_intern: @mut HashMap<~str, Intern>, | |
id_to_str: @mut ~[~str], | |
} | |
impl Interner { | |
/// Create a new empty interner. TODO: This should really be a | |
/// singleton (though we do create instances in tests...). | |
pub fn new() -> Interner { | |
Interner { | |
str_to_intern: @mut HashMap::new(), | |
id_to_str: @mut ~[] | |
} | |
} | |
} | |
/// An intern is an efficient representation of a string, allowing | |
/// efficient comparison for equality, use as keys, etc. | |
struct Intern { | |
id: uint, | |
} | |
impl TotalEq for Intern { | |
fn equals(&self, other: &Intern) -> bool { | |
self.id == other.id | |
} | |
} | |
impl Eq for Intern { | |
fn eq(&self, other: &Intern) -> bool { | |
self.id == other.id | |
} | |
fn ne(&self, other: &Intern) -> bool { | |
self.id != other.id | |
} | |
} | |
impl ToStr for Intern { | |
fn to_str(&self) -> ~str { | |
do local_data::get(KEY_ARC_INTERNER) |maybe_arc_interner| { | |
match maybe_arc_interner { | |
None => fail!("no interner set for task"), | |
Some(arc_interner) => { | |
do arc_interner.read |interner| { | |
interner.id_to_str[self.id].clone() | |
} | |
} | |
} | |
} | |
} | |
} | |
/// Intern a string using the task local interner. | |
pub fn intern(burrowed: &str) -> Intern { | |
do local_data::get(KEY_ARC_INTERNER) |maybe_arc_interner| { | |
match maybe_arc_interner { | |
None => fail!("no task local ARC for global interner"), | |
Some(arc_interner) => { | |
// TRICKY: Only obtain a read lock for the common case | |
// where the string was previously interned. | |
do arc_interner.read |interner| { | |
match interner.str_to_intern.find(&burrowed.to_str()) { | |
Some(intern) => *intern, | |
None => { | |
// TRICKY: If we didn't find it above, we need | |
// to get a write lock and re-find it, to | |
// ensure no other task sneaked in and added it | |
// between the above find and obtaining the | |
// write lock below. This sort of race | |
// condition is why one shouldn't write code | |
// using locks unless it is *really* necessary. | |
do arc_interner.write |mut_interner: &mut Interner| { | |
let intern = do mut_interner.str_to_intern.find_or_insert_with(burrowed.to_str()) |owned| { | |
mut_interner.id_to_str.push(owned.clone()); | |
Intern { id: mut_interner.id_to_str.len() - 1 } | |
}; | |
*intern | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
#[test] | |
fn intern_strings() { | |
// TODO: This leaves the interner in the task local data after the test | |
// is run. Provide a "do with_test_interner { ... }" function? | |
set_task_local_arc_interner(RWArc::new(Interner::new())); | |
let foo = intern("foo"); | |
let bar = intern("bar"); | |
let baz = intern("foo"); | |
assert!(foo != bar); | |
assert!(foo == baz); | |
assert!(foo.to_str() == ~"foo"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment