// 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::{vec, map}; import std::map::{hashmap, hashfn, eqfn}; import std::option::{none, some}; type interner = {map: hashmap, mutable vect: [T], hasher: hashfn, eqer: eqfn}; fn mk(hasher: hashfn, eqer: eqfn) -> interner { let m = map::mk_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); }