// 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}; import dvec::{dvec, extensions}; type interner = {map: hashmap, vect: dvec, hasher: hashfn, eqer: eqfn}; fn mk(hasher: hashfn, eqer: eqfn) -> interner { let m = map::hashmap::(hasher, eqer); ret {map: m, vect: dvec(), hasher: hasher, eqer: eqer}; } fn intern(itr: interner, val: T) -> uint { alt itr.map.find(val) { some(idx) { ret idx; } none { let new_idx = itr.vect.len(); itr.map.insert(val, new_idx); itr.vect.push(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.get_elt(idx) } } fn len(itr: interner) -> uint { ret itr.vect.len(); }