// An "interner" is a data structure that associates values with uint tags and // allows bidirectional lookup; i.e. given a value, one can easily find the // type, and vice versa. import std::map; import std::map::{hashmap, hashfn, eqfn}; type interner = {map: hashmap, mutable vect: [T], hasher: hashfn, eqer: eqfn}; fn mk(hasher: hashfn, eqer: eqfn) -> interner { let m = map::new_hashmap::(hasher, eqer); ret {map: m, mutable vect: [], hasher: hasher, eqer: eqer}; } fn intern(itr: interner, val: T) -> uint { alt itr.map.find(val) { some(idx) { ret idx; } none { let new_idx = vec::len::(itr.vect); itr.map.insert(val, new_idx); itr.vect += [val]; ret new_idx; } } } // |get| isn't "pure" in the traditional sense, because it can go from // failing to returning a value as items are interned. But for typestate, // where we first check a pred and then rely on it, ceasing to fail is ok. pure fn get(itr: interner, idx: uint) -> T { unchecked { itr.vect[idx] } } fn len(itr: interner) -> uint { ret vec::len(itr.vect); }